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

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

kash: Use event semaphores to signal parent shell early before the subshell thread has performed cleanups.

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