VirtualBox

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

Last change on this file since 2392 was 2385, checked in by bird, 15 years ago

kash: drop debug fprintf

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 32.9 KB
Line 
1/* $Id: shinstance.c 2385 2010-01-16 01:01:05Z bird $ */
2/** @file
3 * The shell instance methods.
4 */
5
6/*
7 * Copyright (c) 2007-2009 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_it(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_it(psh);
901 if (pid == 0)
902 shthread_set_shell(psh);
903
904#elif defined(SH_FORKED_MODE)
905# ifdef _MSC_VER
906 pid = -1;
907 errno = ENOSYS;
908# else
909 pid = fork();
910# endif
911
912#else
913
914#endif
915
916 /* child: update the pid */
917 if (!pid)
918# ifdef _MSC_VER
919 psh->pid = _getpid();
920# else
921 psh->pid = getpid();
922# endif
923
924 TRACE2((psh, "sh_fork -> %d [%d]\n", pid, errno));
925 (void)psh;
926 return pid;
927}
928
929/** waitpid() */
930pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags)
931{
932 pid_t pidret;
933#if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
934 DWORD dwRet;
935 HANDLE hChild = INVALID_HANDLE_VALUE;
936 int i;
937
938 *statusp = 0;
939 pidret = -1;
940 if (pid != -1)
941 {
942 /*
943 * A specific child, try look it up in the child process table
944 * and wait for it.
945 */
946 for (i = 0; i < psh->num_children; i++)
947 if (psh->children[i].pid == pid)
948 break;
949 if (i < psh->num_children)
950 {
951 dwRet = WaitForSingleObject(psh->children[i].hChild,
952 flags & WNOHANG ? 0 : INFINITE);
953 if (dwRet == WAIT_OBJECT_0)
954 hChild = psh->children[i].hChild;
955 else if (dwRet == WAIT_TIMEOUT)
956 {
957 i = -1; /* don't try close anything */
958 pidret = 0;
959 }
960 else
961 errno = ECHILD;
962 }
963 else
964 errno = ECHILD;
965 }
966 else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
967 {
968 HANDLE ahChildren[64];
969 for (i = 0; i < psh->num_children; i++)
970 ahChildren[i] = psh->children[i].hChild;
971 dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
972 FALSE,
973 flags & WNOHANG ? 0 : INFINITE);
974 i = dwRet - WAIT_OBJECT_0;
975 if ((unsigned)i < (unsigned)psh->num_children)
976 {
977 hChild = psh->children[i].hChild;
978 }
979 else if (dwRet == WAIT_TIMEOUT)
980 {
981 i = -1; /* don't try close anything */
982 pidret = 0;
983 }
984 else
985 {
986 i = -1; /* don't try close anything */
987 errno = EINVAL;
988 }
989 }
990 else
991 {
992 fprintf(stderr, "panic! too many children!\n");
993 i = -1;
994 *(char *)1 = '\0'; /** @todo implement this! */
995 }
996
997 /*
998 * Close the handle, and if we succeeded collect the exit code first.
999 */
1000 if ( i >= 0
1001 && i < psh->num_children)
1002 {
1003 if (hChild != INVALID_HANDLE_VALUE)
1004 {
1005 DWORD dwExitCode = 127;
1006 if (GetExitCodeProcess(hChild, &dwExitCode))
1007 {
1008 pidret = psh->children[i].pid;
1009 if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
1010 dwExitCode |= 16;
1011 *statusp = W_EXITCODE(dwExitCode, 0);
1012 }
1013 else
1014 errno = EINVAL;
1015 }
1016
1017 /* remove and close */
1018 hChild = psh->children[i].hChild;
1019 psh->num_children--;
1020 if (i < psh->num_children)
1021 psh->children[i] = psh->children[psh->num_children];
1022 i = CloseHandle(hChild); assert(i);
1023 }
1024
1025#elif defined(SH_FORKED_MODE)
1026 *statusp = 0;
1027# ifdef _MSC_VER
1028 pidret = -1;
1029 errno = ENOSYS;
1030# else
1031 pidret = waitpid(pid, statusp, flags);
1032# endif
1033
1034#else
1035#endif
1036
1037 TRACE2((psh, "waitpid(%d, %p, %#x) -> %d [%d] *statusp=%#x (rc=%d)\n", pid, statusp, flags,
1038 pidret, errno, *statusp, WEXITSTATUS(*statusp)));
1039 (void)psh;
1040 return pidret;
1041}
1042
1043SH_NORETURN_1 void sh__exit(shinstance *psh, int rc)
1044{
1045 TRACE2((psh, "sh__exit(%d)\n", rc));
1046 (void)psh;
1047
1048#if defined(SH_FORKED_MODE)
1049 _exit(rc);
1050
1051#else
1052#endif
1053}
1054
1055int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp)
1056{
1057 int rc;
1058
1059#ifdef DEBUG
1060 /* log it all */
1061 TRACE2((psh, "sh_execve(%p:{%s}, %p, %p}\n", exe, exe, argv, envp));
1062 for (rc = 0; argv[rc]; rc++)
1063 TRACE2((psh, " argv[%d]=%p:{%s}\n", rc, argv[rc], argv[rc]));
1064#endif
1065
1066 if (!envp)
1067 envp = (const char * const *)sh_environ(psh);
1068
1069#if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS
1070# ifdef _MSC_VER
1071 errno = 0;
1072 {
1073 intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
1074 if (rc2 != -1)
1075 {
1076 TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
1077 rc = (int)rc2;
1078 if (!rc && rc2)
1079 rc = 16;
1080 exit(rc);
1081 }
1082 }
1083 rc = -1;
1084# else
1085 rc = execve(exe, (char **)argv, (char **)envp);
1086# endif
1087
1088#else
1089# if K_OS == K_OS_WINDOWS
1090 {
1091 /*
1092 * This ain't quite straight forward on Windows...
1093 */
1094 PROCESS_INFORMATION ProcInfo;
1095 STARTUPINFO StrtInfo;
1096 intptr_t hndls[3];
1097 char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
1098 char *cmdline;
1099 size_t cmdline_size;
1100 char *envblock;
1101 size_t env_size;
1102 char *p;
1103 int i;
1104
1105 /* Create the environment block. */
1106 if (!envp)
1107 envp = sh_environ(psh);
1108 env_size = 2;
1109 for (i = 0; envp[i]; i++)
1110 env_size += strlen(envp[i]) + 1;
1111 envblock = p = sh_malloc(psh, env_size);
1112 for (i = 0; envp[i]; i++)
1113 {
1114 size_t len = strlen(envp[i]) + 1;
1115 memcpy(p, envp[i], len);
1116 p += len;
1117 }
1118 *p = '\0';
1119
1120 /* Create the command line. */
1121 cmdline_size = 2;
1122 for (i = 0; argv[i]; i++)
1123 cmdline_size += strlen(argv[i]) + 3;
1124 cmdline = p = sh_malloc(psh, cmdline_size);
1125 for (i = 0; argv[i]; i++)
1126 {
1127 size_t len = strlen(argv[i]);
1128 int quoted = !!strpbrk(argv[i], " \t"); /** @todo Do this quoting business right. */
1129 if (i != 0)
1130 *(p++) = ' ';
1131 if (quoted)
1132 *(p++) = '"';
1133 memcpy(p, argv[i], len);
1134 p += len;
1135 if (quoted)
1136 *(p++) = '"';
1137 }
1138 p[0] = p[1] = '\0';
1139
1140 /* Init the info structure */
1141 memset(&StrtInfo, '\0', sizeof(StrtInfo));
1142 StrtInfo.cb = sizeof(StrtInfo);
1143
1144 /* File handles. */
1145 StrtInfo.dwFlags |= STARTF_USESTDHANDLES;
1146 StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
1147 StrtInfo.hStdInput = (HANDLE)hndls[0];
1148 StrtInfo.hStdOutput = (HANDLE)hndls[1];
1149 StrtInfo.hStdError = (HANDLE)hndls[2];
1150
1151 /* Get going... */
1152 if (CreateProcess(exe,
1153 cmdline,
1154 NULL, /* pProcessAttributes */
1155 NULL, /* pThreadAttributes */
1156 TRUE, /* bInheritHandles */
1157 0, /* dwCreationFlags */
1158 envblock,
1159 cwd,
1160 &StrtInfo,
1161 &ProcInfo))
1162 {
1163 DWORD dwErr;
1164 DWORD dwExitCode;
1165
1166 CloseHandle(ProcInfo.hThread);
1167 dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
1168 assert(dwErr == WAIT_OBJECT_0);
1169
1170 if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
1171 {
1172 CloseHandle(ProcInfo.hProcess);
1173 _exit(dwExitCode);
1174 }
1175 errno = EINVAL;
1176 }
1177
1178 shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL);
1179 }
1180 rc = -1;
1181
1182# else
1183 errno = ENOSYS;
1184 rc = -1;
1185# endif
1186#endif
1187
1188 TRACE2((psh, "sh_execve -> %d [%d]\n", rc, errno));
1189 (void)psh;
1190 return (int)rc;
1191}
1192
1193uid_t sh_getuid(shinstance *psh)
1194{
1195#if defined(SH_FORKED_MODE)
1196# ifdef _MSC_VER
1197 uid_t uid = 0;
1198# else
1199 uid_t uid = getuid();
1200# endif
1201
1202#else
1203#endif
1204
1205 TRACE2((psh, "sh_getuid() -> %d [%d]\n", uid, errno));
1206 (void)psh;
1207 return uid;
1208}
1209
1210uid_t sh_geteuid(shinstance *psh)
1211{
1212#if defined(SH_FORKED_MODE)
1213# ifdef _MSC_VER
1214 uid_t euid = 0;
1215# else
1216 uid_t euid = geteuid();
1217# endif
1218
1219#else
1220#endif
1221
1222 TRACE2((psh, "sh_geteuid() -> %d [%d]\n", euid, errno));
1223 (void)psh;
1224 return euid;
1225}
1226
1227gid_t sh_getgid(shinstance *psh)
1228{
1229#if defined(SH_FORKED_MODE)
1230# ifdef _MSC_VER
1231 gid_t gid = 0;
1232# else
1233 gid_t gid = getgid();
1234# endif
1235
1236#else
1237#endif
1238
1239 TRACE2((psh, "sh_getgid() -> %d [%d]\n", gid, errno));
1240 (void)psh;
1241 return gid;
1242}
1243
1244gid_t sh_getegid(shinstance *psh)
1245{
1246#if defined(SH_FORKED_MODE)
1247# ifdef _MSC_VER
1248 gid_t egid = 0;
1249# else
1250 gid_t egid = getegid();
1251# endif
1252
1253#else
1254#endif
1255
1256 TRACE2((psh, "sh_getegid() -> %d [%d]\n", egid, errno));
1257 (void)psh;
1258 return egid;
1259}
1260
1261pid_t sh_getpid(shinstance *psh)
1262{
1263 pid_t pid;
1264
1265#if defined(SH_FORKED_MODE)
1266# ifdef _MSC_VER
1267 pid = _getpid();
1268# else
1269 pid = getpid();
1270# endif
1271#else
1272#endif
1273
1274 (void)psh;
1275 return pid;
1276}
1277
1278pid_t sh_getpgrp(shinstance *psh)
1279{
1280#if defined(SH_FORKED_MODE)
1281# ifdef _MSC_VER
1282 pid_t pgrp = _getpid();
1283# else
1284 pid_t pgrp = getpgrp();
1285# endif
1286
1287#else
1288#endif
1289
1290 TRACE2((psh, "sh_getpgrp() -> %d [%d]\n", pgrp, errno));
1291 (void)psh;
1292 return pgrp;
1293}
1294
1295pid_t sh_getpgid(shinstance *psh, pid_t pid)
1296{
1297#if defined(SH_FORKED_MODE)
1298# ifdef _MSC_VER
1299 pid_t pgid = pid;
1300# else
1301 pid_t pgid = getpgid(pid);
1302# endif
1303
1304#else
1305#endif
1306
1307 TRACE2((psh, "sh_getpgid(%d) -> %d [%d]\n", pid, pgid, errno));
1308 (void)psh;
1309 return pgid;
1310}
1311
1312int sh_setpgid(shinstance *psh, pid_t pid, pid_t pgid)
1313{
1314#if defined(SH_FORKED_MODE)
1315# ifdef _MSC_VER
1316 int rc = -1;
1317 errno = ENOSYS;
1318# else
1319 int rc = setpgid(pid, pgid);
1320# endif
1321
1322#else
1323#endif
1324
1325 TRACE2((psh, "sh_setpgid(%d, %d) -> %d [%d]\n", pid, pgid, rc, errno));
1326 (void)psh;
1327 return rc;
1328}
1329
1330pid_t sh_tcgetpgrp(shinstance *psh, int fd)
1331{
1332 pid_t pgrp;
1333
1334#if defined(SH_FORKED_MODE)
1335# ifdef _MSC_VER
1336 pgrp = -1;
1337 errno = ENOSYS;
1338# else
1339 pgrp = tcgetpgrp(fd);
1340# endif
1341
1342#else
1343#endif
1344
1345 TRACE2((psh, "sh_tcgetpgrp(%d) -> %d [%d]\n", fd, pgrp, errno));
1346 (void)psh;
1347 return pgrp;
1348}
1349
1350int sh_tcsetpgrp(shinstance *psh, int fd, pid_t pgrp)
1351{
1352 int rc;
1353 TRACE2((psh, "sh_tcsetpgrp(%d, %d)\n", fd, pgrp));
1354
1355#if defined(SH_FORKED_MODE)
1356# ifdef _MSC_VER
1357 rc = -1;
1358 errno = ENOSYS;
1359# else
1360 rc = tcsetpgrp(fd, pgrp);
1361# endif
1362
1363#else
1364#endif
1365
1366 TRACE2((psh, "sh_tcsetpgrp(%d, %d) -> %d [%d]\n", fd, pgrp, rc, errno));
1367 (void)psh;
1368 return rc;
1369}
1370
1371int sh_getrlimit(shinstance *psh, int resid, shrlimit *limp)
1372{
1373#if defined(SH_FORKED_MODE)
1374# ifdef _MSC_VER
1375 int rc = -1;
1376 errno = ENOSYS;
1377# else
1378 int rc = getrlimit(resid, limp);
1379# endif
1380
1381#else
1382 /* returned the stored limit */
1383#endif
1384
1385 TRACE2((psh, "sh_getrlimit(%d, %p) -> %d [%d] {%ld,%ld}\n",
1386 resid, limp, rc, errno, (long)limp->rlim_cur, (long)limp->rlim_max));
1387 (void)psh;
1388 return rc;
1389}
1390
1391int sh_setrlimit(shinstance *psh, int resid, const shrlimit *limp)
1392{
1393#if defined(SH_FORKED_MODE)
1394# ifdef _MSC_VER
1395 int rc = -1;
1396 errno = ENOSYS;
1397# else
1398 int rc = setrlimit(resid, limp);
1399# endif
1400
1401#else
1402 /* if max(shell) < limp; then setrlimit; fi
1403 if success; then store limit for later retrival and maxing. */
1404
1405#endif
1406
1407 TRACE2((psh, "sh_setrlimit(%d, %p:{%ld,%ld}) -> %d [%d]\n",
1408 resid, limp, (long)limp->rlim_cur, (long)limp->rlim_max, rc, errno));
1409 (void)psh;
1410 return rc;
1411}
1412
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