VirtualBox

source: kBuild/trunk/src/kash/shinstance.c@ 3458

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

kash: Use reference counting of parser output in threaded-mode.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette