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

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

kash: sh_destroy should be mostly finished now.

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