VirtualBox

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

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

kash: more sh_destroy work.

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