VirtualBox

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

Last change on this file since 2652 was 2652, checked in by bird, 12 years ago

kash: Fixes for hash-bang-scripts on windows. Related debug tracing fix. Another CWD slash fix. Fixed a couple of assertions.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 34.3 KB
Line 
1/* $Id: shinstance.c 2652 2012-09-09 17:21:48Z 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* Header Files *
30*******************************************************************************/
31#include <string.h>
32#include <stdlib.h>
33#include <assert.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#if K_OS == K_OS_WINDOWS
43# include <Windows.h>
44extern pid_t shfork_do(shinstance *psh); /* shforkA-win.asm */
45#endif
46#if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG)
47extern void init_sys_signame(void);
48#endif
49
50
51/*******************************************************************************
52* Global Variables *
53*******************************************************************************/
54/** The mutex protecting the the globals and some shell instance members (sigs). */
55static shmtx g_sh_mtx;
56/** The root shell instance. */
57static shinstance *g_sh_root;
58/** The first shell instance. */
59static shinstance *g_sh_head;
60/** The last shell instance. */
61static shinstance *g_sh_tail;
62/** The number of shells. */
63static int volatile g_num_shells;
64/** Per signal state for determining a common denominator.
65 * @remarks defaults and unmasked actions aren't counted. */
66struct shsigstate
67{
68 /** The current signal action. */
69#ifndef _MSC_VER
70 struct sigaction sa;
71#else
72 struct
73 {
74 void (*sa_handler)(int);
75 int sa_flags;
76 shsigset_t sa_mask;
77 } sa;
78#endif
79 /** The number of restarts (siginterrupt / SA_RESTART). */
80 int num_restart;
81 /** The number of ignore handlers. */
82 int num_ignore;
83 /** The number of specific handlers. */
84 int num_specific;
85 /** The number of threads masking it. */
86 int num_masked;
87} g_sig_state[NSIG];
88
89
90
91int shmtx_init(shmtx *pmtx)
92{
93 pmtx->b[0] = 0;
94 return 0;
95}
96
97void shmtx_delete(shmtx *pmtx)
98{
99 pmtx->b[0] = 0;
100}
101
102void shmtx_enter(shmtx *pmtx, shmtxtmp *ptmp)
103{
104 pmtx->b[0] = 0;
105 ptmp->i = 0;
106}
107
108void shmtx_leave(shmtx *pmtx, shmtxtmp *ptmp)
109{
110 pmtx->b[0] = 0;
111 ptmp->i = 432;
112}
113
114/**
115 * Links the shell instance.
116 *
117 * @param psh The shell.
118 */
119static void sh_int_link(shinstance *psh)
120{
121 shmtxtmp tmp;
122 shmtx_enter(&g_sh_mtx, &tmp);
123
124 if (psh->rootshell)
125 g_sh_root = psh;
126
127 psh->next = NULL;
128 psh->prev = g_sh_tail;
129 if (g_sh_tail)
130 g_sh_tail->next = psh;
131 else
132 g_sh_tail = g_sh_head = psh;
133 g_sh_tail = psh;
134
135 g_num_shells++;
136
137 shmtx_leave(&g_sh_mtx, &tmp);
138}
139
140#if 0
141/**
142 * Unlink the shell instance.
143 *
144 * @param psh The shell.
145 */
146static void sh_int_unlink(shinstance *psh)
147{
148 shmtxtmp tmp;
149 shmtx_enter(&g_sh_mtx, &tmp);
150
151 g_num_shells--;
152
153 if (g_sh_tail == psh)
154 g_sh_tail = psh->prev;
155 else
156 psh->next->prev = psh->prev;
157
158 if (g_sh_head == psh)
159 g_sh_head = psh->next;
160 else
161 psh->prev->next = psh->next;
162
163 if (g_sh_root == psh)
164 g_sh_root = 0;
165
166 shmtx_leave(&g_sh_mtx, &tmp);
167}
168#endif
169
170/**
171 * Destroys the shell instance.
172 *
173 * This will work on partially initialized instances (because I'm lazy).
174 *
175 * @param psh The shell instance to be destroyed.
176 */
177static void sh_destroy(shinstance *psh)
178{
179 memset(psh, 0, sizeof(*psh));
180 sh_free(NULL, psh);
181}
182
183/**
184 * Clones a string vector like enviorn or argv.
185 *
186 * @returns 0 on success, -1 and errno on failure.
187 * @param psh The shell to associate the allocations with.
188 * @param dstp Where to store the clone.
189 * @param src The vector to be cloned.
190 */
191static int sh_clone_string_vector(shinstance *psh, char ***dstp, char **src)
192{
193 char **dst;
194 size_t items;
195
196 /* count first */
197 items = 0;
198 while (src[items])
199 items++;
200
201 /* alloc clone array. */
202 *dstp = dst = sh_malloc(psh, sizeof(*dst) * items + 1);
203 if (!dst)
204 return -1;
205
206 /* copy the items */
207 dst[items] = NULL;
208 while (items-- > 0)
209 {
210 dst[items] = sh_strdup(psh, src[items]);
211 if (!dst[items])
212 {
213 /* allocation error, clean up. */
214 while (dst[++items])
215 sh_free(psh, dst[items]);
216 sh_free(psh, dst);
217 errno = ENOMEM;
218 return -1;
219 }
220 }
221
222 return 0;
223}
224
225/**
226 * Creates a root shell instance.
227 *
228 * @param inherit The shell to inherit from. If NULL inherit from environment and such.
229 * @param argc The argument count.
230 * @param argv The argument vector.
231 * @param envp The environment vector.
232 *
233 * @returns pointer to root shell on success, NULL on failure.
234 */
235shinstance *sh_create_root_shell(shinstance *inherit, int argc, char **argv, char **envp)
236{
237 shinstance *psh;
238 int i;
239
240 /*
241 * The allocations.
242 */
243 psh = sh_calloc(NULL, sizeof(*psh), 1);
244 if (psh)
245 {
246 /* Init it enought for sh_destroy() to not get upset */
247 /* ... */
248
249 /* Call the basic initializers. */
250 if ( !sh_clone_string_vector(psh, &psh->shenviron, envp)
251 && !sh_clone_string_vector(psh, &psh->argptr, argv)
252 && !shfile_init(&psh->fdtab, inherit ? &inherit->fdtab : NULL))
253 {
254 /* the special stuff. */
255#ifdef _MSC_VER
256 psh->pid = _getpid();
257#else
258 psh->pid = getpid();
259#endif
260 /*sh_sigemptyset(&psh->sigrestartset);*/
261 for (i = 0; i < NSIG; i++)
262 psh->sigactions[i].sh_handler = SH_SIG_UNK;
263 if (inherit)
264 psh->sigmask = psh->sigmask;
265 else
266 {
267#if defined(_MSC_VER)
268 sh_sigemptyset(&psh->sigmask);
269#else
270 sigprocmask(SIG_SETMASK, NULL, &psh->sigmask);
271#endif
272 }
273
274 /* memalloc.c */
275 psh->stacknleft = MINSIZE;
276 psh->herefd = -1;
277 psh->stackp = &psh->stackbase;
278 psh->stacknxt = psh->stackbase.space;
279
280 /* input.c */
281 psh->plinno = 1;
282 psh->init_editline = 0;
283 psh->parsefile = &psh->basepf;
284
285 /* output.c */
286 psh->output.bufsize = OUTBUFSIZ;
287 psh->output.fd = 1;
288 psh->output.psh = psh;
289 psh->errout.bufsize = 100;
290 psh->errout.fd = 2;
291 psh->errout.psh = psh;
292 psh->memout.fd = MEM_OUT;
293 psh->memout.psh = psh;
294 psh->out1 = &psh->output;
295 psh->out2 = &psh->errout;
296
297 /* jobs.c */
298 psh->backgndpid = -1;
299#if JOBS
300 psh->curjob = -1;
301#else
302# error asdf
303#endif
304 psh->ttyfd = -1;
305
306 /* show.c */
307 psh->tracefd = -1;
308
309 /* link it. */
310 sh_int_link(psh);
311 return psh;
312 }
313
314 sh_destroy(psh);
315 }
316 return NULL;
317}
318
319/** getenv() */
320char *sh_getenv(shinstance *psh, const char *var)
321{
322 size_t len;
323 int i = 0;
324
325 if (!var)
326 return NULL;
327
328 len = strlen(var);
329 i = 0;
330 while (psh->shenviron[i])
331 {
332 const char *item = psh->shenviron[i];
333 if ( !strncmp(item, var, len)
334 && item[len] == '=')
335 return (char *)item + len + 1;
336 }
337
338 return NULL;
339}
340
341char **sh_environ(shinstance *psh)
342{
343 return psh->shenviron;
344}
345
346const char *sh_gethomedir(shinstance *psh, const char *user)
347{
348 const char *ret = NULL;
349
350#ifdef _MSC_VER
351 ret = sh_getenv(psh, "HOME");
352 if (!ret)
353 ret = sh_getenv(psh, "USERPROFILE");
354#else
355 struct passwd *pwd = getpwnam(user); /** @todo use getpwdnam_r */
356 (void)psh;
357 ret = pwd ? pwd->pw_dir : NULL;
358#endif
359
360 return ret;
361}
362
363/**
364 * Lazy initialization of a signal state, globally.
365 *
366 * @param psh The shell doing the lazy work.
367 * @param signo The signal (valid).
368 */
369static void sh_int_lazy_init_sigaction(shinstance *psh, int signo)
370{
371 if (psh->sigactions[signo].sh_handler == SH_SIG_UNK)
372 {
373 shmtxtmp tmp;
374 shmtx_enter(&g_sh_mtx, &tmp);
375
376 if (psh->sigactions[signo].sh_handler == SH_SIG_UNK)
377 {
378 shsigaction_t shold;
379 shinstance *cur;
380#ifndef _MSC_VER
381 struct sigaction old;
382 if (!sigaction(signo, NULL, &old))
383 {
384 /* convert */
385 shold.sh_flags = old.sa_flags;
386 shold.sh_mask = old.sa_mask;
387 if (old.sa_handler == SIG_DFL)
388 shold.sh_handler = SH_SIG_DFL;
389 else
390 {
391 assert(old.sa_handler == SIG_IGN);
392 shold.sh_handler = SH_SIG_IGN;
393 }
394 }
395 else
396#endif
397 {
398 /* fake */
399#ifndef _MSC_VER
400 assert(0);
401 old.sa_handler = SIG_DFL;
402 old.sa_flags = 0;
403 sigemptyset(&shold.sh_mask);
404 sigaddset(&shold.sh_mask, signo);
405#endif
406 shold.sh_flags = 0;
407 sh_sigemptyset(&shold.sh_mask);
408 sh_sigaddset(&shold.sh_mask, signo);
409 shold.sh_handler = SH_SIG_DFL;
410 }
411
412 /* update globals */
413#ifndef _MSC_VER
414 g_sig_state[signo].sa = old;
415#else
416 g_sig_state[signo].sa.sa_handler = SIG_DFL;
417 g_sig_state[signo].sa.sa_flags = 0;
418 g_sig_state[signo].sa.sa_mask = shold.sh_mask;
419#endif
420 TRACE2((psh, "sh_int_lazy_init_sigaction: signo=%d:%s sa_handler=%p sa_flags=%#x\n",
421 signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags));
422
423 /* update all shells */
424 for (cur = g_sh_head; cur; cur = cur->next)
425 {
426 assert(cur->sigactions[signo].sh_handler == SH_SIG_UNK);
427 cur->sigactions[signo] = shold;
428 }
429 }
430
431 shmtx_leave(&g_sh_mtx, &tmp);
432 }
433}
434
435/**
436 * Perform the default signal action on the shell.
437 *
438 * @param psh The shell instance.
439 * @param signo The signal.
440 */
441static void sh_sig_do_default(shinstance *psh, int signo)
442{
443 /** @todo */
444}
445
446/**
447 * Deliver a signal to a shell.
448 *
449 * @param psh The shell instance.
450 * @param pshDst The shell instance to signal.
451 * @param signo The signal.
452 * @param locked Whether we're owning the lock or not.
453 */
454static void sh_sig_do_signal(shinstance *psh, shinstance *pshDst, int signo, int locked)
455{
456 shsig_t pfn = pshDst->sigactions[signo].sh_handler;
457 if (pfn == SH_SIG_UNK)
458 {
459 sh_int_lazy_init_sigaction(pshDst, signo);
460 pfn = pshDst->sigactions[signo].sh_handler;
461 }
462
463 if (pfn == SH_SIG_DFL)
464 sh_sig_do_default(pshDst, signo);
465 else if (pfn == SH_SIG_IGN)
466 /* ignore it */;
467 else
468 {
469 assert(pfn != SH_SIG_ERR);
470 pfn(pshDst, signo);
471 }
472 (void)locked;
473}
474
475/**
476 * Handler for external signals.
477 *
478 * @param signo The signal.
479 */
480static void sh_sig_common_handler(int signo)
481{
482 shinstance *psh;
483
484/* fprintf(stderr, "sh_sig_common_handler: signo=%d:%s\n", signo, sys_signame[signo]); */
485
486 /*
487 * No need to take locks if there is only one shell.
488 * Since this will be the initial case, just avoid the deadlock
489 * hell for a litte while...
490 */
491 if (g_num_shells <= 1)
492 {
493 psh = g_sh_head;
494 if (psh)
495 sh_sig_do_signal(NULL, psh, signo, 0 /* no lock */);
496 }
497 else
498 {
499 shmtxtmp tmp;
500 shmtx_enter(&g_sh_mtx, &tmp);
501
502 /** @todo signal focus chain or something? Atm there will only be one shell,
503 * so it's not really important until we go threaded for real... */
504 psh = g_sh_tail;
505 while (psh != NULL)
506 {
507 sh_sig_do_signal(NULL, psh, signo, 1 /* locked */);
508 psh = psh->prev;
509 }
510
511 shmtx_leave(&g_sh_mtx, &tmp);
512 }
513}
514
515int sh_sigaction(shinstance *psh, int signo, const struct shsigaction *newp, struct shsigaction *oldp)
516{
517 if (newp)
518 TRACE2((psh, "sh_sigaction: signo=%d:%s newp=%p:{.sh_handler=%p, .sh_flags=%#x} oldp=%p\n",
519 signo, sys_signame[signo], newp, newp->sh_handler, newp->sh_flags, oldp));
520 else
521 TRACE2((psh, "sh_sigaction: signo=%d:%s newp=NULL oldp=%p\n", signo, sys_signame[signo], oldp));
522
523 /*
524 * Input validation.
525 */
526 if (signo >= NSIG || signo <= 0)
527 {
528 errno = EINVAL;
529 return -1;
530 }
531
532 /*
533 * Make sure our data is correct.
534 */
535 sh_int_lazy_init_sigaction(psh, signo);
536
537 /*
538 * Get the old one if requested.
539 */
540 if (oldp)
541 *oldp = psh->sigactions[signo];
542
543 /*
544 * Set the new one if it has changed.
545 *
546 * This will be attempted coordinated with the other signal handlers so
547 * that we can arrive at a common denominator.
548 */
549 if ( newp
550 && memcmp(&psh->sigactions[signo], newp, sizeof(*newp)))
551 {
552 shmtxtmp tmp;
553 shmtx_enter(&g_sh_mtx, &tmp);
554
555 /* Undo the accounting for the current entry. */
556 if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
557 g_sig_state[signo].num_ignore--;
558 else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
559 g_sig_state[signo].num_specific--;
560 if (psh->sigactions[signo].sh_flags & SA_RESTART)
561 g_sig_state[signo].num_restart--;
562
563 /* Set the new entry. */
564 psh->sigactions[signo] = *newp;
565
566 /* Add the bits for the new action entry. */
567 if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
568 g_sig_state[signo].num_ignore++;
569 else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
570 g_sig_state[signo].num_specific++;
571 if (psh->sigactions[signo].sh_flags & SA_RESTART)
572 g_sig_state[signo].num_restart++;
573
574 /*
575 * Calc new common action.
576 *
577 * This is quit a bit ASSUMPTIVE about the limited use. We will not
578 * bother synching the mask, and we pretend to care about SA_RESTART.
579 * The only thing we really actually care about is the sh_handler.
580 *
581 * On second though, it's possible we should just tie this to the root
582 * shell since it only really applies to external signal ...
583 */
584 if ( g_sig_state[signo].num_specific
585 || g_sig_state[signo].num_ignore != g_num_shells)
586 g_sig_state[signo].sa.sa_handler = sh_sig_common_handler;
587 else if (g_sig_state[signo].num_ignore)
588 g_sig_state[signo].sa.sa_handler = SIG_IGN;
589 else
590 g_sig_state[signo].sa.sa_handler = SIG_DFL;
591 g_sig_state[signo].sa.sa_flags = psh->sigactions[signo].sh_flags & SA_RESTART;
592
593#if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG)
594 init_sys_signame();
595#endif
596 TRACE2((psh, "sh_sigaction: setting signo=%d:%s to {.sa_handler=%p, .sa_flags=%#x}\n",
597 signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags));
598#ifdef _MSC_VER
599 if (signal(signo, g_sig_state[signo].sa.sa_handler) == SIG_ERR)
600 {
601 TRACE2((psh, "sh_sigaction: SIG_ERR, errno=%d signo=%d\n", errno, signo));
602 if ( signo != SIGHUP /* whatever */
603 && signo != SIGQUIT
604 && signo != SIGPIPE
605 && signo != SIGTTIN
606 && signo != SIGTSTP
607 && signo != SIGTTOU
608 && signo != SIGCONT)
609 assert(0);
610 }
611#else
612 if (sigaction(signo, &g_sig_state[signo].sa, NULL))
613 assert(0);
614#endif
615
616 shmtx_leave(&g_sh_mtx, &tmp);
617 }
618
619 return 0;
620}
621
622shsig_t sh_signal(shinstance *psh, int signo, shsig_t handler)
623{
624 shsigaction_t sa;
625 shsig_t ret;
626
627 /*
628 * Implementation using sh_sigaction.
629 */
630 if (sh_sigaction(psh, signo, NULL, &sa))
631 return SH_SIG_ERR;
632
633 ret = sa.sh_handler;
634 sa.sh_flags &= SA_RESTART;
635 sa.sh_handler = handler;
636 sh_sigemptyset(&sa.sh_mask);
637 sh_sigaddset(&sa.sh_mask, signo); /* ?? */
638 if (sh_sigaction(psh, signo, &sa, NULL))
639 return SH_SIG_ERR;
640
641 return ret;
642}
643
644int sh_siginterrupt(shinstance *psh, int signo, int interrupt)
645{
646 shsigaction_t sa;
647 int oldflags = 0;
648
649 /*
650 * Implementation using sh_sigaction.
651 */
652 if (sh_sigaction(psh, signo, NULL, &sa))
653 return -1;
654 oldflags = sa.sh_flags;
655 if (interrupt)
656 sa.sh_flags &= ~SA_RESTART;
657 else
658 sa.sh_flags |= ~SA_RESTART;
659 if (!((oldflags ^ sa.sh_flags) & SA_RESTART))
660 return 0; /* unchanged. */
661
662 return sh_sigaction(psh, signo, &sa, NULL);
663}
664
665void sh_sigemptyset(shsigset_t *setp)
666{
667 memset(setp, 0, sizeof(*setp));
668}
669
670void sh_sigfillset(shsigset_t *setp)
671{
672 memset(setp, 0xff, sizeof(*setp));
673}
674
675void sh_sigaddset(shsigset_t *setp, int signo)
676{
677#ifdef _MSC_VER
678 *setp |= 1U << signo;
679#else
680 sigaddset(setp, signo);
681#endif
682}
683
684void sh_sigdelset(shsigset_t *setp, int signo)
685{
686#ifdef _MSC_VER
687 *setp &= ~(1U << signo);
688#else
689 sigdelset(setp, signo);
690#endif
691}
692
693int sh_sigismember(shsigset_t const *setp, int signo)
694{
695#ifdef _MSC_VER
696 return !!(*setp & (1U << signo));
697#else
698 return !!sigismember(setp, signo);
699#endif
700}
701
702int sh_sigprocmask(shinstance *psh, int operation, shsigset_t const *newp, shsigset_t *oldp)
703{
704 int rc;
705
706 if ( operation != SIG_BLOCK
707 && operation != SIG_UNBLOCK
708 && operation != SIG_SETMASK)
709 {
710 errno = EINVAL;
711 return -1;
712 }
713
714#if defined(SH_FORKED_MODE) && !defined(_MSC_VER)
715 rc = sigprocmask(operation, newp, oldp);
716 if (!rc && newp)
717 psh->sigmask = *newp;
718
719#else
720 if (oldp)
721 *oldp = psh->sigmask;
722 if (newp)
723 {
724 /* calc the new mask */
725 shsigset_t mask = psh->sigmask;
726 switch (operation)
727 {
728 case SIG_BLOCK:
729 for (rc = 0; rc < NSIG; rc++)
730 if (sh_sigismember(newp, rc))
731 sh_sigaddset(&mask, rc);
732 break;
733 case SIG_UNBLOCK:
734 for (rc = 0; rc < NSIG; rc++)
735 if (sh_sigismember(newp, rc))
736 sh_sigdelset(&mask, rc);
737 break;
738 case SIG_SETMASK:
739 mask = *newp;
740 break;
741 }
742
743# if defined(_MSC_VER)
744 rc = 0;
745# else
746 rc = sigprocmask(operation, &mask, NULL);
747 if (!rc)
748# endif
749 psh->sigmask = mask;
750 }
751
752#endif
753 return rc;
754}
755
756SH_NORETURN_1 void sh_abort(shinstance *psh)
757{
758 shsigset_t set;
759 TRACE2((psh, "sh_abort\n"));
760
761 /* block other async signals */
762 sh_sigfillset(&set);
763 sh_sigdelset(&set, SIGABRT);
764 sh_sigprocmask(psh, SIG_SETMASK, &set, NULL);
765
766 sh_sig_do_signal(psh, psh, SIGABRT, 0 /* no lock */);
767
768 /** @todo die in a nicer manner. */
769 *(char *)1 = 3;
770
771 TRACE2((psh, "sh_abort returns!\n"));
772 (void)psh;
773 abort();
774}
775
776void sh_raise_sigint(shinstance *psh)
777{
778 TRACE2((psh, "sh_raise(SIGINT)\n"));
779
780 sh_sig_do_signal(psh, psh, SIGINT, 0 /* no lock */);
781
782 TRACE2((psh, "sh_raise(SIGINT) returns\n"));
783}
784
785int sh_kill(shinstance *psh, pid_t pid, int signo)
786{
787 shinstance *pshDst;
788 shmtxtmp tmp;
789 int rc;
790
791 /*
792 * Self or any of the subshells?
793 */
794 shmtx_enter(&g_sh_mtx, &tmp);
795
796 pshDst = g_sh_tail;
797 while (pshDst != NULL)
798 {
799 if (pshDst->pid == pid)
800 {
801 TRACE2((psh, "sh_kill(%d, %d): pshDst=%p\n", pid, signo, pshDst));
802 sh_sig_do_signal(psh, pshDst, signo, 1 /* locked */);
803
804 shmtx_leave(&g_sh_mtx, &tmp);
805 return 0;
806 }
807 pshDst = pshDst->prev;
808 }
809
810 shmtx_leave(&g_sh_mtx, &tmp);
811
812 /*
813 * Some other process, call kill where possible
814 */
815#if defined(SH_FORKED_MODE)
816# ifdef _MSC_VER
817 errno = ENOSYS;
818 rc = -1;
819# else
820/* fprintf(stderr, "kill(%d, %d)\n", pid, signo);*/
821 rc = kill(pid, signo);
822# endif
823
824#else
825#endif
826
827 TRACE2((psh, "sh_kill(%d, %d) -> %d [%d]\n", pid, signo, rc, errno));
828 return rc;
829}
830
831int sh_killpg(shinstance *psh, pid_t pgid, int signo)
832{
833 int rc;
834
835#if defined(SH_FORKED_MODE)
836# ifdef _MSC_VER
837 errno = ENOSYS;
838 rc = -1;
839# else
840 //fprintf(stderr, "killpg(%d, %d)\n", pgid, signo);
841 rc = killpg(pgid, signo);
842# endif
843
844#else
845#endif
846
847 TRACE2((psh, "sh_killpg(%d, %d) -> %d [%d]\n", pgid, signo, rc, errno));
848 (void)psh;
849 return rc;
850}
851
852clock_t sh_times(shinstance *psh, shtms *tmsp)
853{
854#if defined(SH_FORKED_MODE)
855 (void)psh;
856# ifdef _MSC_VER
857 errno = ENOSYS;
858 return (clock_t)-1;
859# else
860 return times(tmsp);
861# endif
862
863#else
864#endif
865}
866
867int sh_sysconf_clk_tck(void)
868{
869#ifdef _MSC_VER
870 return CLK_TCK;
871#else
872 return sysconf(_SC_CLK_TCK);
873#endif
874}
875
876/**
877 * Adds a child to the shell
878 *
879 * @returns 0 on success, on failure -1 and errno set to ENOMEM.
880 *
881 * @param psh The shell instance.
882 * @param pid The child pid.
883 * @param hChild Windows child handle.
884 */
885int sh_add_child(shinstance *psh, pid_t pid, void *hChild)
886{
887 /* get a free table entry. */
888 int i = psh->num_children++;
889 if (!(i % 32))
890 {
891 void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32));
892 if (!ptr)
893 {
894 psh->num_children--;
895 errno = ENOMEM;
896 return -1;
897 }
898 psh->children = ptr;
899 }
900
901 /* add it */
902 psh->children[i].pid = pid;
903#if K_OS == K_OS_WINDOWS
904 psh->children[i].hChild = hChild;
905#endif
906 (void)hChild;
907 return 0;
908}
909
910pid_t sh_fork(shinstance *psh)
911{
912 pid_t pid;
913 TRACE2((psh, "sh_fork\n"));
914
915#if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
916 pid = shfork_do(psh);
917
918#elif defined(SH_FORKED_MODE)
919# ifdef _MSC_VER
920 pid = -1;
921 errno = ENOSYS;
922# else
923 pid = fork();
924# endif
925
926#else
927
928#endif
929
930 /* child: update the pid */
931 if (!pid)
932# ifdef _MSC_VER
933 psh->pid = _getpid();
934# else
935 psh->pid = getpid();
936# endif
937
938 TRACE2((psh, "sh_fork -> %d [%d]\n", pid, errno));
939 (void)psh;
940 return pid;
941}
942
943/** waitpid() */
944pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags)
945{
946 pid_t pidret;
947#if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
948 DWORD dwRet;
949 HANDLE hChild = INVALID_HANDLE_VALUE;
950 int i;
951
952 *statusp = 0;
953 pidret = -1;
954 if (pid != -1)
955 {
956 /*
957 * A specific child, try look it up in the child process table
958 * and wait for it.
959 */
960 for (i = 0; i < psh->num_children; i++)
961 if (psh->children[i].pid == pid)
962 break;
963 if (i < psh->num_children)
964 {
965 dwRet = WaitForSingleObject(psh->children[i].hChild,
966 flags & WNOHANG ? 0 : INFINITE);
967 if (dwRet == WAIT_OBJECT_0)
968 hChild = psh->children[i].hChild;
969 else if (dwRet == WAIT_TIMEOUT)
970 {
971 i = -1; /* don't try close anything */
972 pidret = 0;
973 }
974 else
975 errno = ECHILD;
976 }
977 else
978 errno = ECHILD;
979 }
980 else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
981 {
982 HANDLE ahChildren[64];
983 for (i = 0; i < psh->num_children; i++)
984 ahChildren[i] = psh->children[i].hChild;
985 dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
986 FALSE,
987 flags & WNOHANG ? 0 : INFINITE);
988 i = dwRet - WAIT_OBJECT_0;
989 if ((unsigned)i < (unsigned)psh->num_children)
990 {
991 hChild = psh->children[i].hChild;
992 }
993 else if (dwRet == WAIT_TIMEOUT)
994 {
995 i = -1; /* don't try close anything */
996 pidret = 0;
997 }
998 else
999 {
1000 i = -1; /* don't try close anything */
1001 errno = EINVAL;
1002 }
1003 }
1004 else
1005 {
1006 fprintf(stderr, "panic! too many children!\n");
1007 i = -1;
1008 *(char *)1 = '\0'; /** @todo implement this! */
1009 }
1010
1011 /*
1012 * Close the handle, and if we succeeded collect the exit code first.
1013 */
1014 if ( i >= 0
1015 && i < psh->num_children)
1016 {
1017 if (hChild != INVALID_HANDLE_VALUE)
1018 {
1019 DWORD dwExitCode = 127;
1020 if (GetExitCodeProcess(hChild, &dwExitCode))
1021 {
1022 pidret = psh->children[i].pid;
1023 if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
1024 dwExitCode |= 16;
1025 *statusp = W_EXITCODE(dwExitCode, 0);
1026 }
1027 else
1028 errno = EINVAL;
1029 }
1030
1031 /* remove and close */
1032 hChild = psh->children[i].hChild;
1033 psh->num_children--;
1034 if (i < psh->num_children)
1035 psh->children[i] = psh->children[psh->num_children];
1036 i = CloseHandle(hChild); assert(i);
1037 }
1038
1039#elif defined(SH_FORKED_MODE)
1040 *statusp = 0;
1041# ifdef _MSC_VER
1042 pidret = -1;
1043 errno = ENOSYS;
1044# else
1045 pidret = waitpid(pid, statusp, flags);
1046# endif
1047
1048#else
1049#endif
1050
1051 TRACE2((psh, "waitpid(%d, %p, %#x) -> %d [%d] *statusp=%#x (rc=%d)\n", pid, statusp, flags,
1052 pidret, errno, *statusp, WEXITSTATUS(*statusp)));
1053 (void)psh;
1054 return pidret;
1055}
1056
1057SH_NORETURN_1 void sh__exit(shinstance *psh, int rc)
1058{
1059 TRACE2((psh, "sh__exit(%d)\n", rc));
1060 (void)psh;
1061
1062#if defined(SH_FORKED_MODE)
1063 _exit(rc);
1064
1065#else
1066#endif
1067}
1068
1069int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp)
1070{
1071 int rc;
1072
1073#ifdef DEBUG
1074 /* log it all */
1075 TRACE2((psh, "sh_execve(%p:{%s}, %p, %p}\n", exe, exe, argv, envp));
1076 for (rc = 0; argv[rc]; rc++)
1077 TRACE2((psh, " argv[%d]=%p:{%s}\n", rc, argv[rc], argv[rc]));
1078#endif
1079
1080 if (!envp)
1081 envp = (const char * const *)sh_environ(psh);
1082
1083#if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS
1084# ifdef _MSC_VER
1085 errno = 0;
1086 {
1087 intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
1088 if (rc2 != -1)
1089 {
1090 TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
1091 rc = (int)rc2;
1092 if (!rc && rc2)
1093 rc = 16;
1094 exit(rc);
1095 }
1096 }
1097 rc = -1;
1098
1099# else
1100 rc = shfile_exec_unix(&psh->fdtab);
1101 if (!rc)
1102 rc = execve(exe, (char **)argv, (char **)envp);
1103# endif
1104
1105#else
1106# if K_OS == K_OS_WINDOWS
1107 {
1108 /*
1109 * This ain't quite straight forward on Windows...
1110 */
1111 PROCESS_INFORMATION ProcInfo;
1112 STARTUPINFO StrtInfo;
1113 intptr_t hndls[3];
1114 char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
1115 char *cmdline;
1116 size_t cmdline_size;
1117 char *envblock;
1118 size_t env_size;
1119 char *p;
1120 int i;
1121
1122 /* Create the environment block. */
1123 if (!envp)
1124 envp = sh_environ(psh);
1125 env_size = 2;
1126 for (i = 0; envp[i]; i++)
1127 env_size += strlen(envp[i]) + 1;
1128 envblock = p = sh_malloc(psh, env_size);
1129 for (i = 0; envp[i]; i++)
1130 {
1131 size_t len = strlen(envp[i]) + 1;
1132 memcpy(p, envp[i], len);
1133 p += len;
1134 }
1135 *p = '\0';
1136
1137 /* Create the command line. */
1138 cmdline_size = 2;
1139 for (i = 0; argv[i]; i++)
1140 cmdline_size += strlen(argv[i]) + 3;
1141 cmdline = p = sh_malloc(psh, cmdline_size);
1142 for (i = 0; argv[i]; i++)
1143 {
1144 size_t len = strlen(argv[i]);
1145 int quoted = !!strpbrk(argv[i], " \t"); /** @todo Do this quoting business right. */
1146 if (i != 0)
1147 *(p++) = ' ';
1148 if (quoted)
1149 *(p++) = '"';
1150 memcpy(p, argv[i], len);
1151 p += len;
1152 if (quoted)
1153 *(p++) = '"';
1154 }
1155 p[0] = p[1] = '\0';
1156
1157 /* Init the info structure */
1158 memset(&StrtInfo, '\0', sizeof(StrtInfo));
1159 StrtInfo.cb = sizeof(StrtInfo);
1160
1161 /* File handles. */
1162 StrtInfo.dwFlags |= STARTF_USESTDHANDLES;
1163 StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
1164 StrtInfo.hStdInput = (HANDLE)hndls[0];
1165 StrtInfo.hStdOutput = (HANDLE)hndls[1];
1166 StrtInfo.hStdError = (HANDLE)hndls[2];
1167
1168 /* Get going... */
1169 if (CreateProcess(exe,
1170 cmdline,
1171 NULL, /* pProcessAttributes */
1172 NULL, /* pThreadAttributes */
1173 TRUE, /* bInheritHandles */
1174 0, /* dwCreationFlags */
1175 envblock,
1176 cwd,
1177 &StrtInfo,
1178 &ProcInfo))
1179 {
1180 DWORD dwErr;
1181 DWORD dwExitCode;
1182
1183 CloseHandle(ProcInfo.hThread);
1184 dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
1185 assert(dwErr == WAIT_OBJECT_0);
1186
1187 if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
1188 {
1189 CloseHandle(ProcInfo.hProcess);
1190 _exit(dwExitCode);
1191 }
1192 errno = EINVAL;
1193 }
1194 else
1195 {
1196 DWORD dwErr = GetLastError();
1197 switch (dwErr)
1198 {
1199 case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
1200 case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
1201 case ERROR_BAD_EXE_FORMAT: errno = ENOEXEC; break;
1202 case ERROR_INVALID_EXE_SIGNATURE: errno = ENOEXEC; break;
1203 default:
1204 errno = EINVAL;
1205 break;
1206 }
1207 TRACE2((psh, "sh_execve: dwErr=%d -> errno=%d\n", dwErr, errno));
1208 }
1209
1210 shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL);
1211 }
1212 rc = -1;
1213
1214# else
1215 errno = ENOSYS;
1216 rc = -1;
1217# endif
1218#endif
1219
1220 TRACE2((psh, "sh_execve -> %d [%d]\n", rc, errno));
1221 (void)psh;
1222 return (int)rc;
1223}
1224
1225uid_t sh_getuid(shinstance *psh)
1226{
1227#if defined(SH_FORKED_MODE)
1228# ifdef _MSC_VER
1229 uid_t uid = 0;
1230# else
1231 uid_t uid = getuid();
1232# endif
1233
1234#else
1235#endif
1236
1237 TRACE2((psh, "sh_getuid() -> %d [%d]\n", uid, errno));
1238 (void)psh;
1239 return uid;
1240}
1241
1242uid_t sh_geteuid(shinstance *psh)
1243{
1244#if defined(SH_FORKED_MODE)
1245# ifdef _MSC_VER
1246 uid_t euid = 0;
1247# else
1248 uid_t euid = geteuid();
1249# endif
1250
1251#else
1252#endif
1253
1254 TRACE2((psh, "sh_geteuid() -> %d [%d]\n", euid, errno));
1255 (void)psh;
1256 return euid;
1257}
1258
1259gid_t sh_getgid(shinstance *psh)
1260{
1261#if defined(SH_FORKED_MODE)
1262# ifdef _MSC_VER
1263 gid_t gid = 0;
1264# else
1265 gid_t gid = getgid();
1266# endif
1267
1268#else
1269#endif
1270
1271 TRACE2((psh, "sh_getgid() -> %d [%d]\n", gid, errno));
1272 (void)psh;
1273 return gid;
1274}
1275
1276gid_t sh_getegid(shinstance *psh)
1277{
1278#if defined(SH_FORKED_MODE)
1279# ifdef _MSC_VER
1280 gid_t egid = 0;
1281# else
1282 gid_t egid = getegid();
1283# endif
1284
1285#else
1286#endif
1287
1288 TRACE2((psh, "sh_getegid() -> %d [%d]\n", egid, errno));
1289 (void)psh;
1290 return egid;
1291}
1292
1293pid_t sh_getpid(shinstance *psh)
1294{
1295 pid_t pid;
1296
1297#if defined(SH_FORKED_MODE)
1298# ifdef _MSC_VER
1299 pid = _getpid();
1300# else
1301 pid = getpid();
1302# endif
1303#else
1304#endif
1305
1306 (void)psh;
1307 return pid;
1308}
1309
1310pid_t sh_getpgrp(shinstance *psh)
1311{
1312#if defined(SH_FORKED_MODE)
1313# ifdef _MSC_VER
1314 pid_t pgrp = _getpid();
1315# else
1316 pid_t pgrp = getpgrp();
1317# endif
1318
1319#else
1320#endif
1321
1322 TRACE2((psh, "sh_getpgrp() -> %d [%d]\n", pgrp, errno));
1323 (void)psh;
1324 return pgrp;
1325}
1326
1327pid_t sh_getpgid(shinstance *psh, pid_t pid)
1328{
1329#if defined(SH_FORKED_MODE)
1330# ifdef _MSC_VER
1331 pid_t pgid = pid;
1332# else
1333 pid_t pgid = getpgid(pid);
1334# endif
1335
1336#else
1337#endif
1338
1339 TRACE2((psh, "sh_getpgid(%d) -> %d [%d]\n", pid, pgid, errno));
1340 (void)psh;
1341 return pgid;
1342}
1343
1344int sh_setpgid(shinstance *psh, pid_t pid, pid_t pgid)
1345{
1346#if defined(SH_FORKED_MODE)
1347# ifdef _MSC_VER
1348 int rc = -1;
1349 errno = ENOSYS;
1350# else
1351 int rc = setpgid(pid, pgid);
1352# endif
1353
1354#else
1355#endif
1356
1357 TRACE2((psh, "sh_setpgid(%d, %d) -> %d [%d]\n", pid, pgid, rc, errno));
1358 (void)psh;
1359 return rc;
1360}
1361
1362pid_t sh_tcgetpgrp(shinstance *psh, int fd)
1363{
1364 pid_t pgrp;
1365
1366#if defined(SH_FORKED_MODE)
1367# ifdef _MSC_VER
1368 pgrp = -1;
1369 errno = ENOSYS;
1370# else
1371 pgrp = tcgetpgrp(fd);
1372# endif
1373
1374#else
1375#endif
1376
1377 TRACE2((psh, "sh_tcgetpgrp(%d) -> %d [%d]\n", fd, pgrp, errno));
1378 (void)psh;
1379 return pgrp;
1380}
1381
1382int sh_tcsetpgrp(shinstance *psh, int fd, pid_t pgrp)
1383{
1384 int rc;
1385 TRACE2((psh, "sh_tcsetpgrp(%d, %d)\n", fd, pgrp));
1386
1387#if defined(SH_FORKED_MODE)
1388# ifdef _MSC_VER
1389 rc = -1;
1390 errno = ENOSYS;
1391# else
1392 rc = tcsetpgrp(fd, pgrp);
1393# endif
1394
1395#else
1396#endif
1397
1398 TRACE2((psh, "sh_tcsetpgrp(%d, %d) -> %d [%d]\n", fd, pgrp, rc, errno));
1399 (void)psh;
1400 return rc;
1401}
1402
1403int sh_getrlimit(shinstance *psh, int resid, shrlimit *limp)
1404{
1405#if defined(SH_FORKED_MODE)
1406# ifdef _MSC_VER
1407 int rc = -1;
1408 errno = ENOSYS;
1409# else
1410 int rc = getrlimit(resid, limp);
1411# endif
1412
1413#else
1414 /* returned the stored limit */
1415#endif
1416
1417 TRACE2((psh, "sh_getrlimit(%d, %p) -> %d [%d] {%ld,%ld}\n",
1418 resid, limp, rc, errno, (long)limp->rlim_cur, (long)limp->rlim_max));
1419 (void)psh;
1420 return rc;
1421}
1422
1423int sh_setrlimit(shinstance *psh, int resid, const shrlimit *limp)
1424{
1425#if defined(SH_FORKED_MODE)
1426# ifdef _MSC_VER
1427 int rc = -1;
1428 errno = ENOSYS;
1429# else
1430 int rc = setrlimit(resid, limp);
1431# endif
1432
1433#else
1434 /* if max(shell) < limp; then setrlimit; fi
1435 if success; then store limit for later retrival and maxing. */
1436
1437#endif
1438
1439 TRACE2((psh, "sh_setrlimit(%d, %p:{%ld,%ld}) -> %d [%d]\n",
1440 resid, limp, (long)limp->rlim_cur, (long)limp->rlim_max, rc, errno));
1441 (void)psh;
1442 return rc;
1443}
1444
1445
1446/* Wrapper for strerror that makes sure it doesn't return NULL and causes the
1447 caller or fprintf routines to crash. */
1448const char *sh_strerror(shinstance *psh, int error)
1449{
1450 char *err = strerror(error);
1451 if (!err)
1452 return "strerror return NULL!";
1453 (void)psh;
1454 return err;
1455}
1456
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