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