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