source: trunk/src/kash/shinstance.c@ 3442

Last change on this file since 3442 was 3442, checked in by bird, 5 years ago

kash: Turns out the redirlist needs to be copied too.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 55.6 KB
Line 
1/* $Id: shinstance.c 3442 2020-09-10 12:06:29Z bird $ */
2/** @file
3 * The shell instance methods.
4 */
5
6/*
7 * Copyright (c) 2007-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <string.h>
33#include <stdlib.h>
34#include <assert.h>
35#ifdef _MSC_VER
36# include <process.h>
37#else
38# include <unistd.h>
39# include <pwd.h>
40#endif
41#include "shinstance.h"
42
43#include "alias.h"
44#include "error.h"
45#include "memalloc.h"
46#include "shell.h"
47#include "trap.h"
48
49#if K_OS == K_OS_WINDOWS
50# include <Windows.h>
51# ifdef SH_FORKED_MODE
52extern pid_t shfork_do(shinstance *psh); /* shforkA-win.asm */
53# endif
54#endif
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60#ifndef SH_FORKED_MODE
61/** Used by sh__exit/sh_thread_wrapper for passing zero via longjmp. */
62# define SH_EXIT_ZERO 0x0d15ea5e
63#endif
64
65
66/*********************************************************************************************************************************
67* Global Variables *
68*********************************************************************************************************************************/
69#ifndef SH_FORKED_MODE
70/** Mutex serializing exec/spawn to prevent unwanted file inherting. */
71static shmtx g_sh_exec_mtx;
72#endif
73/** The mutex protecting the the globals and some shell instance members (sigs). */
74static shmtx g_sh_mtx;
75/** The root shell instance. */
76static shinstance *g_sh_root;
77/** The first shell instance. */
78static shinstance *g_sh_head;
79/** The last shell instance. */
80static shinstance *g_sh_tail;
81/** The number of shells. */
82static int volatile g_num_shells;
83/** Per signal state for determining a common denominator.
84 * @remarks defaults and unmasked actions aren't counted. */
85struct shsigstate
86{
87 /** The current signal action. */
88#ifndef _MSC_VER
89 struct sigaction sa;
90#else
91 struct
92 {
93 void (*sa_handler)(int);
94 int sa_flags;
95 shsigset_t sa_mask;
96 } sa;
97#endif
98 /** The number of restarts (siginterrupt / SA_RESTART). */
99 int num_restart;
100 /** The number of ignore handlers. */
101 int num_ignore;
102 /** The number of specific handlers. */
103 int num_specific;
104 /** The number of threads masking it. */
105 int num_masked;
106} g_sig_state[NSIG];
107
108
109
110/** Magic mutex value (final u64).
111 * This is used to detect whether the mutex has been initialized or not,
112 * allowing shmtx_delete to be called more than once without doing harm.
113 * @internal */
114#define SHMTX_MAGIC KU64_C(0x8888000019641018) /**< Charles Stross */
115/** Index into shmtx::au64 of the SHMTX_MAGIC value.
116 * @internal */
117#define SHMTX_MAGIC_IDX (sizeof(shmtx) / sizeof(KU64) - 1)
118
119int shmtx_init(shmtx *pmtx)
120{
121#if K_OS == K_OS_WINDOWS
122 typedef int mtxsizecheck[sizeof(CRITICAL_SECTION) + sizeof(KU64) <= sizeof(*pmtx) ? 2 : 0];
123 InitializeCriticalSection((CRITICAL_SECTION *)pmtx);
124#else
125 pmtx->b[0] = 0;
126#endif
127 pmtx->au64[SHMTX_MAGIC_IDX] = SHMTX_MAGIC;
128 return 0;
129}
130
131/**
132 * Safe to call more than once.
133 */
134void shmtx_delete(shmtx *pmtx)
135{
136 if (pmtx->au64[SHMTX_MAGIC_IDX] != SHMTX_MAGIC)
137 {
138#if K_OS == K_OS_WINDOWS
139 DeleteCriticalSection((CRITICAL_SECTION *)pmtx);
140#else
141 pmtx->b[0] = 0;
142#endif
143 pmtx->au64[SHMTX_MAGIC_IDX] = ~SHMTX_MAGIC;
144 }
145}
146
147void shmtx_enter(shmtx *pmtx, shmtxtmp *ptmp)
148{
149#if K_OS == K_OS_WINDOWS
150 EnterCriticalSection((CRITICAL_SECTION *)pmtx);
151 ptmp->i = 0x42;
152#else
153 pmtx->b[0] = 0;
154 ptmp->i = 0;
155#endif
156}
157
158void shmtx_leave(shmtx *pmtx, shmtxtmp *ptmp)
159{
160#if K_OS == K_OS_WINDOWS
161 assert(ptmp->i == 0x42);
162 LeaveCriticalSection((CRITICAL_SECTION *)pmtx);
163 ptmp->i = 0x21;
164#else
165 pmtx->b[0] = 0;
166 ptmp->i = 432;
167#endif
168}
169
170/**
171 * Links the shell instance.
172 *
173 * @param psh The shell.
174 */
175static void sh_int_link(shinstance *psh)
176{
177 shmtxtmp tmp;
178 shmtx_enter(&g_sh_mtx, &tmp);
179
180 if (psh->rootshell)
181 g_sh_root = psh;
182
183 psh->next = NULL;
184 psh->prev = g_sh_tail;
185 if (g_sh_tail)
186 g_sh_tail->next = psh;
187 else
188 g_sh_tail = g_sh_head = psh;
189 g_sh_tail = psh;
190
191 g_num_shells++;
192
193 psh->linked = 1;
194
195 shmtx_leave(&g_sh_mtx, &tmp);
196}
197
198/**
199 * Unlink the shell instance.
200 *
201 * @param psh The shell.
202 */
203static void sh_int_unlink(shinstance *psh)
204{
205 if (psh->linked)
206 {
207 shinstance *pshcur;
208 shmtxtmp tmp;
209 shmtx_enter(&g_sh_mtx, &tmp);
210
211 g_num_shells--;
212
213 if (g_sh_tail == psh)
214 g_sh_tail = psh->prev;
215 else
216 psh->next->prev = psh->prev;
217
218 if (g_sh_head == psh)
219 g_sh_head = psh->next;
220 else
221 psh->prev->next = psh->next;
222
223 if (g_sh_root == psh)
224 g_sh_root = NULL;
225
226 /* Orphan children: */
227 for (pshcur = g_sh_head; pshcur; pshcur = pshcur->next)
228 if (pshcur->parent == psh)
229 pshcur->parent = NULL;
230
231 shmtx_leave(&g_sh_mtx, &tmp);
232 }
233}
234
235/**
236 * Frees a string vector like environ or argv.
237 *
238 * @param psh The shell to associate the deallocations with.
239 * @param vecp Pointer to the vector pointer.
240 */
241static void sh_free_string_vector(shinstance *psh, char ***vecp)
242{
243 char **vec = *vecp;
244 if (vec)
245 {
246 char *str;
247 size_t i = 0;
248 while ((str = vec[i]) != NULL)
249 {
250 sh_free(psh, str);
251 vec[i] = NULL;
252 i++;
253 }
254
255 sh_free(psh, vec);
256 *vecp = NULL;
257 }
258}
259
260
261/**
262 * Destroys the shell instance.
263 *
264 * This will work on partially initialized instances (because I'm lazy).
265 *
266 * @param psh The shell instance to be destroyed.
267 * @note invalidate thread arguments.
268 */
269static void sh_destroy(shinstance *psh)
270{
271 unsigned left, i;
272
273 sh_int_unlink(psh);
274 shfile_uninit(&psh->fdtab);
275 sh_free_string_vector(psh, &psh->shenviron);
276
277 /** @todo children. */
278 sh_free(psh, psh->threadarg);
279 psh->threadarg = NULL;
280
281 /* alias.c */
282 left = psh->aliases;
283 if (left > 0)
284 for (i = 0; i < K_ELEMENTS(psh->atab); i++)
285 {
286 struct alias *cur = psh->atab[i];
287 if (cur)
288 {
289 do
290 {
291 struct alias *next = cur->next;
292 sh_free(psh, cur->val);
293 sh_free(psh, cur->name);
294 sh_free(psh, cur);
295 cur = next;
296 left--;
297 } while (cur);
298 psh->atab[i] = NULL;
299 if (!left)
300 break;
301 }
302 }
303
304 /* cd.c */
305 sh_free(psh, psh->curdir);
306 psh->curdir = NULL;
307 sh_free(psh, psh->prevdir);
308 psh->prevdir = NULL;
309 psh->cdcomppath = NULL; /* stalloc */
310
311 /* eval.h */
312 if (psh->commandnamemalloc)
313 sh_free(psh, psh->commandname);
314 psh->commandname = NULL;
315 psh->cmdenviron = NULL;
316
317#if 0
318 /* expand.c */
319 char *expdest; /**< output of current string */
320 struct nodelist *argbackq; /**< list of back quote expressions */
321 struct ifsregion ifsfirst; /**< first struct in list of ifs regions */
322 struct ifsregion *ifslastp; /**< last struct in list */
323 struct arglist exparg; /**< holds expanded arg list */
324 char *expdir; /**< Used by expandmeta. */
325
326 /* exec.h */
327 const char *pathopt; /**< set by padvance */
328
329 /* exec.c */
330 struct tblentry *cmdtable[CMDTABLESIZE];
331 int builtinloc/* = -1*/; /**< index in path of %builtin, or -1 */
332
333 /* input.h */
334 int plinno/* = 1 */;/**< input line number */
335 int parsenleft; /**< number of characters left in input buffer */
336 char *parsenextc; /**< next character in input buffer */
337 int init_editline/* = 0 */; /**< 0 == not setup, 1 == OK, -1 == failed */
338
339 /* input.c */
340 int parselleft; /**< copy of parsefile->lleft */
341 struct parsefile basepf; /**< top level input file */
342 char basebuf[BUFSIZ];/**< buffer for top level input file */
343 struct parsefile *parsefile/* = &basepf*/; /**< current input file */
344#ifndef SMALL
345 EditLine *el; /**< cookie for editline package */
346#endif
347
348 /* jobs.h */
349 shpid backgndpid/* = -1 */; /**< pid of last background process */
350 int job_warning; /**< user was warned about stopped jobs */
351
352 /* jobs.c */
353 struct job *jobtab; /**< array of jobs */
354 int njobs; /**< size of array */
355 int jobs_invalid; /**< set in child */
356 shpid initialpgrp; /**< pgrp of shell on invocation */
357 int curjob/* = -1*/;/**< current job */
358 int ttyfd/* = -1*/;
359 int jobctl; /**< job control enabled / disabled */
360 char *cmdnextc;
361 int cmdnleft;
362
363
364 /* mail.c */
365#define MAXMBOXES 10
366 int nmboxes; /**< number of mailboxes */
367 time_t mailtime[MAXMBOXES]; /**< times of mailboxes */
368
369 /* main.h */
370 shpid rootpid; /**< pid of main shell. */
371 int rootshell; /**< true if we aren't a child of the main shell. */
372 struct shinstance *psh_rootshell; /**< The root shell pointer. (!rootshell) */
373
374 /* memalloc.h */
375 char *stacknxt/* = stackbase.space*/;
376 int stacknleft/* = MINSIZE*/;
377 int sstrnleft;
378 int herefd/* = -1 */;
379
380 /* memalloc.c */
381 struct stack_block stackbase;
382 struct stack_block *stackp/* = &stackbase*/;
383 struct stackmark *markp;
384
385 /* myhistedit.h */
386 int displayhist;
387#ifndef SMALL
388 History *hist;
389 EditLine *el;
390#endif
391
392 /* output.h */
393 struct output output;
394 struct output errout;
395 struct output memout;
396 struct output *out1;
397 struct output *out2;
398
399 /* output.c */
400#define OUTBUFSIZ BUFSIZ
401#define MEM_OUT -3 /**< output to dynamically allocated memory */
402
403 /* options.h */
404 struct optent optlist[NOPTS];
405 char *minusc; /**< argument to -c option */
406 char *arg0; /**< $0 */
407 struct shparam shellparam; /**< $@ */
408 char **argptr; /**< argument list for builtin commands */
409 char *optionarg; /**< set by nextopt */
410 char *optptr; /**< used by nextopt */
411 char **orgargv; /**< The original argument vector (for cleanup). */
412 int arg0malloc; /**< Indicates whether arg0 was allocated or is part of orgargv. */
413
414 /* parse.h */
415 int tokpushback;
416 int whichprompt; /**< 1 == PS1, 2 == PS2 */
417
418 /* parser.c */
419 int noalias/* = 0*/;/**< when set, don't handle aliases */
420 struct heredoc *heredoclist; /**< list of here documents to read */
421 int parsebackquote; /**< nonzero if we are inside backquotes */
422 int doprompt; /**< if set, prompt the user */
423 int needprompt; /**< true if interactive and at start of line */
424 int lasttoken; /**< last token read */
425 char *wordtext; /**< text of last word returned by readtoken */
426 int checkkwd; /**< 1 == check for kwds, 2 == also eat newlines */
427 struct nodelist *backquotelist;
428 union node *redirnode;
429 struct heredoc *heredoc;
430 int quoteflag; /**< set if (part of) last token was quoted */
431 int startlinno; /**< line # where last token started */
432
433 /* redir.c */
434 struct redirtab *redirlist;
435 int fd0_redirected/* = 0*/;
436
437 /* show.c */
438 char tracebuf[1024];
439 size_t tracepos;
440 int tracefd;
441
442 /* trap.h */
443 int pendingsigs; /**< indicates some signal received */
444
445 /* trap.c */
446 char gotsig[NSIG]; /**< indicates specified signal received */
447 char *trap[NSIG+1]; /**< trap handler commands */
448 char sigmode[NSIG]; /**< current value of signal */
449
450 /* var.h */
451 struct localvar *localvars;
452 struct var vatty;
453 struct var vifs;
454 struct var vmail;
455 struct var vmpath;
456 struct var vpath;
457#ifdef _MSC_VER
458 struct var vpath2;
459#endif
460 struct var vps1;
461 struct var vps2;
462 struct var vps4;
463#ifndef SMALL
464 struct var vterm;
465 struct var vhistsize;
466#endif
467 struct var voptind;
468#ifdef PC_OS2_LIBPATHS
469 struct var libpath_vars[4];
470#endif
471#ifdef SMALL
472# define VTABSIZE 39
473#else
474# define VTABSIZE 517
475#endif
476 struct var *vartab[VTABSIZE];
477
478 /* builtins.h */
479
480 /* bltin/test.c */
481 char **t_wp;
482 struct t_op const *t_wp_op;
483#endif
484
485/** @todo finish this... */
486 memset(psh, 0, sizeof(*psh));
487 sh_free(NULL, psh);
488}
489
490/**
491 * Clones a string vector like environ or argv.
492 *
493 * @returns 0 on success, -1 and errno on failure.
494 * @param psh The shell to associate the allocations with.
495 * @param dstp Where to store the clone.
496 * @param src The vector to be cloned.
497 */
498static int sh_clone_string_vector(shinstance *psh, char ***dstp, char **src)
499{
500 char **dst;
501 size_t items;
502
503 /* count first */
504 items = 0;
505 while (src[items])
506 items++;
507
508 /* alloc clone array. */
509 *dstp = dst = sh_malloc(psh, sizeof(*dst) * (items + 1));
510 if (!dst)
511 return -1;
512
513 /* copy the items */
514 dst[items] = NULL;
515 while (items-- > 0)
516 {
517 dst[items] = sh_strdup(psh, src[items]);
518 if (!dst[items])
519 {
520 /* allocation error, clean up. */
521 while (dst[++items])
522 sh_free(psh, dst[items]);
523 sh_free(psh, dst);
524 errno = ENOMEM;
525 return -1;
526 }
527 }
528
529 return 0;
530}
531
532/**
533 * Creates a shell instance, caller must link it.
534 *
535 * @param inherit The shell to inherit from, or NULL if root.
536 * @param argv The argument vector.
537 * @param envp The environment vector.
538 * @param parentfdtab File table to inherit from, NULL if root.
539 *
540 * @returns pointer to root shell on success, NULL on failure.
541 */
542static shinstance *sh_create_shell_common(char **argv, char **envp, shfdtab *parentfdtab)
543{
544 shinstance *psh;
545
546 /*
547 * The allocations.
548 */
549 psh = sh_calloc(NULL, sizeof(*psh), 1);
550 if (psh)
551 {
552 /* Init it enough for sh_destroy() to not get upset: */
553 /* ... */
554
555 /* Call the basic initializers. */
556 if ( !sh_clone_string_vector(psh, &psh->shenviron, envp)
557 && !sh_clone_string_vector(psh, &psh->orgargv, argv)
558 && !shfile_init(&psh->fdtab, parentfdtab))
559 {
560 unsigned i;
561
562 /*
563 * The special stuff.
564 */
565#ifdef _MSC_VER
566 psh->pgid = psh->pid = _getpid();
567#else
568 psh->pid = getpid();
569 psh->pgid = getpgid();
570#endif
571
572 /*sh_sigemptyset(&psh->sigrestartset);*/
573 for (i = 0; i < K_ELEMENTS(psh->sigactions); i++)
574 psh->sigactions[i].sh_handler = SH_SIG_UNK;
575#if defined(_MSC_VER)
576 sh_sigemptyset(&psh->sigmask);
577#else
578 sigprocmask(SIG_SETMASK, NULL, &psh->sigmask);
579#endif
580
581 /*
582 * State initialization.
583 */
584 /* cd.c */
585 psh->getpwd_first = 1;
586
587 /* exec */
588 psh->builtinloc = -1;
589
590 /* memalloc.c */
591 psh->stacknleft = MINSIZE;
592 psh->herefd = -1;
593 psh->stackp = &psh->stackbase;
594 psh->stacknxt = psh->stackbase.space;
595
596 /* input.c */
597 psh->plinno = 1;
598 psh->init_editline = 0;
599 psh->parsefile = &psh->basepf;
600
601 /* output.c */
602 psh->output.bufsize = OUTBUFSIZ;
603 psh->output.fd = 1;
604 psh->output.psh = psh;
605 psh->errout.bufsize = 100;
606 psh->errout.fd = 2;
607 psh->errout.psh = psh;
608 psh->memout.fd = MEM_OUT;
609 psh->memout.psh = psh;
610 psh->out1 = &psh->output;
611 psh->out2 = &psh->errout;
612
613 /* jobs.c */
614 psh->backgndpid = -1;
615#if JOBS
616 psh->curjob = -1;
617#else
618# error asdf
619#endif
620 psh->ttyfd = -1;
621
622 /* show.c */
623 psh->tracefd = -1;
624 return psh;
625 }
626
627 sh_destroy(psh);
628 }
629 return NULL;
630}
631
632/**
633 * Creates the root shell instance.
634 *
635 * @param argv The argument vector.
636 * @param envp The environment vector.
637 *
638 * @returns pointer to root shell on success, NULL on failure.
639 */
640shinstance *sh_create_root_shell(char **argv, char **envp)
641{
642 shinstance *psh;
643
644 assert(g_sh_mtx.au64[SHMTX_MAGIC_IDX] != SHMTX_MAGIC);
645 shmtx_init(&g_sh_mtx);
646#ifndef SH_FORKED_MODE
647 shmtx_init(&g_sh_exec_mtx);
648#endif
649
650 psh = sh_create_shell_common(argv, envp, NULL /*parentfdtab*/);
651 if (psh)
652 {
653 sh_int_link(psh);
654 return psh;
655 }
656 return NULL;
657}
658
659#ifndef SH_FORKED_MODE
660
661/**
662 * Does the inherting from the parent shell instance.
663 */
664static void sh_inherit_from_parent(shinstance *psh, shinstance *inherit)
665{
666 /*
667 * Do the rest of the inheriting.
668 */
669 psh->parent = inherit;
670 psh->pgid = inherit->pgid;
671
672 psh->sigmask = psh->sigmask;
673 /** @todo sigactions? */
674 /// @todo suppressint?
675
676 /* alises: */
677 subshellinitalias(psh, inherit);
678
679 /* cd.c */
680 psh->getpwd_first = inherit->getpwd_first;
681 if (inherit->curdir)
682 psh->curdir = savestr(psh, inherit->curdir);
683 if (inherit->prevdir)
684 psh->prevdir = savestr(psh, inherit->prevdir);
685
686 /* eval.h */
687 /* psh->commandname - see subshellinitoptions */
688 psh->exitstatus = inherit->exitstatus; /// @todo ??
689 psh->back_exitstatus = inherit->back_exitstatus; /// @todo ??
690 psh->funcnest = inherit->funcnest;
691 psh->evalskip = inherit->evalskip; /// @todo ??
692 psh->skipcount = inherit->skipcount; /// @todo ??
693
694 /* exec.c */
695 subshellinitexec(psh, inherit);
696
697 /* input.h/input.c - only for the parser and anyway forkchild calls closescript(). */
698
699 /* jobs.h - should backgndpid be -1 in subshells? */
700
701 /* jobs.c - */
702 psh->jobctl = inherit->jobctl; /// @todo ??
703 psh->initialpgrp = inherit->initialpgrp;
704 psh->ttyfd = inherit->ttyfd;
705 /** @todo copy jobtab so the 'jobs' command can be run in a subshell.
706 * Better, make it follow the parent chain and skip the copying. Will
707 * require some kind of job locking. */
708
709 /* mail.c - nothing (for now at least) */
710
711 /* main.h */
712 psh->rootpid = inherit->rootpid;
713 psh->psh_rootshell = inherit->psh_rootshell;
714
715 /* memalloc.h / memalloc.c - nothing. */
716
717 /* myhistedit.h */ /** @todo copy history? Do we need to care? */
718
719 /* output.h */ /** @todo not sure this is possible/relevant for subshells */
720 psh->output.fd = inherit->output.fd;
721 psh->errout.fd = inherit->errout.fd;
722 if (inherit->out1 == &inherit->memout)
723 psh->out1 = &psh->memout;
724 if (inherit->out2 == &inherit->memout)
725 psh->out2 = &psh->memout;
726
727 /* options.h */
728 subshellinitoptions(psh, inherit);
729
730 /* parse.h/parse.c */
731 psh->whichprompt = inherit->whichprompt;
732 /* tokpushback, doprompt and needprompt shouldn't really matter, parsecmd resets thems. */
733 /* The rest are internal to the parser, as I see them, and can be ignored. */
734
735 /* redir.c */
736 subshellinitredir(psh, inherit);
737
738 /* show.c */
739 psh->tracefd = inherit->tracefd;
740
741 /* trap.h / trap.c */ /** @todo we don't carry pendingsigs to the subshell, right? */
742 subshellinittrap(psh, inherit);
743
744 /* var.h */
745 subshellinitvar(psh, inherit);
746}
747
748/**
749 * Creates a child shell instance.
750 *
751 * @param inherit The shell to inherit from.
752 *
753 * @returns pointer to root shell on success, NULL on failure.
754 */
755shinstance *sh_create_child_shell(shinstance *inherit)
756{
757 shinstance *psh = sh_create_shell_common(inherit->orgargv, inherit->shenviron, &inherit->fdtab);
758 if (psh)
759 {
760 /* Fake a pid for the child: */
761 static unsigned volatile s_cShells = 0;
762 int const iSubShell = ++s_cShells;
763 psh->pid = SHPID_MAKE(SHPID_GET_PID(inherit->pid), iSubShell);
764
765 sh_inherit_from_parent(psh, inherit);
766
767 /* link it */
768 sh_int_link(psh);
769 return psh;
770 }
771 return NULL;
772}
773
774#endif /* !SH_FORKED_MODE */
775
776/** getenv() */
777char *sh_getenv(shinstance *psh, const char *var)
778{
779 size_t len;
780 int i = 0;
781
782 if (!var)
783 return NULL;
784
785 len = strlen(var);
786 i = 0;
787 while (psh->shenviron[i])
788 {
789 const char *item = psh->shenviron[i];
790 if ( !strncmp(item, var, len)
791 && item[len] == '=')
792 return (char *)item + len + 1;
793 i++;
794 }
795
796 return NULL;
797}
798
799char **sh_environ(shinstance *psh)
800{
801 return psh->shenviron;
802}
803
804const char *sh_gethomedir(shinstance *psh, const char *user)
805{
806 const char *ret = NULL;
807
808#ifdef _MSC_VER
809 ret = sh_getenv(psh, "HOME");
810 if (!ret)
811 ret = sh_getenv(psh, "USERPROFILE");
812#else
813 struct passwd *pwd = getpwnam(user); /** @todo use getpwdnam_r */
814 (void)psh;
815 ret = pwd ? pwd->pw_dir : NULL;
816#endif
817
818 return ret;
819}
820
821/**
822 * Lazy initialization of a signal state, globally.
823 *
824 * @param psh The shell doing the lazy work.
825 * @param signo The signal (valid).
826 */
827static void sh_int_lazy_init_sigaction(shinstance *psh, int signo)
828{
829 if (psh->sigactions[signo].sh_handler == SH_SIG_UNK)
830 {
831 shmtxtmp tmp;
832 shmtx_enter(&g_sh_mtx, &tmp);
833
834 if (psh->sigactions[signo].sh_handler == SH_SIG_UNK)
835 {
836 shsigaction_t shold;
837 shinstance *cur;
838#ifndef _MSC_VER
839 struct sigaction old;
840 if (!sigaction(signo, NULL, &old))
841 {
842 /* convert */
843 shold.sh_flags = old.sa_flags;
844 shold.sh_mask = old.sa_mask;
845 if (old.sa_handler == SIG_DFL)
846 shold.sh_handler = SH_SIG_DFL;
847 else
848 {
849 assert(old.sa_handler == SIG_IGN);
850 shold.sh_handler = SH_SIG_IGN;
851 }
852 }
853 else
854#endif
855 {
856 /* fake */
857#ifndef _MSC_VER
858 assert(0);
859 old.sa_handler = SIG_DFL;
860 old.sa_flags = 0;
861 sigemptyset(&shold.sh_mask);
862 sigaddset(&shold.sh_mask, signo);
863#endif
864 shold.sh_flags = 0;
865 sh_sigemptyset(&shold.sh_mask);
866 sh_sigaddset(&shold.sh_mask, signo);
867 shold.sh_handler = SH_SIG_DFL;
868 }
869
870 /* update globals */
871#ifndef _MSC_VER
872 g_sig_state[signo].sa = old;
873#else
874 g_sig_state[signo].sa.sa_handler = SIG_DFL;
875 g_sig_state[signo].sa.sa_flags = 0;
876 g_sig_state[signo].sa.sa_mask = shold.sh_mask;
877#endif
878 TRACE2((psh, "sh_int_lazy_init_sigaction: signo=%d:%s sa_handler=%p sa_flags=%#x\n",
879 signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags));
880
881 /* update all shells */
882 for (cur = g_sh_head; cur; cur = cur->next)
883 {
884 assert(cur->sigactions[signo].sh_handler == SH_SIG_UNK);
885 cur->sigactions[signo] = shold;
886 }
887 }
888
889 shmtx_leave(&g_sh_mtx, &tmp);
890 }
891}
892
893/**
894 * Perform the default signal action on the shell.
895 *
896 * @param psh The shell instance.
897 * @param signo The signal.
898 */
899static void sh_sig_do_default(shinstance *psh, int signo)
900{
901 /** @todo */
902}
903
904/**
905 * Deliver a signal to a shell.
906 *
907 * @param psh The shell instance.
908 * @param pshDst The shell instance to signal.
909 * @param signo The signal.
910 * @param locked Whether we're owning the lock or not.
911 */
912static void sh_sig_do_signal(shinstance *psh, shinstance *pshDst, int signo, int locked)
913{
914 shsig_t pfn = pshDst->sigactions[signo].sh_handler;
915 if (pfn == SH_SIG_UNK)
916 {
917 sh_int_lazy_init_sigaction(pshDst, signo);
918 pfn = pshDst->sigactions[signo].sh_handler;
919 }
920
921 if (pfn == SH_SIG_DFL)
922 sh_sig_do_default(pshDst, signo);
923 else if (pfn == SH_SIG_IGN)
924 /* ignore it */;
925 else
926 {
927 assert(pfn != SH_SIG_ERR);
928 pfn(pshDst, signo);
929 }
930 (void)locked;
931}
932
933/**
934 * Handler for external signals.
935 *
936 * @param signo The signal.
937 */
938static void sh_sig_common_handler(int signo)
939{
940 shinstance *psh;
941
942/* fprintf(stderr, "sh_sig_common_handler: signo=%d:%s\n", signo, sys_signame[signo]); */
943
944 /*
945 * No need to take locks if there is only one shell.
946 * Since this will be the initial case, just avoid the deadlock
947 * hell for a litte while...
948 */
949 if (g_num_shells <= 1)
950 {
951 psh = g_sh_head;
952 if (psh)
953 sh_sig_do_signal(NULL, psh, signo, 0 /* no lock */);
954 }
955 else
956 {
957 shmtxtmp tmp;
958 shmtx_enter(&g_sh_mtx, &tmp);
959
960 /** @todo signal focus chain or something? Atm there will only be one shell,
961 * so it's not really important until we go threaded for real... */
962 psh = g_sh_tail;
963 while (psh != NULL)
964 {
965 sh_sig_do_signal(NULL, psh, signo, 1 /* locked */);
966 psh = psh->prev;
967 }
968
969 shmtx_leave(&g_sh_mtx, &tmp);
970 }
971}
972
973int sh_sigaction(shinstance *psh, int signo, const struct shsigaction *newp, struct shsigaction *oldp)
974{
975 if (newp)
976 TRACE2((psh, "sh_sigaction: signo=%d:%s newp=%p:{.sh_handler=%p, .sh_flags=%#x} oldp=%p\n",
977 signo, sys_signame[signo], newp, newp->sh_handler, newp->sh_flags, oldp));
978 else
979 TRACE2((psh, "sh_sigaction: signo=%d:%s newp=NULL oldp=%p\n", signo, sys_signame[signo], oldp));
980
981 /*
982 * Input validation.
983 */
984 if (signo >= NSIG || signo <= 0)
985 {
986 errno = EINVAL;
987 return -1;
988 }
989
990 /*
991 * Make sure our data is correct.
992 */
993 sh_int_lazy_init_sigaction(psh, signo);
994
995 /*
996 * Get the old one if requested.
997 */
998 if (oldp)
999 *oldp = psh->sigactions[signo];
1000
1001 /*
1002 * Set the new one if it has changed.
1003 *
1004 * This will be attempted coordinated with the other signal handlers so
1005 * that we can arrive at a common denominator.
1006 */
1007 if ( newp
1008 && memcmp(&psh->sigactions[signo], newp, sizeof(*newp)))
1009 {
1010 shmtxtmp tmp;
1011 shmtx_enter(&g_sh_mtx, &tmp);
1012
1013 /* Undo the accounting for the current entry. */
1014 if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
1015 g_sig_state[signo].num_ignore--;
1016 else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
1017 g_sig_state[signo].num_specific--;
1018 if (psh->sigactions[signo].sh_flags & SA_RESTART)
1019 g_sig_state[signo].num_restart--;
1020
1021 /* Set the new entry. */
1022 psh->sigactions[signo] = *newp;
1023
1024 /* Add the bits for the new action entry. */
1025 if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
1026 g_sig_state[signo].num_ignore++;
1027 else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
1028 g_sig_state[signo].num_specific++;
1029 if (psh->sigactions[signo].sh_flags & SA_RESTART)
1030 g_sig_state[signo].num_restart++;
1031
1032 /*
1033 * Calc new common action.
1034 *
1035 * This is quit a bit ASSUMPTIVE about the limited use. We will not
1036 * bother synching the mask, and we pretend to care about SA_RESTART.
1037 * The only thing we really actually care about is the sh_handler.
1038 *
1039 * On second though, it's possible we should just tie this to the root
1040 * shell since it only really applies to external signal ...
1041 */
1042 if ( g_sig_state[signo].num_specific
1043 || g_sig_state[signo].num_ignore != g_num_shells)
1044 g_sig_state[signo].sa.sa_handler = sh_sig_common_handler;
1045 else if (g_sig_state[signo].num_ignore)
1046 g_sig_state[signo].sa.sa_handler = SIG_IGN;
1047 else
1048 g_sig_state[signo].sa.sa_handler = SIG_DFL;
1049 g_sig_state[signo].sa.sa_flags = psh->sigactions[signo].sh_flags & SA_RESTART;
1050
1051 TRACE2((psh, "sh_sigaction: setting signo=%d:%s to {.sa_handler=%p, .sa_flags=%#x}\n",
1052 signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags));
1053#ifdef _MSC_VER
1054 if (signal(signo, g_sig_state[signo].sa.sa_handler) == SIG_ERR)
1055 {
1056 TRACE2((psh, "sh_sigaction: SIG_ERR, errno=%d signo=%d\n", errno, signo));
1057 if ( signo != SIGHUP /* whatever */
1058 && signo != SIGQUIT
1059 && signo != SIGPIPE
1060 && signo != SIGTTIN
1061 && signo != SIGTSTP
1062 && signo != SIGTTOU
1063 && signo != SIGCONT)
1064 assert(0);
1065 }
1066#else
1067 if (sigaction(signo, &g_sig_state[signo].sa, NULL))
1068 assert(0);
1069#endif
1070
1071 shmtx_leave(&g_sh_mtx, &tmp);
1072 }
1073
1074 return 0;
1075}
1076
1077shsig_t sh_signal(shinstance *psh, int signo, shsig_t handler)
1078{
1079 shsigaction_t sa;
1080 shsig_t ret;
1081
1082 /*
1083 * Implementation using sh_sigaction.
1084 */
1085 if (sh_sigaction(psh, signo, NULL, &sa))
1086 return SH_SIG_ERR;
1087
1088 ret = sa.sh_handler;
1089 sa.sh_flags &= SA_RESTART;
1090 sa.sh_handler = handler;
1091 sh_sigemptyset(&sa.sh_mask);
1092 sh_sigaddset(&sa.sh_mask, signo); /* ?? */
1093 if (sh_sigaction(psh, signo, &sa, NULL))
1094 return SH_SIG_ERR;
1095
1096 return ret;
1097}
1098
1099int sh_siginterrupt(shinstance *psh, int signo, int interrupt)
1100{
1101 shsigaction_t sa;
1102 int oldflags = 0;
1103
1104 /*
1105 * Implementation using sh_sigaction.
1106 */
1107 if (sh_sigaction(psh, signo, NULL, &sa))
1108 return -1;
1109 oldflags = sa.sh_flags;
1110 if (interrupt)
1111 sa.sh_flags &= ~SA_RESTART;
1112 else
1113 sa.sh_flags |= ~SA_RESTART;
1114 if (!((oldflags ^ sa.sh_flags) & SA_RESTART))
1115 return 0; /* unchanged. */
1116
1117 return sh_sigaction(psh, signo, &sa, NULL);
1118}
1119
1120void sh_sigemptyset(shsigset_t *setp)
1121{
1122 memset(setp, 0, sizeof(*setp));
1123}
1124
1125void sh_sigfillset(shsigset_t *setp)
1126{
1127 memset(setp, 0xff, sizeof(*setp));
1128}
1129
1130void sh_sigaddset(shsigset_t *setp, int signo)
1131{
1132#ifdef _MSC_VER
1133 *setp |= 1U << signo;
1134#else
1135 sigaddset(setp, signo);
1136#endif
1137}
1138
1139void sh_sigdelset(shsigset_t *setp, int signo)
1140{
1141#ifdef _MSC_VER
1142 *setp &= ~(1U << signo);
1143#else
1144 sigdelset(setp, signo);
1145#endif
1146}
1147
1148int sh_sigismember(shsigset_t const *setp, int signo)
1149{
1150#ifdef _MSC_VER
1151 return !!(*setp & (1U << signo));
1152#else
1153 return !!sigismember(setp, signo);
1154#endif
1155}
1156
1157int sh_sigprocmask(shinstance *psh, int operation, shsigset_t const *newp, shsigset_t *oldp)
1158{
1159 int rc;
1160
1161 if ( operation != SIG_BLOCK
1162 && operation != SIG_UNBLOCK
1163 && operation != SIG_SETMASK)
1164 {
1165 errno = EINVAL;
1166 return -1;
1167 }
1168
1169#if defined(SH_FORKED_MODE) && !defined(_MSC_VER)
1170 rc = sigprocmask(operation, newp, oldp);
1171 if (!rc && newp)
1172 psh->sigmask = *newp;
1173
1174#else
1175 if (oldp)
1176 *oldp = psh->sigmask;
1177 if (newp)
1178 {
1179 /* calc the new mask */
1180 shsigset_t mask = psh->sigmask;
1181 switch (operation)
1182 {
1183 case SIG_BLOCK:
1184 for (rc = 0; rc < NSIG; rc++)
1185 if (sh_sigismember(newp, rc))
1186 sh_sigaddset(&mask, rc);
1187 break;
1188 case SIG_UNBLOCK:
1189 for (rc = 0; rc < NSIG; rc++)
1190 if (sh_sigismember(newp, rc))
1191 sh_sigdelset(&mask, rc);
1192 break;
1193 case SIG_SETMASK:
1194 mask = *newp;
1195 break;
1196 }
1197
1198# if defined(_MSC_VER)
1199 rc = 0;
1200# else
1201 rc = sigprocmask(operation, &mask, NULL);
1202 if (!rc)
1203# endif
1204 psh->sigmask = mask;
1205 }
1206
1207#endif
1208 return rc;
1209}
1210
1211SH_NORETURN_1 void sh_abort(shinstance *psh)
1212{
1213 shsigset_t set;
1214 TRACE2((psh, "sh_abort\n"));
1215
1216 /* block other async signals */
1217 sh_sigfillset(&set);
1218 sh_sigdelset(&set, SIGABRT);
1219 sh_sigprocmask(psh, SIG_SETMASK, &set, NULL);
1220
1221 sh_sig_do_signal(psh, psh, SIGABRT, 0 /* no lock */);
1222
1223 /** @todo die in a nicer manner. */
1224 *(char *)1 = 3;
1225
1226 TRACE2((psh, "sh_abort returns!\n"));
1227 (void)psh;
1228 abort();
1229}
1230
1231void sh_raise_sigint(shinstance *psh)
1232{
1233 TRACE2((psh, "sh_raise(SIGINT)\n"));
1234
1235 sh_sig_do_signal(psh, psh, SIGINT, 0 /* no lock */);
1236
1237 TRACE2((psh, "sh_raise(SIGINT) returns\n"));
1238}
1239
1240int sh_kill(shinstance *psh, shpid pid, int signo)
1241{
1242 shinstance *pshDst;
1243 shmtxtmp tmp;
1244 int rc;
1245
1246 /*
1247 * Self or any of the subshells?
1248 */
1249 shmtx_enter(&g_sh_mtx, &tmp);
1250
1251 pshDst = g_sh_tail;
1252 while (pshDst != NULL)
1253 {
1254 if (pshDst->pid == pid)
1255 {
1256 TRACE2((psh, "sh_kill(%" SHPID_PRI ", %d): pshDst=%p\n", pid, signo, pshDst));
1257 sh_sig_do_signal(psh, pshDst, signo, 1 /* locked */);
1258
1259 shmtx_leave(&g_sh_mtx, &tmp);
1260 return 0;
1261 }
1262 pshDst = pshDst->prev;
1263 }
1264
1265 shmtx_leave(&g_sh_mtx, &tmp);
1266
1267 /*
1268 * Some other process, call kill where possible
1269 */
1270#ifdef _MSC_VER
1271 errno = ENOSYS;
1272 rc = -1;
1273#elif defined(SH_FORKED_MODE)
1274/* fprintf(stderr, "kill(%d, %d)\n", pid, signo);*/
1275 rc = kill(pid, signo);
1276#else
1277# error "PORT ME?"
1278#endif
1279
1280 TRACE2((psh, "sh_kill(%d, %d) -> %d [%d]\n", pid, signo, rc, errno));
1281 return rc;
1282}
1283
1284int sh_killpg(shinstance *psh, shpid pgid, int signo)
1285{
1286 shinstance *pshDst;
1287 shmtxtmp tmp;
1288 int rc;
1289
1290 /*
1291 * Self or any of the subshells?
1292 */
1293 shmtx_enter(&g_sh_mtx, &tmp);
1294
1295 pshDst = g_sh_tail;
1296 while (pshDst != NULL)
1297 {
1298 if (pshDst->pgid == pgid)
1299 {
1300 TRACE2((psh, "sh_killpg(%" SHPID_PRI ", %d): pshDst=%p\n", pgid, signo, pshDst));
1301 sh_sig_do_signal(psh, pshDst, signo, 1 /* locked */);
1302
1303 shmtx_leave(&g_sh_mtx, &tmp);
1304 return 0;
1305 }
1306 pshDst = pshDst->prev;
1307 }
1308
1309 shmtx_leave(&g_sh_mtx, &tmp);
1310
1311#ifdef _MSC_VER
1312 errno = ENOSYS;
1313 rc = -1;
1314#elif defined(SH_FORKED_MODE)
1315 //fprintf(stderr, "killpg(%d, %d)\n", pgid, signo);
1316 rc = killpg(pgid, signo);
1317#else
1318# error "PORTME?"
1319#endif
1320
1321 TRACE2((psh, "sh_killpg(%" SHPID_PRI ", %d) -> %d [%d]\n", pgid, signo, rc, errno));
1322 (void)psh;
1323 return rc;
1324}
1325
1326clock_t sh_times(shinstance *psh, shtms *tmsp)
1327{
1328#ifdef _MSC_VER
1329 errno = ENOSYS;
1330 return (clock_t)-1;
1331#elif defined(SH_FORKED_MODE)
1332 (void)psh;
1333 return times(tmsp);
1334#else
1335# error "PORTME"
1336#endif
1337}
1338
1339int sh_sysconf_clk_tck(void)
1340{
1341#ifdef _MSC_VER
1342 return CLK_TCK;
1343#else
1344 return sysconf(_SC_CLK_TCK);
1345#endif
1346}
1347
1348/**
1349 * Adds a child to the shell
1350 *
1351 * @returns 0 on success, on failure -1 and errno set to ENOMEM.
1352 *
1353 * @param psh The shell instance.
1354 * @param pid The child pid.
1355 * @param hChild Windows child handle.
1356 * @param fProcess Set if process, clear if thread.
1357 */
1358int sh_add_child(shinstance *psh, shpid pid, void *hChild, KBOOL fProcess)
1359{
1360 /* get a free table entry. */
1361 unsigned i = psh->num_children++;
1362 if (!(i % 32))
1363 {
1364 void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32));
1365 if (!ptr)
1366 {
1367 psh->num_children--;
1368 errno = ENOMEM;
1369 return -1;
1370 }
1371 psh->children = ptr;
1372 }
1373
1374 /* add it */
1375 psh->children[i].pid = pid;
1376#if K_OS == K_OS_WINDOWS
1377 psh->children[i].hChild = hChild;
1378#endif
1379#ifndef SH_FORKED_MODE
1380 psh->children[i].fProcess = fProcess;
1381#endif
1382 (void)hChild; (void)fProcess;
1383 return 0;
1384}
1385
1386#ifdef SH_FORKED_MODE
1387
1388pid_t sh_fork(shinstance *psh)
1389{
1390 pid_t pid;
1391 TRACE2((psh, "sh_fork\n"));
1392
1393#if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
1394 pid = shfork_do(psh);
1395
1396#elif defined(SH_FORKED_MODE)
1397# ifdef _MSC_VER
1398 pid = -1;
1399 errno = ENOSYS;
1400# else
1401 pid = fork();
1402# endif
1403
1404#else
1405
1406#endif
1407
1408 /* child: update the pid and zap the children array */
1409 if (!pid)
1410 {
1411# ifdef _MSC_VER
1412 psh->pid = _getpid();
1413# else
1414 psh->pid = getpid();
1415# endif
1416 psh->num_children = 0;
1417 }
1418
1419 TRACE2((psh, "sh_fork -> %d [%d]\n", pid, errno));
1420 (void)psh;
1421 return pid;
1422}
1423
1424#else /* !SH_FORKED_MODE */
1425
1426# ifdef _MSC_VER
1427/** Thread wrapper procedure. */
1428static unsigned __stdcall sh_thread_wrapper(void *user)
1429{
1430 shinstance * volatile volpsh = (shinstance *)user;
1431 shinstance *psh = (shinstance *)user;
1432 struct jmploc exitjmp;
1433 int iExit;
1434
1435 /* Update the TID and PID (racing sh_thread_start) */
1436 DWORD tid = GetCurrentThreadId();
1437 shpid pid = GetCurrentProcessId();
1438
1439 pid = SHPID_MAKE(pid, tid);
1440 psh->pid = pid;
1441 psh->tid = tid;
1442
1443 /* Set the TLS entry before we try TRACE or TRACE2. */
1444 shthread_set_shell(psh);
1445
1446 TRACE2((psh, "sh_thread_wrapper: enter\n"));
1447 if ((iExit = setjmp(exitjmp.loc)) == 0)
1448 {
1449 psh->exitjmp = &exitjmp;
1450 iExit = psh->thread(psh, psh->threadarg);
1451 TRACE2((psh, "sh_thread_wrapper: thread proc returns %d (%#x)\n", iExit, iExit));
1452 }
1453 else
1454 {
1455 psh = volpsh; /* paranoia */
1456 psh->exitjmp = NULL;
1457 TRACE2((psh, "sh_thread_wrapper: longjmp: iExit=%d (%#x)\n", iExit, iExit));
1458 if (iExit == SH_EXIT_ZERO)
1459 iExit = 0;
1460 }
1461
1462 /* destroy the shell instance and exit the thread. */
1463 TRACE2((psh, "sh_thread_wrapper: quits - iExit=%d\n", iExit));
1464 sh_destroy(psh);
1465 shthread_set_shell(NULL);
1466 _endthreadex(iExit);
1467 return iExit;
1468}
1469# else
1470# error "PORTME"
1471# endif
1472
1473/**
1474 * Starts a sub-shell thread.
1475 */
1476shpid sh_thread_start(shinstance *pshparent, shinstance *pshchild, int (*thread)(shinstance *, void *), void *arg)
1477{
1478# ifdef _MSC_VER
1479 unsigned tid = 0;
1480 uintptr_t hThread;
1481 shpid pid;
1482
1483 pshchild->thread = thread;
1484 pshchild->threadarg = arg;
1485 hThread = _beginthreadex(NULL /*security*/, 0 /*stack_size*/, sh_thread_wrapper, pshchild, 0 /*initflags*/, &tid);
1486 if (hThread == -1)
1487 return -errno;
1488
1489 pid = SHPID_MAKE(SHPID_GET_PID(pshparent->pid), tid);
1490 pshchild->pid = pid;
1491 pshchild->tid = tid;
1492
1493 if (sh_add_child(pshparent, pid, (void *)hThread, K_FALSE) != 0) {
1494 return -ENOMEM;
1495 }
1496 return pid;
1497
1498# else
1499# error "PORTME"
1500# endif
1501}
1502
1503#endif /* !SH_FORKED_MODE */
1504
1505/** waitpid() */
1506shpid sh_waitpid(shinstance *psh, shpid pid, int *statusp, int flags)
1507{
1508 shpid pidret;
1509#if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
1510 DWORD dwRet;
1511 HANDLE hChild = INVALID_HANDLE_VALUE;
1512 unsigned i;
1513
1514 *statusp = 0;
1515 pidret = -1;
1516 if (pid != -1)
1517 {
1518 /*
1519 * A specific child, try look it up in the child process table
1520 * and wait for it.
1521 */
1522 for (i = 0; i < psh->num_children; i++)
1523 if (psh->children[i].pid == pid)
1524 break;
1525 if (i < psh->num_children)
1526 {
1527 dwRet = WaitForSingleObject(psh->children[i].hChild,
1528 flags & WNOHANG ? 0 : INFINITE);
1529 if (dwRet == WAIT_OBJECT_0)
1530 hChild = psh->children[i].hChild;
1531 else if (dwRet == WAIT_TIMEOUT)
1532 {
1533 i = ~0; /* don't try close anything */
1534 pidret = 0;
1535 }
1536 else
1537 errno = ECHILD;
1538 }
1539 else
1540 errno = ECHILD;
1541 }
1542 else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
1543 {
1544 HANDLE ahChildren[MAXIMUM_WAIT_OBJECTS];
1545 for (i = 0; i < psh->num_children; i++)
1546 ahChildren[i] = psh->children[i].hChild;
1547 dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
1548 FALSE,
1549 flags & WNOHANG ? 0 : INFINITE);
1550 i = dwRet - WAIT_OBJECT_0;
1551 if (i < psh->num_children)
1552 {
1553 hChild = psh->children[i].hChild;
1554 }
1555 else if (dwRet == WAIT_TIMEOUT)
1556 {
1557 i = ~0; /* don't try close anything */
1558 pidret = 0;
1559 }
1560 else
1561 {
1562 i = ~0; /* don't try close anything */
1563 errno = EINVAL;
1564 }
1565 }
1566 else
1567 {
1568 fprintf(stderr, "panic! too many children!\n");
1569 i = ~0;
1570 *(char *)1 = '\0'; /** @todo implement this! */
1571 }
1572
1573 /*
1574 * Close the handle, and if we succeeded collect the exit code first.
1575 */
1576 if (i < psh->num_children)
1577 {
1578 if (hChild != INVALID_HANDLE_VALUE)
1579 {
1580 DWORD dwExitCode = 127;
1581#ifndef SH_FORKED_MODE
1582 if (psh->children[i].fProcess ? GetExitCodeProcess(hChild, &dwExitCode) : GetExitCodeThread(hChild, &dwExitCode))
1583#else
1584 if (GetExitCodeProcess(hChild, &dwExitCode))
1585#endif
1586 {
1587 pidret = psh->children[i].pid;
1588 if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
1589 dwExitCode |= 16;
1590 *statusp = W_EXITCODE(dwExitCode, 0);
1591 }
1592 else
1593 errno = EINVAL;
1594 }
1595
1596 /* remove and close */
1597 hChild = psh->children[i].hChild;
1598 psh->num_children--;
1599 if (i < psh->num_children)
1600 psh->children[i] = psh->children[psh->num_children];
1601 i = CloseHandle(hChild); assert(i);
1602 }
1603
1604#elif defined(SH_FORKED_MODE)
1605 *statusp = 0;
1606# ifdef _MSC_VER
1607 pidret = -1;
1608 errno = ENOSYS;
1609# else
1610 pidret = waitpid(pid, statusp, flags);
1611# endif
1612
1613#else
1614#endif
1615
1616 TRACE2((psh, "waitpid(%" SHPID_PRI ", %p, %#x) -> %" SHPID_PRI " [%d] *statusp=%#x (rc=%d)\n", pid, statusp, flags,
1617 pidret, errno, *statusp, WEXITSTATUS(*statusp)));
1618 (void)psh;
1619 return pidret;
1620}
1621
1622SH_NORETURN_1 void sh__exit(shinstance *psh, int rc)
1623{
1624 TRACE2((psh, "sh__exit(%d)\n", rc));
1625
1626#if defined(SH_FORKED_MODE)
1627 _exit(rc);
1628 (void)psh;
1629
1630#else
1631 psh->exitstatus = rc;
1632
1633 /*
1634 * If we're a thread, jump to the sh_thread_wrapper and make a clean exit.
1635 */
1636 if (psh->thread)
1637 {
1638 if (psh->exitjmp)
1639 longjmp(psh->exitjmp->loc, !rc ? SH_EXIT_ZERO : rc);
1640 else
1641 {
1642 static char const s_msg[] = "fatal error in sh__exit: exitjmp is NULL!\n";
1643 shfile_write(&psh->fdtab, 2, s_msg, sizeof(s_msg) - 1);
1644 _exit(rc);
1645 }
1646 }
1647
1648 /*
1649 * The main thread will typically have to stick around till all subshell
1650 * threads have been stopped. We must tear down this shell instance as
1651 * much as possible before doing this, though, as subshells could be
1652 * waiting for pipes and such to be closed before they're willing to exit.
1653 */
1654 if (g_num_shells > 1)
1655 {
1656 TRACE2((psh, "sh__exit: %u shells around, must wait...\n", g_num_shells));
1657 shfile_uninit(&psh->fdtab);
1658 sh_int_unlink(psh);
1659 /** @todo */
1660 }
1661
1662 _exit(rc);
1663#endif
1664}
1665
1666int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp)
1667{
1668 int rc;
1669
1670#ifdef DEBUG
1671 /* log it all */
1672 TRACE2((psh, "sh_execve(%p:{%s}, %p, %p}\n", exe, exe, argv, envp));
1673 for (rc = 0; argv[rc]; rc++)
1674 TRACE2((psh, " argv[%d]=%p:{%s}\n", rc, argv[rc], argv[rc]));
1675#endif
1676
1677 if (!envp)
1678 envp = (const char * const *)sh_environ(psh);
1679
1680#if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS
1681# ifdef _MSC_VER
1682 errno = 0;
1683 {
1684 intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
1685 if (rc2 != -1)
1686 {
1687 TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
1688 rc = (int)rc2;
1689 if (!rc && rc2)
1690 rc = 16;
1691 exit(rc);
1692 }
1693 }
1694 rc = -1;
1695
1696# else
1697 rc = shfile_exec_unix(&psh->fdtab);
1698 if (!rc)
1699 rc = execve(exe, (char **)argv, (char **)envp);
1700# endif
1701
1702#else
1703# if K_OS == K_OS_WINDOWS
1704 {
1705 /*
1706 * This ain't quite straight forward on Windows...
1707 */
1708#ifndef SH_FORKED_MODE
1709 shmtxtmp tmp;
1710#endif
1711 PROCESS_INFORMATION ProcInfo;
1712 STARTUPINFO StrtInfo;
1713 intptr_t hndls[3];
1714 char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
1715 char *cmdline;
1716 size_t cmdline_size;
1717 char *envblock;
1718 size_t env_size;
1719 char *p;
1720 int i;
1721
1722 /* Create the environment block. */
1723 if (!envp)
1724 envp = sh_environ(psh);
1725 env_size = 2;
1726 for (i = 0; envp[i]; i++)
1727 env_size += strlen(envp[i]) + 1;
1728 envblock = p = sh_malloc(psh, env_size);
1729 for (i = 0; envp[i]; i++)
1730 {
1731 size_t len = strlen(envp[i]) + 1;
1732 memcpy(p, envp[i], len);
1733 p += len;
1734 }
1735 *p = '\0';
1736
1737 /* Figure the size of the command line. Double quotes makes this
1738 tedious and we overestimate to simplify. */
1739 cmdline_size = 2;
1740 for (i = 0; argv[i]; i++)
1741 {
1742 const char *arg = argv[i];
1743 cmdline_size += strlen(arg) + 3;
1744 arg = strchr(arg, '"');
1745 if (arg)
1746 {
1747 do
1748 cmdline_size++;
1749 while ((arg = strchr(arg + 1, '"')) != NULL);
1750 arg = argv[i] - 1;
1751 while ((arg = strchr(arg + 1, '\\')) != NULL);
1752 cmdline_size++;
1753 }
1754 }
1755
1756 /* Create the command line. */
1757 cmdline = p = sh_malloc(psh, cmdline_size);
1758 for (i = 0; argv[i]; i++)
1759 {
1760 const char *arg = argv[i];
1761 const char *cur = arg;
1762 size_t len = strlen(arg);
1763 int quoted = 0;
1764 char ch;
1765 while ((ch = *cur++) != '\0')
1766 if (ch <= 0x20 || strchr("&><|%", ch) != NULL)
1767 {
1768 quoted = 1;
1769 break;
1770 }
1771
1772 if (i != 0)
1773 *(p++) = ' ';
1774 if (quoted)
1775 *(p++) = '"';
1776 if (memchr(arg, '"', len) == NULL)
1777 {
1778 memcpy(p, arg, len);
1779 p += len;
1780 }
1781 else
1782 { /* MS CRT style: double quotes must be escaped; backslashes
1783 must be escaped if followed by double quotes. */
1784 while ((ch = *arg++) != '\0')
1785 if (ch != '\\' && ch != '"')
1786 *p++ = ch;
1787 else if (ch == '"')
1788 {
1789 *p++ = '\\';
1790 *p++ = '"';
1791 }
1792 else
1793 {
1794 unsigned slashes = 1;
1795 *p++ = '\\';
1796 while (*arg == '\\')
1797 {
1798 *p++ = '\\';
1799 slashes++;
1800 arg++;
1801 }
1802 if (*arg == '"')
1803 {
1804 while (slashes-- > 0)
1805 *p++ = '\\';
1806 *p++ = '\\';
1807 *p++ = '"';
1808 arg++;
1809 }
1810 }
1811 }
1812 if (quoted)
1813 *(p++) = '"';
1814 }
1815 p[0] = p[1] = '\0';
1816
1817 /* Init the info structure */
1818 memset(&StrtInfo, '\0', sizeof(StrtInfo));
1819 StrtInfo.cb = sizeof(StrtInfo);
1820
1821 /* File handles. */
1822#ifndef SH_FORKED_MODE
1823 shmtx_enter(&g_sh_exec_mtx, &tmp);
1824#endif
1825 StrtInfo.dwFlags |= STARTF_USESTDHANDLES;
1826 StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
1827 StrtInfo.hStdInput = (HANDLE)hndls[0];
1828 StrtInfo.hStdOutput = (HANDLE)hndls[1];
1829 StrtInfo.hStdError = (HANDLE)hndls[2];
1830
1831 /* Get going... */
1832 rc = CreateProcess(exe,
1833 cmdline,
1834 NULL, /* pProcessAttributes */
1835 NULL, /* pThreadAttributes */
1836 TRUE, /* bInheritHandles */
1837 0, /* dwCreationFlags */
1838 envblock,
1839 cwd,
1840 &StrtInfo,
1841 &ProcInfo);
1842
1843 shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL);
1844#ifndef SH_FORKED_MODE
1845 shmtx_leave(&g_sh_exec_mtx, &tmp);
1846#endif
1847 if (rc)
1848 {
1849 DWORD dwErr;
1850 DWORD dwExitCode;
1851
1852 CloseHandle(ProcInfo.hThread);
1853 dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
1854 assert(dwErr == WAIT_OBJECT_0);
1855
1856 if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
1857 {
1858 CloseHandle(ProcInfo.hProcess);
1859 sh__exit(psh, dwExitCode);
1860 }
1861 TRACE2((psh, "sh_execve: GetExitCodeProcess failed: %u\n", GetLastError()));
1862 assert(0);
1863 CloseHandle(ProcInfo.hProcess);
1864 errno = EINVAL;
1865 }
1866 else
1867 {
1868 DWORD dwErr = GetLastError();
1869 switch (dwErr)
1870 {
1871 case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
1872 case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
1873 case ERROR_BAD_EXE_FORMAT: errno = ENOEXEC; break;
1874 case ERROR_INVALID_EXE_SIGNATURE: errno = ENOEXEC; break;
1875 default:
1876 errno = EINVAL;
1877 break;
1878 }
1879 TRACE2((psh, "sh_execve: dwErr=%d -> errno=%d\n", dwErr, errno));
1880 }
1881
1882 }
1883 rc = -1;
1884
1885# else
1886 errno = ENOSYS;
1887 rc = -1;
1888# endif
1889#endif
1890
1891 TRACE2((psh, "sh_execve -> %d [%d]\n", rc, errno));
1892 (void)psh;
1893 return (int)rc;
1894}
1895
1896uid_t sh_getuid(shinstance *psh)
1897{
1898#ifdef _MSC_VER
1899 uid_t uid = 0;
1900#else
1901 uid_t uid = getuid();
1902#endif
1903
1904 TRACE2((psh, "sh_getuid() -> %d [%d]\n", uid, errno));
1905 (void)psh;
1906 return uid;
1907}
1908
1909uid_t sh_geteuid(shinstance *psh)
1910{
1911#ifdef _MSC_VER
1912 uid_t euid = 0;
1913#else
1914 uid_t euid = geteuid();
1915#endif
1916
1917 TRACE2((psh, "sh_geteuid() -> %d [%d]\n", euid, errno));
1918 (void)psh;
1919 return euid;
1920}
1921
1922gid_t sh_getgid(shinstance *psh)
1923{
1924#ifdef _MSC_VER
1925 gid_t gid = 0;
1926#else
1927 gid_t gid = getgid();
1928#endif
1929
1930 TRACE2((psh, "sh_getgid() -> %d [%d]\n", gid, errno));
1931 (void)psh;
1932 return gid;
1933}
1934
1935gid_t sh_getegid(shinstance *psh)
1936{
1937#ifdef _MSC_VER
1938 gid_t egid = 0;
1939#else
1940 gid_t egid = getegid();
1941#endif
1942
1943 TRACE2((psh, "sh_getegid() -> %d [%d]\n", egid, errno));
1944 (void)psh;
1945 return egid;
1946}
1947
1948shpid sh_getpid(shinstance *psh)
1949{
1950 return psh->pid;
1951}
1952
1953shpid sh_getpgrp(shinstance *psh)
1954{
1955 shpid pgid = psh->pgid;
1956#ifndef _MSC_VER
1957 assert(pgid == getpgrp());
1958#endif
1959
1960 TRACE2((psh, "sh_getpgrp() -> %" SHPID_PRI " [%d]\n", pgid, errno));
1961 return pgid;
1962}
1963
1964/**
1965 * @param pid Should always be zero, i.e. referring to the current shell
1966 * process.
1967 */
1968shpid sh_getpgid(shinstance *psh, shpid pid)
1969{
1970 shpid pgid;
1971 if (pid == 0 || psh->pid == pid)
1972 {
1973 shpid pgid = psh->pgid;
1974#ifndef _MSC_VER
1975 assert(pgid == getpgrp());
1976#endif
1977 }
1978 else
1979 {
1980 assert(0);
1981 errno = ESRCH;
1982 pgid = -1;
1983 }
1984
1985 TRACE2((psh, "sh_getpgid(%" SHPID_PRI ") -> %" SHPID_PRI " [%d]\n", pid, pgid, errno));
1986 return pgid;
1987}
1988
1989/**
1990 *
1991 * @param pid The pid to modify. This is always 0, except when forkparent
1992 * calls to group a newly created child. Though, we might
1993 * almost safely ignore it in that case as the child will also
1994 * perform the operation.
1995 * @param pgid The process group to assign @a pid to.
1996 */
1997int sh_setpgid(shinstance *psh, shpid pid, shpid pgid)
1998{
1999#if defined(SH_FORKED_MODE) && !defined(_MSC_VER)
2000 int rc = setpgid(pid, pgid);
2001 TRACE2((psh, "sh_setpgid(%" SHPID_PRI ", %" SHPID_PRI ") -> %d [%d]\n", pid, pgid, rc, errno));
2002 (void)psh;
2003#else
2004 int rc = 0;
2005 if (pid == 0 || psh->pid == pid)
2006 {
2007 TRACE2((psh, "sh_setpgid(self,): %" SHPID_PRI " -> %" SHPID_PRI "\n", psh->pgid, pgid));
2008 psh->pgid = pgid;
2009 }
2010 else
2011 {
2012 /** @todo fixme */
2013 rc = -1;
2014 errno = ENOSYS;
2015 }
2016#endif
2017 return rc;
2018}
2019
2020shpid sh_tcgetpgrp(shinstance *psh, int fd)
2021{
2022 shpid pgrp;
2023
2024#ifdef _MSC_VER
2025 pgrp = -1;
2026 errno = ENOSYS;
2027#elif defined(SH_FORKED_MODE)
2028 pgrp = tcgetpgrp(fd);
2029#else
2030# error "PORT ME"
2031#endif
2032
2033 TRACE2((psh, "sh_tcgetpgrp(%d) -> %" SHPID_PRI " [%d]\n", fd, pgrp, errno));
2034 (void)psh;
2035 return pgrp;
2036}
2037
2038int sh_tcsetpgrp(shinstance *psh, int fd, shpid pgrp)
2039{
2040 int rc;
2041 TRACE2((psh, "sh_tcsetpgrp(%d, %" SHPID_PRI ")\n", fd, pgrp));
2042
2043#ifdef _MSC_VER
2044 rc = -1;
2045 errno = ENOSYS;
2046#elif defined(SH_FORKED_MODE)
2047 rc = tcsetpgrp(fd, pgrp);
2048#else
2049# error "PORT ME"
2050#endif
2051
2052 TRACE2((psh, "sh_tcsetpgrp(%d, %" SHPID_PRI ") -> %d [%d]\n", fd, pgrp, rc, errno));
2053 (void)psh;
2054 return rc;
2055}
2056
2057int sh_getrlimit(shinstance *psh, int resid, shrlimit *limp)
2058{
2059#ifdef _MSC_VER
2060 int rc = -1;
2061 errno = ENOSYS;
2062#elif defined(SH_FORKED_MODE)
2063 int rc = getrlimit(resid, limp);
2064#else
2065# error "PORT ME"
2066 /* returned the stored limit */
2067#endif
2068
2069 TRACE2((psh, "sh_getrlimit(%d, %p) -> %d [%d] {%ld,%ld}\n",
2070 resid, limp, rc, errno, (long)limp->rlim_cur, (long)limp->rlim_max));
2071 (void)psh;
2072 return rc;
2073}
2074
2075int sh_setrlimit(shinstance *psh, int resid, const shrlimit *limp)
2076{
2077#ifdef _MSC_VER
2078 int rc = -1;
2079 errno = ENOSYS;
2080#elif defined(SH_FORKED_MODE)
2081 int rc = setrlimit(resid, limp);
2082#else
2083# error "PORT ME"
2084 /* if max(shell) < limp; then setrlimit; fi
2085 if success; then store limit for later retrival and maxing. */
2086
2087#endif
2088
2089 TRACE2((psh, "sh_setrlimit(%d, %p:{%ld,%ld}) -> %d [%d]\n",
2090 resid, limp, (long)limp->rlim_cur, (long)limp->rlim_max, rc, errno));
2091 (void)psh;
2092 return rc;
2093}
2094
2095
2096/* Wrapper for strerror that makes sure it doesn't return NULL and causes the
2097 caller or fprintf routines to crash. */
2098const char *sh_strerror(shinstance *psh, int error)
2099{
2100 char *err = strerror(error);
2101 if (!err)
2102 return "strerror return NULL!";
2103 (void)psh;
2104 return err;
2105}
2106
Note: See TracBrowser for help on using the repository browser.