VirtualBox

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

最後變更 在這個檔案從3570是 3570,由 bird 提交於 3 年 前

kash: Must NULL nextc when freeing an output buffer.

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

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