VirtualBox

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

Last change on this file since 2423 was 2423, checked in by bird, 14 years ago

kash: made the SHFILE_IN_USE mode work on unix (because openbsd has a very hackish pthread library).

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