1 /* $Id: shinstance.c 2809 2016-02-05 09:13:42Z bird $ */
2 /** @file
3  * The shell instance methods.
4  */
5 
6 /*
7  * Copyright (c) 2007-2010 knut st. osmundsen <bird-kBuild-spamx@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 #include "shinstance.h"
41 
42 #if K_OS == K_OS_WINDOWS
43 # include <Windows.h>
44 extern pid_t shfork_do(shinstance *psh); /* shforkA-win.asm */
45 #endif
46 #if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG)
47 extern 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). */
55 static shmtx        g_sh_mtx;
56 /** The root shell instance. */
57 static shinstance  *g_sh_root;
58 /** The first shell instance. */
59 static shinstance  *g_sh_head;
60 /** The last shell instance. */
61 static shinstance  *g_sh_tail;
62 /** The number of shells. */
63 static int volatile g_num_shells;
64 /** Per signal state for determining a common denominator.
65  * @remarks defaults and unmasked actions aren't counted. */
66 struct 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 
shmtx_init(shmtx * pmtx)91 int shmtx_init(shmtx *pmtx)
92 {
93     pmtx->b[0] = 0;
94     return 0;
95 }
96 
shmtx_delete(shmtx * pmtx)97 void shmtx_delete(shmtx *pmtx)
98 {
99     pmtx->b[0] = 0;
100 }
101 
shmtx_enter(shmtx * pmtx,shmtxtmp * ptmp)102 void shmtx_enter(shmtx *pmtx, shmtxtmp *ptmp)
103 {
104     pmtx->b[0] = 0;
105     ptmp->i = 0;
106 }
107 
shmtx_leave(shmtx * pmtx,shmtxtmp * ptmp)108 void 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  */
sh_int_link(shinstance * psh)119 static 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  */
146 static 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  */
sh_destroy(shinstance * psh)177 static 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 environ 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  */
sh_clone_string_vector(shinstance * psh,char *** dstp,char ** src)191 static 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  */
sh_create_root_shell(shinstance * inherit,int argc,char ** argv,char ** envp)235 shinstance *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() */
sh_getenv(shinstance * psh,const char * var)320 char *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 
sh_environ(shinstance * psh)341 char **sh_environ(shinstance *psh)
342 {
343     return psh->shenviron;
344 }
345 
sh_gethomedir(shinstance * psh,const char * user)346 const 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  */
sh_int_lazy_init_sigaction(shinstance * psh,int signo)369 static 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  */
sh_sig_do_default(shinstance * psh,int signo)441 static 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  */
sh_sig_do_signal(shinstance * psh,shinstance * pshDst,int signo,int locked)454 static 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  */
sh_sig_common_handler(int signo)480 static 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 
sh_sigaction(shinstance * psh,int signo,const struct shsigaction * newp,struct shsigaction * oldp)515 int sh_sigaction(shinstance *psh, int signo, const struct shsigaction *newp, struct shsigaction *oldp)
516 {
517     if (newp)
518         TRACE2((psh, "sh_sigaction: signo=%d:%s newp=%p:{.sh_handler=%p, .sh_flags=%#x} oldp=%p\n",
519                 signo, sys_signame[signo], newp, newp->sh_handler, newp->sh_flags, oldp));
520     else
521         TRACE2((psh, "sh_sigaction: signo=%d:%s newp=NULL oldp=%p\n", signo, sys_signame[signo], oldp));
522 
523     /*
524      * Input validation.
525      */
526     if (signo >= NSIG || signo <= 0)
527     {
528         errno = EINVAL;
529         return -1;
530     }
531 
532     /*
533      * Make sure our data is correct.
534      */
535     sh_int_lazy_init_sigaction(psh, signo);
536 
537     /*
538      * Get the old one if requested.
539      */
540     if (oldp)
541         *oldp = psh->sigactions[signo];
542 
543     /*
544      * Set the new one if it has changed.
545      *
546      * This will be attempted coordinated with the other signal handlers so
547      * that we can arrive at a common denominator.
548      */
549     if (    newp
550         &&  memcmp(&psh->sigactions[signo], newp, sizeof(*newp)))
551     {
552         shmtxtmp tmp;
553         shmtx_enter(&g_sh_mtx, &tmp);
554 
555         /* Undo the accounting for the current entry. */
556         if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
557             g_sig_state[signo].num_ignore--;
558         else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
559             g_sig_state[signo].num_specific--;
560         if (psh->sigactions[signo].sh_flags & SA_RESTART)
561             g_sig_state[signo].num_restart--;
562 
563         /* Set the new entry. */
564         psh->sigactions[signo] = *newp;
565 
566         /* Add the bits for the new action entry. */
567         if (psh->sigactions[signo].sh_handler == SH_SIG_IGN)
568             g_sig_state[signo].num_ignore++;
569         else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL)
570             g_sig_state[signo].num_specific++;
571         if (psh->sigactions[signo].sh_flags & SA_RESTART)
572             g_sig_state[signo].num_restart++;
573 
574         /*
575          * Calc new common action.
576          *
577          * This is quit a bit ASSUMPTIVE about the limited use. We will not
578          * bother synching the mask, and we pretend to care about SA_RESTART.
579          * The only thing we really actually care about is the sh_handler.
580          *
581          * On second though, it's possible we should just tie this to the root
582          * shell since it only really applies to external signal ...
583          */
584         if (    g_sig_state[signo].num_specific
585             ||  g_sig_state[signo].num_ignore != g_num_shells)
586             g_sig_state[signo].sa.sa_handler = sh_sig_common_handler;
587         else if (g_sig_state[signo].num_ignore)
588             g_sig_state[signo].sa.sa_handler = SIG_IGN;
589         else
590             g_sig_state[signo].sa.sa_handler = SIG_DFL;
591         g_sig_state[signo].sa.sa_flags = psh->sigactions[signo].sh_flags & SA_RESTART;
592 
593 #if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG)
594         init_sys_signame();
595 #endif
596         TRACE2((psh, "sh_sigaction: setting signo=%d:%s to {.sa_handler=%p, .sa_flags=%#x}\n",
597                 signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags));
598 #ifdef _MSC_VER
599         if (signal(signo, g_sig_state[signo].sa.sa_handler) == SIG_ERR)
600         {
601             TRACE2((psh, "sh_sigaction: SIG_ERR, errno=%d signo=%d\n", errno, signo));
602             if (   signo != SIGHUP   /* whatever */
603                 && signo != SIGQUIT
604                 && signo != SIGPIPE
605                 && signo != SIGTTIN
606                 && signo != SIGTSTP
607                 && signo != SIGTTOU
608                 && signo != SIGCONT)
609                 assert(0);
610         }
611 #else
612         if (sigaction(signo, &g_sig_state[signo].sa, NULL))
613             assert(0);
614 #endif
615 
616         shmtx_leave(&g_sh_mtx, &tmp);
617     }
618 
619     return 0;
620 }
621 
sh_signal(shinstance * psh,int signo,shsig_t handler)622 shsig_t sh_signal(shinstance *psh, int signo, shsig_t handler)
623 {
624     shsigaction_t sa;
625     shsig_t ret;
626 
627     /*
628      * Implementation using sh_sigaction.
629      */
630     if (sh_sigaction(psh, signo, NULL, &sa))
631         return SH_SIG_ERR;
632 
633     ret = sa.sh_handler;
634     sa.sh_flags &= SA_RESTART;
635     sa.sh_handler = handler;
636     sh_sigemptyset(&sa.sh_mask);
637     sh_sigaddset(&sa.sh_mask, signo); /* ?? */
638     if (sh_sigaction(psh, signo, &sa, NULL))
639         return SH_SIG_ERR;
640 
641     return ret;
642 }
643 
sh_siginterrupt(shinstance * psh,int signo,int interrupt)644 int sh_siginterrupt(shinstance *psh, int signo, int interrupt)
645 {
646     shsigaction_t sa;
647     int oldflags = 0;
648 
649     /*
650      * Implementation using sh_sigaction.
651      */
652     if (sh_sigaction(psh, signo, NULL, &sa))
653         return -1;
654     oldflags = sa.sh_flags;
655     if (interrupt)
656         sa.sh_flags &= ~SA_RESTART;
657     else
658         sa.sh_flags |= ~SA_RESTART;
659     if (!((oldflags ^ sa.sh_flags) & SA_RESTART))
660         return 0; /* unchanged. */
661 
662     return sh_sigaction(psh, signo, &sa, NULL);
663 }
664 
sh_sigemptyset(shsigset_t * setp)665 void sh_sigemptyset(shsigset_t *setp)
666 {
667     memset(setp, 0, sizeof(*setp));
668 }
669 
sh_sigfillset(shsigset_t * setp)670 void sh_sigfillset(shsigset_t *setp)
671 {
672     memset(setp, 0xff, sizeof(*setp));
673 }
674 
sh_sigaddset(shsigset_t * setp,int signo)675 void sh_sigaddset(shsigset_t *setp, int signo)
676 {
677 #ifdef _MSC_VER
678     *setp |= 1U << signo;
679 #else
680     sigaddset(setp, signo);
681 #endif
682 }
683 
sh_sigdelset(shsigset_t * setp,int signo)684 void sh_sigdelset(shsigset_t *setp, int signo)
685 {
686 #ifdef _MSC_VER
687     *setp &= ~(1U << signo);
688 #else
689     sigdelset(setp, signo);
690 #endif
691 }
692 
sh_sigismember(shsigset_t const * setp,int signo)693 int sh_sigismember(shsigset_t const *setp, int signo)
694 {
695 #ifdef _MSC_VER
696     return !!(*setp & (1U << signo));
697 #else
698     return !!sigismember(setp, signo);
699 #endif
700 }
701 
sh_sigprocmask(shinstance * psh,int operation,shsigset_t const * newp,shsigset_t * oldp)702 int sh_sigprocmask(shinstance *psh, int operation, shsigset_t const *newp, shsigset_t *oldp)
703 {
704     int rc;
705 
706     if (    operation != SIG_BLOCK
707         &&  operation != SIG_UNBLOCK
708         &&  operation != SIG_SETMASK)
709     {
710         errno = EINVAL;
711         return -1;
712     }
713 
714 #if defined(SH_FORKED_MODE) && !defined(_MSC_VER)
715     rc = sigprocmask(operation, newp, oldp);
716     if (!rc && newp)
717         psh->sigmask = *newp;
718 
719 #else
720     if (oldp)
721         *oldp = psh->sigmask;
722     if (newp)
723     {
724         /* calc the new mask */
725         shsigset_t mask = psh->sigmask;
726         switch (operation)
727         {
728             case SIG_BLOCK:
729                 for (rc = 0; rc < NSIG; rc++)
730                     if (sh_sigismember(newp, rc))
731                         sh_sigaddset(&mask, rc);
732                 break;
733             case SIG_UNBLOCK:
734                 for (rc = 0; rc < NSIG; rc++)
735                     if (sh_sigismember(newp, rc))
736                         sh_sigdelset(&mask, rc);
737                 break;
738             case SIG_SETMASK:
739                 mask = *newp;
740                 break;
741         }
742 
743 # if defined(_MSC_VER)
744         rc = 0;
745 # else
746         rc = sigprocmask(operation, &mask, NULL);
747         if (!rc)
748 # endif
749             psh->sigmask = mask;
750     }
751 
752 #endif
753     return rc;
754 }
755 
sh_abort(shinstance * psh)756 SH_NORETURN_1 void sh_abort(shinstance *psh)
757 {
758     shsigset_t set;
759     TRACE2((psh, "sh_abort\n"));
760 
761     /* block other async signals */
762     sh_sigfillset(&set);
763     sh_sigdelset(&set, SIGABRT);
764     sh_sigprocmask(psh, SIG_SETMASK, &set, NULL);
765 
766     sh_sig_do_signal(psh, psh, SIGABRT, 0 /* no lock */);
767 
768     /** @todo die in a nicer manner. */
769     *(char *)1 = 3;
770 
771     TRACE2((psh, "sh_abort returns!\n"));
772     (void)psh;
773     abort();
774 }
775 
sh_raise_sigint(shinstance * psh)776 void sh_raise_sigint(shinstance *psh)
777 {
778     TRACE2((psh, "sh_raise(SIGINT)\n"));
779 
780     sh_sig_do_signal(psh, psh, SIGINT, 0 /* no lock */);
781 
782     TRACE2((psh, "sh_raise(SIGINT) returns\n"));
783 }
784 
sh_kill(shinstance * psh,pid_t pid,int signo)785 int sh_kill(shinstance *psh, pid_t pid, int signo)
786 {
787     shinstance *pshDst;
788     shmtxtmp tmp;
789     int rc;
790 
791     /*
792      * Self or any of the subshells?
793      */
794     shmtx_enter(&g_sh_mtx, &tmp);
795 
796     pshDst = g_sh_tail;
797     while (pshDst != NULL)
798     {
799         if (pshDst->pid == pid)
800         {
801             TRACE2((psh, "sh_kill(%d, %d): pshDst=%p\n", pid, signo, pshDst));
802             sh_sig_do_signal(psh, pshDst, signo, 1 /* locked */);
803 
804             shmtx_leave(&g_sh_mtx, &tmp);
805             return 0;
806         }
807         pshDst = pshDst->prev;
808     }
809 
810     shmtx_leave(&g_sh_mtx, &tmp);
811 
812     /*
813      * Some other process, call kill where possible
814      */
815 #if defined(SH_FORKED_MODE)
816 # ifdef _MSC_VER
817     errno = ENOSYS;
818     rc = -1;
819 # else
820 /*    fprintf(stderr, "kill(%d, %d)\n", pid, signo);*/
821     rc = kill(pid, signo);
822 # endif
823 
824 #else
825 #endif
826 
827     TRACE2((psh, "sh_kill(%d, %d) -> %d [%d]\n", pid, signo, rc, errno));
828     return rc;
829 }
830 
sh_killpg(shinstance * psh,pid_t pgid,int signo)831 int sh_killpg(shinstance *psh, pid_t pgid, int signo)
832 {
833     int rc;
834 
835 #if defined(SH_FORKED_MODE)
836 # ifdef _MSC_VER
837     errno = ENOSYS;
838     rc = -1;
839 # else
840     //fprintf(stderr, "killpg(%d, %d)\n", pgid, signo);
841     rc = killpg(pgid, signo);
842 # endif
843 
844 #else
845 #endif
846 
847     TRACE2((psh, "sh_killpg(%d, %d) -> %d [%d]\n", pgid, signo, rc, errno));
848     (void)psh;
849     return rc;
850 }
851 
sh_times(shinstance * psh,shtms * tmsp)852 clock_t sh_times(shinstance *psh, shtms *tmsp)
853 {
854 #if defined(SH_FORKED_MODE)
855     (void)psh;
856 # ifdef _MSC_VER
857     errno = ENOSYS;
858     return (clock_t)-1;
859 # else
860     return times(tmsp);
861 # endif
862 
863 #else
864 #endif
865 }
866 
sh_sysconf_clk_tck(void)867 int sh_sysconf_clk_tck(void)
868 {
869 #ifdef _MSC_VER
870     return CLK_TCK;
871 #else
872     return sysconf(_SC_CLK_TCK);
873 #endif
874 }
875 
876 /**
877  * Adds a child to the shell
878  *
879  * @returns 0 on success, on failure -1 and errno set to ENOMEM.
880  *
881  * @param   psh     The shell instance.
882  * @param   pid     The child pid.
883  * @param   hChild  Windows child handle.
884  */
sh_add_child(shinstance * psh,pid_t pid,void * hChild)885 int sh_add_child(shinstance *psh, pid_t pid, void *hChild)
886 {
887     /* get a free table entry. */
888     int i = psh->num_children++;
889     if (!(i % 32))
890     {
891         void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32));
892         if (!ptr)
893         {
894             psh->num_children--;
895             errno = ENOMEM;
896             return -1;
897         }
898         psh->children = ptr;
899     }
900 
901     /* add it */
902     psh->children[i].pid = pid;
903 #if K_OS == K_OS_WINDOWS
904     psh->children[i].hChild = hChild;
905 #endif
906     (void)hChild;
907     return 0;
908 }
909 
sh_fork(shinstance * psh)910 pid_t sh_fork(shinstance *psh)
911 {
912     pid_t pid;
913     TRACE2((psh, "sh_fork\n"));
914 
915 #if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
916     pid = shfork_do(psh);
917 
918 #elif defined(SH_FORKED_MODE)
919 # ifdef _MSC_VER
920     pid = -1;
921     errno = ENOSYS;
922 # else
923     pid = fork();
924 # endif
925 
926 #else
927 
928 #endif
929 
930     /* child: update the pid and zap the children array */
931     if (!pid)
932     {
933 # ifdef _MSC_VER
934         psh->pid = _getpid();
935 # else
936         psh->pid = getpid();
937 # endif
938         psh->num_children = 0;
939     }
940 
941     TRACE2((psh, "sh_fork -> %d [%d]\n", pid, errno));
942     (void)psh;
943     return pid;
944 }
945 
946 /** waitpid() */
sh_waitpid(shinstance * psh,pid_t pid,int * statusp,int flags)947 pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags)
948 {
949     pid_t pidret;
950 #if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
951     DWORD   dwRet;
952     HANDLE  hChild = INVALID_HANDLE_VALUE;
953     int     i;
954 
955     *statusp = 0;
956     pidret = -1;
957     if (pid != -1)
958     {
959         /*
960          * A specific child, try look it up in the child process table
961          * and wait for it.
962          */
963         for (i = 0; i < psh->num_children; i++)
964             if (psh->children[i].pid == pid)
965                 break;
966         if (i < psh->num_children)
967         {
968             dwRet = WaitForSingleObject(psh->children[i].hChild,
969                                         flags & WNOHANG ? 0 : INFINITE);
970             if (dwRet == WAIT_OBJECT_0)
971                 hChild = psh->children[i].hChild;
972             else if (dwRet == WAIT_TIMEOUT)
973             {
974                 i = -1; /* don't try close anything */
975                 pidret = 0;
976             }
977             else
978                 errno = ECHILD;
979         }
980         else
981             errno = ECHILD;
982     }
983     else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
984     {
985         HANDLE ahChildren[MAXIMUM_WAIT_OBJECTS];
986         for (i = 0; i < psh->num_children; i++)
987             ahChildren[i] = psh->children[i].hChild;
988         dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
989                                        FALSE,
990                                        flags & WNOHANG ? 0 : INFINITE);
991         i = dwRet - WAIT_OBJECT_0;
992         if ((unsigned)i < (unsigned)psh->num_children)
993         {
994             hChild = psh->children[i].hChild;
995         }
996         else if (dwRet == WAIT_TIMEOUT)
997         {
998             i = -1; /* don't try close anything */
999             pidret = 0;
1000         }
1001         else
1002         {
1003             i = -1; /* don't try close anything */
1004             errno = EINVAL;
1005         }
1006     }
1007     else
1008     {
1009         fprintf(stderr, "panic! too many children!\n");
1010         i = -1;
1011         *(char *)1 = '\0'; /** @todo implement this! */
1012     }
1013 
1014     /*
1015      * Close the handle, and if we succeeded collect the exit code first.
1016      */
1017     if (    i >= 0
1018         &&  i < psh->num_children)
1019     {
1020         if (hChild != INVALID_HANDLE_VALUE)
1021         {
1022             DWORD dwExitCode = 127;
1023             if (GetExitCodeProcess(hChild, &dwExitCode))
1024             {
1025                 pidret = psh->children[i].pid;
1026                 if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
1027                     dwExitCode |= 16;
1028                 *statusp = W_EXITCODE(dwExitCode, 0);
1029             }
1030             else
1031                 errno = EINVAL;
1032         }
1033 
1034         /* remove and close */
1035         hChild = psh->children[i].hChild;
1036         psh->num_children--;
1037         if (i < psh->num_children)
1038             psh->children[i] = psh->children[psh->num_children];
1039         i = CloseHandle(hChild); assert(i);
1040     }
1041 
1042 #elif defined(SH_FORKED_MODE)
1043     *statusp = 0;
1044 # ifdef _MSC_VER
1045     pidret = -1;
1046     errno = ENOSYS;
1047 # else
1048     pidret = waitpid(pid, statusp, flags);
1049 # endif
1050 
1051 #else
1052 #endif
1053 
1054     TRACE2((psh, "waitpid(%d, %p, %#x) -> %d [%d] *statusp=%#x (rc=%d)\n", pid, statusp, flags,
1055             pidret, errno, *statusp, WEXITSTATUS(*statusp)));
1056     (void)psh;
1057     return pidret;
1058 }
1059 
sh__exit(shinstance * psh,int rc)1060 SH_NORETURN_1 void sh__exit(shinstance *psh, int rc)
1061 {
1062     TRACE2((psh, "sh__exit(%d)\n", rc));
1063     (void)psh;
1064 
1065 #if defined(SH_FORKED_MODE)
1066     _exit(rc);
1067 
1068 #else
1069 #endif
1070 }
1071 
sh_execve(shinstance * psh,const char * exe,const char * const * argv,const char * const * envp)1072 int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp)
1073 {
1074     int rc;
1075 
1076 #ifdef DEBUG
1077     /* log it all */
1078     TRACE2((psh, "sh_execve(%p:{%s}, %p, %p}\n", exe, exe, argv, envp));
1079     for (rc = 0; argv[rc]; rc++)
1080         TRACE2((psh, "  argv[%d]=%p:{%s}\n", rc, argv[rc], argv[rc]));
1081 #endif
1082 
1083     if (!envp)
1084         envp = (const char * const *)sh_environ(psh);
1085 
1086 #if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS
1087 # ifdef _MSC_VER
1088     errno = 0;
1089     {
1090         intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
1091         if (rc2 != -1)
1092         {
1093             TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
1094             rc = (int)rc2;
1095             if (!rc && rc2)
1096                 rc = 16;
1097             exit(rc);
1098         }
1099     }
1100     rc = -1;
1101 
1102 # else
1103     rc = shfile_exec_unix(&psh->fdtab);
1104     if (!rc)
1105         rc = execve(exe, (char **)argv, (char **)envp);
1106 # endif
1107 
1108 #else
1109 # if K_OS == K_OS_WINDOWS
1110     {
1111         /*
1112          * This ain't quite straight forward on Windows...
1113          */
1114         PROCESS_INFORMATION ProcInfo;
1115         STARTUPINFO StrtInfo;
1116         intptr_t hndls[3];
1117         char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
1118         char *cmdline;
1119         size_t cmdline_size;
1120         char *envblock;
1121         size_t env_size;
1122         char *p;
1123         int i;
1124 
1125         /* Create the environment block. */
1126         if (!envp)
1127             envp = sh_environ(psh);
1128         env_size = 2;
1129         for (i = 0; envp[i]; i++)
1130             env_size += strlen(envp[i]) + 1;
1131         envblock = p = sh_malloc(psh, env_size);
1132         for (i = 0; envp[i]; i++)
1133         {
1134             size_t len = strlen(envp[i]) + 1;
1135             memcpy(p, envp[i], len);
1136             p += len;
1137         }
1138         *p = '\0';
1139 
1140         /* Figure the size of the command line. Double quotes makes this
1141            tedious and we overestimate to simplify. */
1142         cmdline_size = 2;
1143         for (i = 0; argv[i]; i++)
1144         {
1145             const char *arg = argv[i];
1146             cmdline_size += strlen(arg) + 3;
1147             arg = strchr(arg, '"');
1148             if (arg)
1149             {
1150                 do
1151                     cmdline_size++;
1152                 while ((arg = strchr(arg + 1, '"')) != NULL);
1153                 arg = argv[i] - 1;
1154                 while ((arg = strchr(arg + 1, '\\')) != NULL);
1155                     cmdline_size++;
1156             }
1157         }
1158 
1159         /* Create the command line. */
1160         cmdline = p = sh_malloc(psh, cmdline_size);
1161         for (i = 0; argv[i]; i++)
1162         {
1163             const char *arg = argv[i];
1164             const char *cur = arg;
1165             size_t len = strlen(arg);
1166             int quoted = 0;
1167             char ch;
1168             while ((ch = *cur++) != '\0')
1169                 if (ch <= 0x20 || strchr("&><|%", ch) != NULL)
1170                 {
1171                     quoted = 1;
1172                     break;
1173                 }
1174 
1175             if (i != 0)
1176                 *(p++) = ' ';
1177             if (quoted)
1178                 *(p++) = '"';
1179             if (memchr(arg, '"', len) == NULL)
1180             {
1181                 memcpy(p, arg, len);
1182                 p += len;
1183             }
1184             else
1185             {   /* MS CRT style: double quotes must be escaped; backslashes
1186                    must be escaped if followed by double quotes. */
1187                 while ((ch = *arg++) != '\0')
1188                     if (ch != '\\' && ch != '"')
1189                         *p++ = ch;
1190                     else if (ch == '"')
1191                     {
1192                         *p++ = '\\';
1193                         *p++ = '"';
1194                     }
1195                     else
1196                     {
1197                         unsigned slashes = 1;
1198                         *p++ = '\\';
1199                         while (*arg == '\\')
1200                         {
1201                             *p++ = '\\';
1202                             slashes++;
1203                             arg++;
1204                         }
1205                         if (*arg == '"')
1206                         {
1207                             while (slashes-- > 0)
1208                                 *p++ = '\\';
1209                             *p++ = '\\';
1210                             *p++ = '"';
1211                             arg++;
1212                         }
1213                     }
1214             }
1215             if (quoted)
1216                 *(p++) = '"';
1217         }
1218         p[0] = p[1] = '\0';
1219 
1220         /* Init the info structure */
1221         memset(&StrtInfo, '\0', sizeof(StrtInfo));
1222         StrtInfo.cb = sizeof(StrtInfo);
1223 
1224         /* File handles. */
1225         StrtInfo.dwFlags   |= STARTF_USESTDHANDLES;
1226         StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
1227         StrtInfo.hStdInput  = (HANDLE)hndls[0];
1228         StrtInfo.hStdOutput = (HANDLE)hndls[1];
1229         StrtInfo.hStdError  = (HANDLE)hndls[2];
1230 
1231         /* Get going... */
1232         if (CreateProcess(exe,
1233                           cmdline,
1234                           NULL,         /* pProcessAttributes */
1235                           NULL,         /* pThreadAttributes */
1236                           TRUE,         /* bInheritHandles */
1237                           0,            /* dwCreationFlags */
1238                           envblock,
1239                           cwd,
1240                           &StrtInfo,
1241                           &ProcInfo))
1242         {
1243             DWORD dwErr;
1244             DWORD dwExitCode;
1245 
1246             CloseHandle(ProcInfo.hThread);
1247             dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
1248             assert(dwErr == WAIT_OBJECT_0);
1249 
1250             if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
1251             {
1252                 CloseHandle(ProcInfo.hProcess);
1253                 _exit(dwExitCode);
1254             }
1255             errno = EINVAL;
1256         }
1257         else
1258         {
1259             DWORD dwErr = GetLastError();
1260             switch (dwErr)
1261             {
1262                 case ERROR_FILE_NOT_FOUND:          errno = ENOENT; break;
1263                 case ERROR_PATH_NOT_FOUND:          errno = ENOENT; break;
1264                 case ERROR_BAD_EXE_FORMAT:          errno = ENOEXEC; break;
1265                 case ERROR_INVALID_EXE_SIGNATURE:   errno = ENOEXEC; break;
1266                 default:
1267                     errno = EINVAL;
1268                     break;
1269             }
1270             TRACE2((psh, "sh_execve: dwErr=%d -> errno=%d\n", dwErr, errno));
1271         }
1272 
1273         shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL);
1274     }
1275     rc = -1;
1276 
1277 # else
1278     errno = ENOSYS;
1279     rc = -1;
1280 # endif
1281 #endif
1282 
1283     TRACE2((psh, "sh_execve -> %d [%d]\n", rc, errno));
1284     (void)psh;
1285     return (int)rc;
1286 }
1287 
sh_getuid(shinstance * psh)1288 uid_t sh_getuid(shinstance *psh)
1289 {
1290 #if defined(SH_FORKED_MODE)
1291 # ifdef _MSC_VER
1292     uid_t uid = 0;
1293 # else
1294     uid_t uid = getuid();
1295 # endif
1296 
1297 #else
1298 #endif
1299 
1300     TRACE2((psh, "sh_getuid() -> %d [%d]\n", uid, errno));
1301     (void)psh;
1302     return uid;
1303 }
1304 
sh_geteuid(shinstance * psh)1305 uid_t sh_geteuid(shinstance *psh)
1306 {
1307 #if defined(SH_FORKED_MODE)
1308 # ifdef _MSC_VER
1309     uid_t euid = 0;
1310 # else
1311     uid_t euid = geteuid();
1312 # endif
1313 
1314 #else
1315 #endif
1316 
1317     TRACE2((psh, "sh_geteuid() -> %d [%d]\n", euid, errno));
1318     (void)psh;
1319     return euid;
1320 }
1321 
sh_getgid(shinstance * psh)1322 gid_t sh_getgid(shinstance *psh)
1323 {
1324 #if defined(SH_FORKED_MODE)
1325 # ifdef _MSC_VER
1326     gid_t gid = 0;
1327 # else
1328     gid_t gid = getgid();
1329 # endif
1330 
1331 #else
1332 #endif
1333 
1334     TRACE2((psh, "sh_getgid() -> %d [%d]\n", gid, errno));
1335     (void)psh;
1336     return gid;
1337 }
1338 
sh_getegid(shinstance * psh)1339 gid_t sh_getegid(shinstance *psh)
1340 {
1341 #if defined(SH_FORKED_MODE)
1342 # ifdef _MSC_VER
1343     gid_t egid = 0;
1344 # else
1345     gid_t egid = getegid();
1346 # endif
1347 
1348 #else
1349 #endif
1350 
1351     TRACE2((psh, "sh_getegid() -> %d [%d]\n", egid, errno));
1352     (void)psh;
1353     return egid;
1354 }
1355 
sh_getpid(shinstance * psh)1356 pid_t sh_getpid(shinstance *psh)
1357 {
1358     pid_t pid;
1359 
1360 #if defined(SH_FORKED_MODE)
1361 # ifdef _MSC_VER
1362     pid = _getpid();
1363 # else
1364     pid = getpid();
1365 # endif
1366 #else
1367 #endif
1368 
1369     (void)psh;
1370     return pid;
1371 }
1372 
sh_getpgrp(shinstance * psh)1373 pid_t sh_getpgrp(shinstance *psh)
1374 {
1375 #if defined(SH_FORKED_MODE)
1376 # ifdef _MSC_VER
1377     pid_t pgrp = _getpid();
1378 # else
1379     pid_t pgrp = getpgrp();
1380 # endif
1381 
1382 #else
1383 #endif
1384 
1385     TRACE2((psh, "sh_getpgrp() -> %d [%d]\n", pgrp, errno));
1386     (void)psh;
1387     return pgrp;
1388 }
1389 
sh_getpgid(shinstance * psh,pid_t pid)1390 pid_t sh_getpgid(shinstance *psh, pid_t pid)
1391 {
1392 #if defined(SH_FORKED_MODE)
1393 # ifdef _MSC_VER
1394     pid_t pgid = pid;
1395 # else
1396     pid_t pgid = getpgid(pid);
1397 # endif
1398 
1399 #else
1400 #endif
1401 
1402     TRACE2((psh, "sh_getpgid(%d) -> %d [%d]\n", pid, pgid, errno));
1403     (void)psh;
1404     return pgid;
1405 }
1406 
sh_setpgid(shinstance * psh,pid_t pid,pid_t pgid)1407 int sh_setpgid(shinstance *psh, pid_t pid, pid_t pgid)
1408 {
1409 #if defined(SH_FORKED_MODE)
1410 # ifdef _MSC_VER
1411     int rc = -1;
1412     errno = ENOSYS;
1413 # else
1414     int rc = setpgid(pid, pgid);
1415 # endif
1416 
1417 #else
1418 #endif
1419 
1420     TRACE2((psh, "sh_setpgid(%d, %d) -> %d [%d]\n", pid, pgid, rc, errno));
1421     (void)psh;
1422     return rc;
1423 }
1424 
sh_tcgetpgrp(shinstance * psh,int fd)1425 pid_t sh_tcgetpgrp(shinstance *psh, int fd)
1426 {
1427     pid_t pgrp;
1428 
1429 #if defined(SH_FORKED_MODE)
1430 # ifdef _MSC_VER
1431     pgrp = -1;
1432     errno = ENOSYS;
1433 # else
1434     pgrp = tcgetpgrp(fd);
1435 # endif
1436 
1437 #else
1438 #endif
1439 
1440     TRACE2((psh, "sh_tcgetpgrp(%d) -> %d [%d]\n", fd, pgrp, errno));
1441     (void)psh;
1442     return pgrp;
1443 }
1444 
sh_tcsetpgrp(shinstance * psh,int fd,pid_t pgrp)1445 int sh_tcsetpgrp(shinstance *psh, int fd, pid_t pgrp)
1446 {
1447     int rc;
1448     TRACE2((psh, "sh_tcsetpgrp(%d, %d)\n", fd, pgrp));
1449 
1450 #if defined(SH_FORKED_MODE)
1451 # ifdef _MSC_VER
1452     rc = -1;
1453     errno = ENOSYS;
1454 # else
1455     rc = tcsetpgrp(fd, pgrp);
1456 # endif
1457 
1458 #else
1459 #endif
1460 
1461     TRACE2((psh, "sh_tcsetpgrp(%d, %d) -> %d [%d]\n", fd, pgrp, rc, errno));
1462     (void)psh;
1463     return rc;
1464 }
1465 
sh_getrlimit(shinstance * psh,int resid,shrlimit * limp)1466 int sh_getrlimit(shinstance *psh, int resid, shrlimit *limp)
1467 {
1468 #if defined(SH_FORKED_MODE)
1469 # ifdef _MSC_VER
1470     int rc = -1;
1471     errno = ENOSYS;
1472 # else
1473     int rc = getrlimit(resid, limp);
1474 # endif
1475 
1476 #else
1477     /* returned the stored limit */
1478 #endif
1479 
1480     TRACE2((psh, "sh_getrlimit(%d, %p) -> %d [%d] {%ld,%ld}\n",
1481             resid, limp, rc, errno, (long)limp->rlim_cur, (long)limp->rlim_max));
1482     (void)psh;
1483     return rc;
1484 }
1485 
sh_setrlimit(shinstance * psh,int resid,const shrlimit * limp)1486 int sh_setrlimit(shinstance *psh, int resid, const shrlimit *limp)
1487 {
1488 #if defined(SH_FORKED_MODE)
1489 # ifdef _MSC_VER
1490     int rc = -1;
1491     errno = ENOSYS;
1492 # else
1493     int rc = setrlimit(resid, limp);
1494 # endif
1495 
1496 #else
1497     /* if max(shell) < limp; then setrlimit; fi
1498        if success; then store limit for later retrival and maxing. */
1499 
1500 #endif
1501 
1502     TRACE2((psh, "sh_setrlimit(%d, %p:{%ld,%ld}) -> %d [%d]\n",
1503             resid, limp, (long)limp->rlim_cur, (long)limp->rlim_max, rc, errno));
1504     (void)psh;
1505     return rc;
1506 }
1507 
1508 
1509 /* Wrapper for strerror that makes sure it doesn't return NULL and causes the
1510    caller or fprintf routines to crash. */
sh_strerror(shinstance * psh,int error)1511 const char *sh_strerror(shinstance *psh, int error)
1512 {
1513     char *err = strerror(error);
1514     if (!err)
1515         return "strerror return NULL!";
1516     (void)psh;
1517     return err;
1518 }
1519 
1520