VirtualBox

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

Last change on this file since 2629 was 2593, checked in by bird, 13 years ago

kash: win.x86 build fix

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

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