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

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

kash: when duplicateing a fdtab, don't heed close-on-exec on windows or in non-forked mode. Close files in sh_execve before waiting, but leave the tracefd open.

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