source: trunk/src/kash/shinstance.c@ 2293

Last change on this file since 2293 was 2293, checked in by bird, 16 years ago

kash: forking on windows (almost there).

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