VirtualBox

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

Last change on this file since 3505 was 3480, checked in by bird, 4 years ago

kash: build fixes (darwin).

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

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