main.c revision 1.12 1 /* $NetBSD: main.c,v 1.12 2005/06/26 19:09:00 christos Exp $ */
2
3 /*
4 * startup, main loop, environments and error handling
5 */
6 #include <sys/cdefs.h>
7
8 #ifndef lint
9 __RCSID("$NetBSD: main.c,v 1.12 2005/06/26 19:09:00 christos Exp $");
10 #endif
11
12
13 #define EXTERN /* define EXTERNs in sh.h */
14
15 #include "sh.h"
16 #include "ksh_stat.h"
17 #include "ksh_time.h"
18
19 extern char **environ;
20
21 /*
22 * global data
23 */
24
25 static void reclaim ARGS((void));
26 static void remove_temps ARGS((struct temp *tp));
27 static int is_restricted ARGS((char *name));
28
29 /*
30 * shell initialization
31 */
32
33 static const char initifs[] = "IFS= \t\n";
34
35 static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
36
37 static const char version_param[] =
38 #ifdef KSH
39 "KSH_VERSION"
40 #else /* KSH */
41 "SH_VERSION"
42 #endif /* KSH */
43 ;
44
45 static const char *const initcoms [] = {
46 "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
47 "typeset", "-r", version_param, NULL,
48 "typeset", "-i", "PPID", NULL,
49 "typeset", "-i", "OPTIND=1", NULL,
50 #ifdef KSH
51 "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
52 #endif /* KSH */
53 "alias",
54 /* Standard ksh aliases */
55 "hash=alias -t", /* not "alias -t --": hash -r needs to work */
56 "type=whence -v",
57 #ifdef JOBS
58 "stop=kill -STOP",
59 "suspend=kill -STOP $$",
60 #endif
61 #ifdef KSH
62 "autoload=typeset -fu",
63 "functions=typeset -f",
64 # ifdef HISTORY
65 "history=fc -l",
66 # endif /* HISTORY */
67 "integer=typeset -i",
68 "nohup=nohup ",
69 "local=typeset",
70 "r=fc -e -",
71 #endif /* KSH */
72 #ifdef KSH
73 /* Aliases that are builtin commands in at&t */
74 "login=exec login",
75 #ifndef __NetBSD__
76 "newgrp=exec newgrp",
77 #endif /* __NetBSD__ */
78 #endif /* KSH */
79 NULL,
80 /* this is what at&t ksh seems to track, with the addition of emacs */
81 "alias", "-tU",
82 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
83 "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
84 NULL,
85 #ifdef EXTRA_INITCOMS
86 EXTRA_INITCOMS, NULL,
87 #endif /* EXTRA_INITCOMS */
88 NULL
89 };
90
91 int
92 main(int argc, char *argv[])
93 {
94 register int i;
95 int argi;
96 Source *s;
97 struct block *l;
98 int restricted, errexit;
99 char **wp;
100 struct env env;
101 pid_t ppid;
102
103 #ifdef MEM_DEBUG
104 chmem_set_defaults("ct", 1);
105 /* chmem_push("+c", 1); */
106 #endif /* MEM_DEBUG */
107
108 #ifdef OS2
109 setmode (0, O_BINARY);
110 setmode (1, O_TEXT);
111 #endif
112
113 /* make sure argv[] is sane */
114 if (!*argv) {
115 static const char *empty_argv[] = {
116 "pdksh", (char *) 0
117 };
118
119 argv = (char **)__UNCONST(empty_argv);
120 argc = 1;
121 }
122 kshname = *argv;
123
124 ainit(&aperm); /* initialize permanent Area */
125
126 /* set up base environment */
127 memset(&env, 0, sizeof(env));
128 env.type = E_NONE;
129 ainit(&env.area);
130 e = &env;
131 newblock(); /* set up global l->vars and l->funs */
132
133 /* Do this first so output routines (eg, errorf, shellf) can work */
134 initio();
135
136 initvar();
137
138 initctypes();
139
140 inittraps();
141
142 #ifdef KSH
143 coproc_init();
144 #endif /* KSH */
145
146 /* set up variable and command dictionaries */
147 tinit(&taliases, APERM, 0);
148 tinit(&aliases, APERM, 0);
149 tinit(&homedirs, APERM, 0);
150
151 /* define shell keywords */
152 initkeywords();
153
154 /* define built-in commands */
155 tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
156 for (i = 0; shbuiltins[i].name != NULL; i++)
157 builtin(shbuiltins[i].name, shbuiltins[i].func);
158 for (i = 0; kshbuiltins[i].name != NULL; i++)
159 builtin(kshbuiltins[i].name, kshbuiltins[i].func);
160
161 init_histvec();
162
163 def_path = DEFAULT__PATH;
164 #if defined(HAVE_CONFSTR) && defined(_CS_PATH)
165 {
166 size_t len = confstr(_CS_PATH, (char *) 0, 0);
167 char *new;
168
169 if (len > 0) {
170 confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
171 def_path = new;
172 }
173 }
174 #endif /* HAVE_CONFSTR && _CS_PATH */
175
176 /* Set PATH to def_path (will set the path global variable).
177 * (import of environment below will probably change this setting).
178 */
179 {
180 struct tbl *vp = global("PATH");
181 /* setstr can't fail here */
182 setstr(vp, def_path, KSH_RETURN_ERROR);
183 }
184
185
186 /* Turn on nohup by default for now - will change to off
187 * by default once people are aware of its existence
188 * (at&t ksh does not have a nohup option - it always sends
189 * the hup).
190 */
191 Flag(FNOHUP) = 1;
192
193 /* Turn on brace expansion by default. At&t ksh's that have
194 * alternation always have it on. BUT, posix doesn't have
195 * brace expansion, so set this before setting up FPOSIX
196 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
197 */
198 #ifdef BRACE_EXPAND
199 Flag(FBRACEEXPAND) = 1;
200 #endif /* BRACE_EXPAND */
201
202 /* set posix flag just before environment so that it will have
203 * exactly the same effect as the POSIXLY_CORRECT environment
204 * variable. If this needs to be done sooner to ensure correct posix
205 * operation, an initial scan of the environment will also have
206 * done sooner.
207 */
208 #ifdef POSIXLY_CORRECT
209 change_flag(FPOSIX, OF_SPECIAL, 1);
210 #endif /* POSIXLY_CORRECT */
211
212 /* Set edit mode to emacs by default, may be overridden
213 * by the environment or the user. Also, we want tab completion
214 * on in vi by default. */
215 #if defined(EDIT) && defined(EMACS)
216 change_flag(FEMACS, OF_SPECIAL, 1);
217 #endif /* EDIT && EMACS */
218 #if defined(EDIT) && defined(VI)
219 Flag(FVITABCOMPLETE) = 1;
220 #endif /* EDIT && VI */
221
222 /* import environment */
223 if (environ != NULL)
224 for (wp = environ; *wp != NULL; wp++)
225 typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
226
227 kshpid = procpid = getpid();
228 typeset(initifs, 0, 0, 0, 0); /* for security */
229
230 /* assign default shell variable values */
231 substitute(initsubs, 0);
232
233 /* Figure out the current working directory and set $PWD */
234 {
235 struct stat s_pwd, s_dot;
236 struct tbl *pwd_v = global("PWD");
237 char *pwd = str_val(pwd_v);
238 char *pwdx = pwd;
239
240 /* Try to use existing $PWD if it is valid */
241 if (!ISABSPATH(pwd)
242 || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
243 || s_pwd.st_dev != s_dot.st_dev
244 || s_pwd.st_ino != s_dot.st_ino)
245 pwdx = (char *) 0;
246 set_current_wd(pwdx);
247 if (current_wd[0])
248 simplify_path(current_wd);
249 /* Only set pwd if we know where we are or if it had a
250 * bogus value
251 */
252 if (current_wd[0] || pwd != null)
253 /* setstr can't fail here */
254 setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
255 }
256 ppid = getppid();
257 setint(global("PPID"), (long) ppid);
258 #ifdef KSH
259 setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
260 #endif /* KSH */
261 /* setstr can't fail here */
262 setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
263
264 /* execute initialization statements */
265 for (wp = (char**)__UNCONST(initcoms); *wp != NULL; wp++) {
266 shcomexec(wp);
267 for (; *wp != NULL; wp++)
268 ;
269 }
270
271
272 ksheuid = geteuid();
273 safe_prompt = ksheuid ? "$ " : "# ";
274 {
275 struct tbl *vp = global("PS1");
276
277 /* Set PS1 if it isn't set, or we are root and prompt doesn't
278 * contain a #.
279 */
280 if (!(vp->flag & ISSET)
281 || (!ksheuid && !strchr(str_val(vp), '#')))
282 /* setstr can't fail here */
283 setstr(vp, safe_prompt, KSH_RETURN_ERROR);
284 }
285
286 /* Set this before parsing arguments */
287 Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
288
289 /* this to note if monitor is set on command line (see below) */
290 Flag(FMONITOR) = 127;
291 argi = parse_args(argv, OF_CMDLINE, (int *) 0);
292 if (argi < 0) {
293 exit(1);
294 /* NOTREACHED */
295 }
296
297 if (Flag(FCOMMAND)) {
298 s = pushs(SSTRING, ATEMP);
299 if (!(s->start = s->str = argv[argi++]))
300 errorf("-c requires an argument");
301 if (argv[argi])
302 kshname = argv[argi++];
303 } else if (argi < argc && !Flag(FSTDIN)) {
304 s = pushs(SFILE, ATEMP);
305 #ifdef OS2
306 /* a bug in os2 extproc shell processing doesn't
307 * pass full pathnames so we have to search for it.
308 * This changes the behavior of 'ksh arg' to search
309 * the users search path but it can't be helped.
310 */
311 s->file = search(argv[argi++], path, R_OK, (int *) 0);
312 if (!s->file || !*s->file)
313 s->file = argv[argi - 1];
314 #else
315 s->file = argv[argi++];
316 #endif /* OS2 */
317 s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
318 if (s->u.shf == NULL) {
319 exstat = 127; /* POSIX */
320 errorf("%s: %s", s->file, strerror(errno));
321 }
322 kshname = s->file;
323 } else {
324 Flag(FSTDIN) = 1;
325 s = pushs(SSTDIN, ATEMP);
326 s->file = "<stdin>";
327 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
328 (struct shf *) 0);
329 if (isatty(0) && isatty(2)) {
330 Flag(FTALKING) = Flag(FTALKING_I) = 1;
331 /* The following only if isatty(0) */
332 s->flags |= SF_TTY;
333 s->u.shf->flags |= SHF_INTERRUPT;
334 s->file = (char *) 0;
335 }
336 }
337
338 /* This bizarreness is mandated by POSIX */
339 {
340 struct stat s_stdin;
341
342 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
343 Flag(FTALKING))
344 reset_nonblock(0);
345 }
346
347 /* initialize job control */
348 i = Flag(FMONITOR) != 127;
349 Flag(FMONITOR) = 0;
350 j_init(i);
351 #ifdef EDIT
352 /* Do this after j_init(), as tty_fd is not initialized 'til then */
353 if (Flag(FTALKING))
354 x_init();
355 #endif
356
357 l = e->loc;
358 l->argv = &argv[argi - 1];
359 l->argc = argc - argi;
360 l->argv[0] = (char *)__UNCONST(kshname);
361 getopts_reset(1);
362
363 /* Disable during .profile/ENV reading */
364 restricted = Flag(FRESTRICTED);
365 Flag(FRESTRICTED) = 0;
366 errexit = Flag(FERREXIT);
367 Flag(FERREXIT) = 0;
368
369 /* Do this before profile/$ENV so that if it causes problems in them,
370 * user will know why things broke.
371 */
372 if (!current_wd[0] && Flag(FTALKING))
373 warningf(FALSE, "Cannot determine current working directory");
374
375 if (Flag(FLOGIN)) {
376 #ifdef OS2
377 char *profile;
378
379 /* Try to find a profile - first see if $INIT has a value,
380 * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh.
381 */
382 if (!Flag(FPRIVILEGED)
383 && strcmp(profile = substitute("$INIT/profile.ksh", 0),
384 "/profile.ksh"))
385 include(profile, 0, (char **) 0, 1);
386 else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0)
387 include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1);
388 if (!Flag(FPRIVILEGED))
389 include(substitute("$HOME/profile.ksh", 0), 0,
390 (char **) 0, 1);
391 #else /* OS2 */
392 include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
393 if (!Flag(FPRIVILEGED))
394 include(substitute("$HOME/.profile", 0), 0,
395 (char **) 0, 1);
396 #endif /* OS2 */
397 }
398
399 if (Flag(FPRIVILEGED))
400 include("/etc/suid_profile", 0, (char **) 0, 1);
401 else {
402 char *env_file;
403
404 #ifndef KSH
405 if (!Flag(FPOSIX))
406 env_file = null;
407 else
408 #endif /* !KSH */
409 /* include $ENV */
410 env_file = str_val(global("ENV"));
411
412 #ifdef DEFAULT_ENV
413 /* If env isn't set, include default environment */
414 if (env_file == null)
415 env_file = __UNCONST(DEFAULT_ENV);
416 #endif /* DEFAULT_ENV */
417 env_file = substitute(env_file, DOTILDE);
418 if (*env_file != '\0')
419 include(env_file, 0, (char **) 0, 1);
420 #ifdef OS2
421 else if (Flag(FTALKING))
422 include(substitute("$HOME/kshrc.ksh", 0), 0,
423 (char **) 0, 1);
424 #endif /* OS2 */
425 }
426
427 if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
428 restricted = 1;
429 if (restricted) {
430 static const char *const restr_com[] = {
431 "typeset", "-r", "PATH",
432 "ENV", "SHELL",
433 (char *) 0
434 };
435 shcomexec((char **)__UNCONST(restr_com));
436 /* After typeset command... */
437 Flag(FRESTRICTED) = 1;
438 }
439 if (errexit)
440 Flag(FERREXIT) = 1;
441
442 if (Flag(FTALKING)) {
443 hist_init(s);
444 #ifdef KSH
445 alarm_init();
446 #endif /* KSH */
447 } else
448 Flag(FTRACKALL) = 1; /* set after ENV */
449
450 shell(s, TRUE); /* doesn't return */
451 return 0;
452 }
453
454 int
455 include(name, argc, argv, intr_ok)
456 const char *name;
457 int argc;
458 char **argv;
459 int intr_ok;
460 {
461 register Source *volatile s = NULL;
462 struct shf *shf;
463 char **volatile old_argv;
464 volatile int old_argc;
465 int i;
466
467 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
468 if (shf == NULL)
469 return -1;
470
471 if (argv) {
472 old_argv = e->loc->argv;
473 old_argc = e->loc->argc;
474 } else {
475 old_argv = (char **) 0;
476 old_argc = 0;
477 }
478 newenv(E_INCL);
479 i = ksh_sigsetjmp(e->jbuf, 0);
480 if (i) {
481 if (s) /* Do this before quitenv(), which frees the memory */
482 shf_close(s->u.shf);
483 quitenv();
484 if (old_argv) {
485 e->loc->argv = old_argv;
486 e->loc->argc = old_argc;
487 }
488 switch (i) {
489 case LRETURN:
490 case LERROR:
491 return exstat & 0xff; /* see below */
492 case LINTR:
493 /* intr_ok is set if we are including .profile or $ENV.
494 * If user ^C's out, we don't want to kill the shell...
495 */
496 if (intr_ok && (exstat - 128) != SIGTERM)
497 return 1;
498 /* fall through... */
499 case LEXIT:
500 case LLEAVE:
501 case LSHELL:
502 unwind(i);
503 /*NOREACHED*/
504 default:
505 internal_errorf(1, "include: %d", i);
506 /*NOREACHED*/
507 }
508 }
509 if (argv) {
510 e->loc->argv = argv;
511 e->loc->argc = argc;
512 }
513 s = pushs(SFILE, ATEMP);
514 s->u.shf = shf;
515 s->file = str_save(name, ATEMP);
516 i = shell(s, FALSE);
517 shf_close(s->u.shf);
518 quitenv();
519 if (old_argv) {
520 e->loc->argv = old_argv;
521 e->loc->argc = old_argc;
522 }
523 return i & 0xff; /* & 0xff to ensure value not -1 */
524 }
525
526 int
527 command(comm)
528 const char *comm;
529 {
530 register Source *s;
531
532 s = pushs(SSTRING, ATEMP);
533 s->start = s->str = comm;
534 return shell(s, FALSE);
535 }
536
537 /*
538 * run the commands from the input source, returning status.
539 */
540 int
541 shell(s, toplevel)
542 Source *volatile s; /* input source */
543 int volatile toplevel;
544 {
545 struct op *t;
546 volatile int wastty = s->flags & SF_TTY;
547 volatile int attempts = 13;
548 volatile int interactive = Flag(FTALKING) && toplevel;
549 Source *volatile old_source = source;
550 int i;
551
552 newenv(E_PARSE);
553 if (interactive)
554 really_exit = 0;
555 i = ksh_sigsetjmp(e->jbuf, 0);
556 if (i) {
557 switch (i) {
558 case LINTR: /* we get here if SIGINT not caught or ignored */
559 case LERROR:
560 case LSHELL:
561 if (interactive) {
562 if (i == LINTR)
563 shellf(newline);
564 /* Reset any eof that was read as part of a
565 * multiline command.
566 */
567 if (Flag(FIGNOREEOF) && s->type == SEOF
568 && wastty)
569 s->type = SSTDIN;
570 /* Used by exit command to get back to
571 * top level shell. Kind of strange since
572 * interactive is set if we are reading from
573 * a tty, but to have stopped jobs, one only
574 * needs FMONITOR set (not FTALKING/SF_TTY)...
575 */
576 /* toss any input we have so far */
577 s->start = s->str = null;
578 break;
579 }
580 /* fall through... */
581 case LEXIT:
582 case LLEAVE:
583 case LRETURN:
584 source = old_source;
585 quitenv();
586 unwind(i); /* keep on going */
587 /*NOREACHED*/
588 default:
589 source = old_source;
590 quitenv();
591 internal_errorf(1, "shell: %d", i);
592 /*NOREACHED*/
593 }
594 }
595
596 while (1) {
597 if (trap)
598 runtraps(0);
599
600 if (s->next == NULL) {
601 if (Flag(FVERBOSE))
602 s->flags |= SF_ECHO;
603 else
604 s->flags &= ~SF_ECHO;
605 }
606
607 if (interactive) {
608 j_notify();
609 #ifdef KSH
610 mcheck();
611 #endif /* KSH */
612 set_prompt(PS1, s);
613 }
614
615 t = compile(s);
616 if (t != NULL && t->type == TEOF) {
617 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
618 shellf("Use `exit' to leave ksh\n");
619 s->type = SSTDIN;
620 } else if (wastty && !really_exit
621 && j_stopped_running())
622 {
623 really_exit = 1;
624 s->type = SSTDIN;
625 } else {
626 /* this for POSIX, which says EXIT traps
627 * shall be taken in the environment
628 * immediately after the last command
629 * executed.
630 */
631 if (toplevel)
632 unwind(LEXIT);
633 break;
634 }
635 }
636
637 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
638 exstat = execute(t, 0);
639
640 if (t != NULL && t->type != TEOF && interactive && really_exit)
641 really_exit = 0;
642
643 reclaim();
644 }
645 quitenv();
646 source = old_source;
647 return exstat;
648 }
649
650 /* return to closest error handler or shell(), exit if none found */
651 void
652 unwind(i)
653 int i;
654 {
655 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
656 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
657 && sigtraps[SIGEXIT_].trap))
658 {
659 runtrap(&sigtraps[SIGEXIT_]);
660 i = LLEAVE;
661 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
662 runtrap(&sigtraps[SIGERR_]);
663 i = LLEAVE;
664 }
665 while (1) {
666 switch (e->type) {
667 case E_PARSE:
668 case E_FUNC:
669 case E_INCL:
670 case E_LOOP:
671 case E_ERRH:
672 ksh_siglongjmp(e->jbuf, i);
673 /*NOTREACHED*/
674
675 case E_NONE:
676 if (i == LINTR)
677 e->flags |= EF_FAKE_SIGDIE;
678 /* Fall through... */
679
680 default:
681 quitenv();
682 }
683 }
684 }
685
686 void
687 newenv(type)
688 int type;
689 {
690 register struct env *ep;
691
692 ep = (struct env *) alloc(sizeof(*ep), ATEMP);
693 ep->type = type;
694 ep->flags = 0;
695 ainit(&ep->area);
696 ep->loc = e->loc;
697 ep->savefd = NULL;
698 ep->oenv = e;
699 ep->temps = NULL;
700 e = ep;
701 }
702
703 void
704 quitenv()
705 {
706 register struct env *ep = e;
707 register int fd;
708
709 if (ep->oenv && ep->oenv->loc != ep->loc)
710 popblock();
711 if (ep->savefd != NULL) {
712 for (fd = 0; fd < NUFILE; fd++)
713 /* if ep->savefd[fd] < 0, means fd was closed */
714 if (ep->savefd[fd])
715 restfd(fd, ep->savefd[fd]);
716 if (ep->savefd[2]) /* Clear any write errors */
717 shf_reopen(2, SHF_WR, shl_out);
718 }
719 reclaim();
720
721 /* Bottom of the stack.
722 * Either main shell is exiting or cleanup_parents_env() was called.
723 */
724 if (ep->oenv == NULL) {
725 if (ep->type == E_NONE) { /* Main shell exiting? */
726 if (Flag(FTALKING))
727 hist_finish();
728 j_exit();
729 if (ep->flags & EF_FAKE_SIGDIE) {
730 int sig = exstat - 128;
731
732 /* ham up our death a bit (at&t ksh
733 * only seems to do this for SIGTERM)
734 * Don't do it for SIGQUIT, since we'd
735 * dump a core..
736 */
737 if (sig == SIGINT || sig == SIGTERM) {
738 setsig(&sigtraps[sig], SIG_DFL,
739 SS_RESTORE_CURR|SS_FORCE);
740 kill(0, sig);
741 }
742 }
743 #ifdef MEM_DEBUG
744 chmem_allfree();
745 #endif /* MEM_DEBUG */
746 }
747 exit(exstat);
748 }
749
750 e = e->oenv;
751 afree(ep, ATEMP);
752 }
753
754 /* Called after a fork to cleanup stuff left over from parents environment */
755 void
756 cleanup_parents_env()
757 {
758 struct env *ep;
759 int fd;
760
761 /* Don't clean up temporary files - parent will probably need them.
762 * Also, can't easily reclaim memory since variables, etc. could be
763 * anywhere.
764 */
765
766 /* close all file descriptors hiding in savefd */
767 for (ep = e; ep; ep = ep->oenv) {
768 if (ep->savefd) {
769 for (fd = 0; fd < NUFILE; fd++)
770 if (ep->savefd[fd] > 0)
771 close(ep->savefd[fd]);
772 afree(ep->savefd, &ep->area);
773 ep->savefd = (short *) 0;
774 }
775 }
776 e->oenv = (struct env *) 0;
777 }
778
779 /* Called just before an execve cleanup stuff temporary files */
780 void
781 cleanup_proc_env()
782 {
783 struct env *ep;
784
785 for (ep = e; ep; ep = ep->oenv)
786 remove_temps(ep->temps);
787 }
788
789 /* remove temp files and free ATEMP Area */
790 static void
791 reclaim()
792 {
793 remove_temps(e->temps);
794 e->temps = NULL;
795 afreeall(&e->area);
796 }
797
798 static void
799 remove_temps(tp)
800 struct temp *tp;
801 {
802 #ifdef OS2
803 static struct temp *delayed_remove;
804 struct temp *t, **tprev;
805
806 if (delayed_remove) {
807 for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev)
808 /* No need to check t->pid here... */
809 if (unlink(t->name) >= 0 || errno == ENOENT) {
810 *tprev = t->next;
811 afree(t, APERM);
812 } else
813 tprev = &t->next;
814 }
815 #endif /* OS2 */
816
817 for (; tp != NULL; tp = tp->next)
818 if (tp->pid == procpid) {
819 #ifdef OS2
820 /* OS/2 (and dos) do not allow files that are currently
821 * open to be removed, so we cache it away for future
822 * removal.
823 * XXX should only do this if errno
824 * is Efile-still-open-can't-remove
825 * (but I don't know what that is...)
826 */
827 if (unlink(tp->name) < 0 && errno != ENOENT) {
828 t = (struct temp *) alloc(
829 sizeof(struct temp) + strlen(tp->name) + 1,
830 APERM);
831 memset(t, 0, sizeof(struct temp));
832 t->name = (char *) &t[1];
833 strlcpy(t->name, tp->name, strlen(tp->name) + 1);
834 t->next = delayed_remove;
835 delayed_remove = t;
836 }
837 #else /* OS2 */
838 unlink(tp->name);
839 #endif /* OS2 */
840 }
841 }
842
843 /* Returns true if name refers to a restricted shell */
844 static int
845 is_restricted(name)
846 char *name;
847 {
848 char *p;
849
850 if ((p = ksh_strrchr_dirsep(name)))
851 name = p;
852 /* accepts rsh, rksh, rpdksh, pdrksh, etc. */
853 return (p = strchr(name, 'r')) && strstr(p, "sh");
854 }
855
856 void
857 aerror(ap, msg)
858 Area *ap;
859 const char *msg;
860 {
861 internal_errorf(1, "alloc: %s", msg);
862 errorf(null); /* this is never executed - keeps gcc quiet */
863 /*NOTREACHED*/
864 }
865