import openbsd kill(1)
[unleashed.git] / bin / ksh / main.c
blob3380d85badb77f126ab2a4a33733af23a6608d5f
1 /* $OpenBSD: main.c,v 1.92 2018/05/18 13:25:20 benno Exp $ */
3 /*
4 * startup, main loop, environments and error handling
5 */
7 #include <sys/stat.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <paths.h>
12 #include <pwd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
18 #include "sh.h"
20 extern char **environ;
23 * global data
26 static void reclaim(void);
27 static void remove_temps(struct temp *tp);
28 static int is_restricted(char *name);
29 static void init_username(void);
31 const char *kshname;
32 pid_t kshpid;
33 pid_t procpid;
34 uid_t ksheuid;
35 int exstat;
36 int subst_exstat;
37 const char *safe_prompt;
39 Area aperm;
41 struct env *genv;
43 char shell_flags[FNFLAGS];
45 char null[] = "";
47 int shl_stdout_ok;
49 unsigned int ksh_tmout;
50 enum tmout_enum ksh_tmout_state = TMOUT_EXECUTING;
52 int really_exit;
54 int ifs0 = ' ';
56 volatile sig_atomic_t trap;
57 volatile sig_atomic_t intrsig;
58 volatile sig_atomic_t fatal_trap;
60 Getopt builtin_opt;
61 Getopt user_opt;
63 struct coproc coproc;
64 sigset_t sm_default, sm_sigchld;
66 char *builtin_argv0;
67 int builtin_flag;
69 char *current_wd;
70 int current_wd_size;
72 int x_cols = 80;
75 * shell initialization
78 static const char initifs[] = "IFS= \t\n";
80 static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
82 static const char *initcoms [] = {
83 "typeset", "-r", "KSH_VERSION", NULL,
84 "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
85 "typeset", "-ir", "PPID", NULL,
86 "typeset", "-i", "OPTIND=1", NULL,
87 "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
88 "alias",
89 /* Standard ksh aliases */
90 "hash=alias -t", /* not "alias -t --": hash -r needs to work */
91 "stop=kill -STOP",
92 "autoload=typeset -fu",
93 "functions=typeset -f",
94 "history=fc -l",
95 "integer=typeset -i",
96 "nohup=nohup ",
97 "local=typeset",
98 "r=fc -s",
99 /* Aliases that are builtin commands in at&t */
100 "login=exec login",
101 NULL,
102 /* this is what at&t ksh seems to track, with the addition of emacs */
103 "alias", "-tU",
104 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
105 "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
106 NULL,
107 NULL
110 char username[_PW_NAME_LEN + 1];
112 #define version_param (initcoms[2])
114 /* The shell uses its own variation on argv, to build variables like
115 * $0 and $@.
116 * Allocate a new array since modifying the original argv will modify
117 * ps output.
119 static char **
120 make_argv(int argc, char *argv[])
122 int i;
123 char **nargv;
125 nargv = areallocarray(NULL, argc + 1, sizeof(char *), &aperm);
126 nargv[0] = (char *) kshname;
127 for (i = 1; i < argc; i++)
128 nargv[i] = argv[i];
129 nargv[i] = NULL;
131 return nargv;
135 main(int argc, char *argv[])
137 int i;
138 int argi;
139 Source *s;
140 struct block *l;
141 int restricted, errexit;
142 char **wp;
143 struct env env;
144 pid_t ppid;
146 kshname = argv[0];
148 if (pledge("stdio rpath wpath cpath fattr flock getpw proc exec tty",
149 NULL) == -1) {
150 perror("pledge");
151 exit(1);
154 ainit(&aperm); /* initialize permanent Area */
156 /* set up base environment */
157 memset(&env, 0, sizeof(env));
158 env.type = E_NONE;
159 ainit(&env.area);
160 genv = &env;
161 newblock(); /* set up global l->vars and l->funs */
163 /* Do this first so output routines (eg, errorf, shellf) can work */
164 initio();
166 initvar();
168 initctypes();
170 inittraps();
172 coproc_init();
174 /* set up variable and command dictionaries */
175 ktinit(&taliases, APERM, 0);
176 ktinit(&aliases, APERM, 0);
177 ktinit(&homedirs, APERM, 0);
179 /* define shell keywords */
180 initkeywords();
182 /* define built-in commands */
183 ktinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
184 for (i = 0; shbuiltins[i].name != NULL; i++)
185 builtin(shbuiltins[i].name, shbuiltins[i].func);
186 for (i = 0; kshbuiltins[i].name != NULL; i++)
187 builtin(kshbuiltins[i].name, kshbuiltins[i].func);
189 init_histvec();
191 def_path = _PATH_DEFPATH;
193 size_t len = confstr(_CS_PATH, NULL, 0);
194 char *new;
196 if (len > 0) {
197 confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
198 def_path = new;
202 /* Set PATH to def_path (will set the path global variable).
203 * (import of environment below will probably change this setting).
206 struct tbl *vp = global("PATH");
207 /* setstr can't fail here */
208 setstr(vp, def_path, KSH_RETURN_ERROR);
212 /* Turn on nohup by default for now - will change to off
213 * by default once people are aware of its existence
214 * (at&t ksh does not have a nohup option - it always sends
215 * the hup).
217 Flag(FNOHUP) = 1;
219 /* Turn on brace expansion by default. At&t ksh's that have
220 * alternation always have it on. BUT, posix doesn't have
221 * brace expansion, so set this before setting up FPOSIX
222 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
224 Flag(FBRACEEXPAND) = 1;
226 /* set posix flag just before environment so that it will have
227 * exactly the same effect as the POSIXLY_CORRECT environment
228 * variable. If this needs to be done sooner to ensure correct posix
229 * operation, an initial scan of the environment will also have
230 * done sooner.
232 #ifdef POSIXLY_CORRECT
233 change_flag(FPOSIX, OF_SPECIAL, 1);
234 #endif /* POSIXLY_CORRECT */
236 /* Check to see if we're /bin/sh. */
237 if (!strcmp(kshname, "sh") || !strcmp(kshname, "-sh") ||
238 (strlen(kshname) >= 3 &&
239 !strcmp(&kshname[strlen(kshname) - 3], "/sh"))) {
240 Flag(FSH) = 1;
241 version_param = "SH_VERSION";
244 /* Set edit mode to emacs by default, may be overridden
245 * by the environment or the user. Also, we want tab completion
246 * on in vi by default. */
247 #if defined(EMACS)
248 change_flag(FEMACS, OF_SPECIAL, 1);
249 #endif /* EMACS */
250 #if defined(VI)
251 Flag(FVITABCOMPLETE) = 1;
252 #endif /* VI */
254 /* import environment */
255 if (environ != NULL)
256 for (wp = environ; *wp != NULL; wp++)
257 typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
259 kshpid = procpid = getpid();
260 typeset(initifs, 0, 0, 0, 0); /* for security */
262 /* assign default shell variable values */
263 substitute(initsubs, 0);
265 /* Figure out the current working directory and set $PWD */
267 struct stat s_pwd, s_dot;
268 struct tbl *pwd_v = global("PWD");
269 char *pwd = str_val(pwd_v);
270 char *pwdx = pwd;
272 /* Try to use existing $PWD if it is valid */
273 if (pwd[0] != '/' ||
274 stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 ||
275 s_pwd.st_dev != s_dot.st_dev ||
276 s_pwd.st_ino != s_dot.st_ino)
277 pwdx = NULL;
278 set_current_wd(pwdx);
279 if (current_wd[0])
280 simplify_path(current_wd);
281 /* Only set pwd if we know where we are or if it had a
282 * bogus value
284 if (current_wd[0] || pwd != null)
285 /* setstr can't fail here */
286 setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
288 ppid = getppid();
289 setint(global("PPID"), (int64_t) ppid);
290 /* setstr can't fail here */
291 setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
293 /* execute initialization statements */
294 for (wp = (char**) initcoms; *wp != NULL; wp++) {
295 shcomexec(wp);
296 for (; *wp != NULL; wp++)
301 ksheuid = geteuid();
302 init_username();
303 safe_prompt = ksheuid ? "$ " : "# ";
305 struct tbl *vp = global("PS1");
307 /* Set PS1 if it isn't set */
308 if (!(vp->flag & ISSET)) {
309 /* setstr can't fail here */
310 setstr(vp, "\\h\\$ ", KSH_RETURN_ERROR);
314 /* Set this before parsing arguments */
315 Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
317 /* this to note if monitor is set on command line (see below) */
318 Flag(FMONITOR) = 127;
319 argi = parse_args(argv, OF_CMDLINE, NULL);
320 if (argi < 0)
321 exit(1);
323 if (Flag(FCOMMAND)) {
324 s = pushs(SSTRING, ATEMP);
325 if (!(s->start = s->str = argv[argi++]))
326 errorf("-c requires an argument");
327 if (argv[argi])
328 kshname = argv[argi++];
329 } else if (argi < argc && !Flag(FSTDIN)) {
330 s = pushs(SFILE, ATEMP);
331 s->file = argv[argi++];
332 s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
333 if (s->u.shf == NULL) {
334 exstat = 127; /* POSIX */
335 errorf("%s: %s", s->file, strerror(errno));
337 kshname = s->file;
338 } else {
339 Flag(FSTDIN) = 1;
340 s = pushs(SSTDIN, ATEMP);
341 s->file = "<stdin>";
342 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), NULL);
343 if (isatty(0) && isatty(2)) {
344 Flag(FTALKING) = Flag(FTALKING_I) = 1;
345 /* The following only if isatty(0) */
346 s->flags |= SF_TTY;
347 s->u.shf->flags |= SHF_INTERRUPT;
348 s->file = NULL;
352 /* This bizarreness is mandated by POSIX */
354 struct stat s_stdin;
356 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
357 Flag(FTALKING))
358 reset_nonblock(0);
361 /* initialize job control */
362 i = Flag(FMONITOR) != 127;
363 Flag(FMONITOR) = 0;
364 j_init(i);
365 /* Do this after j_init(), as tty_fd is not initialized 'til then */
366 if (Flag(FTALKING))
367 x_init();
369 l = genv->loc;
370 l->argv = make_argv(argc - (argi - 1), &argv[argi - 1]);
371 l->argc = argc - argi;
372 getopts_reset(1);
374 /* Disable during .profile/ENV reading */
375 restricted = Flag(FRESTRICTED);
376 Flag(FRESTRICTED) = 0;
377 errexit = Flag(FERREXIT);
378 Flag(FERREXIT) = 0;
380 /* Do this before profile/$ENV so that if it causes problems in them,
381 * user will know why things broke.
383 if (!current_wd[0] && Flag(FTALKING))
384 warningf(false, "Cannot determine current working directory");
386 if (Flag(FLOGIN)) {
387 include(KSH_SYSTEM_PROFILE, 0, NULL, 1);
388 if (!Flag(FPRIVILEGED))
389 include(substitute("$HOME/.profile", 0), 0, NULL, 1);
392 if (Flag(FPRIVILEGED))
393 include("/etc/suid_profile", 0, NULL, 1);
394 else if (Flag(FTALKING)) {
395 char *env_file;
397 /* include $ENV */
398 env_file = str_val(global("ENV"));
400 #ifdef DEFAULT_ENV
401 /* If env isn't set, include default environment */
402 if (env_file == null)
403 env_file = DEFAULT_ENV;
404 #endif /* DEFAULT_ENV */
405 env_file = substitute(env_file, DOTILDE);
406 if (*env_file != '\0')
407 include(env_file, 0, NULL, 1);
410 if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
411 restricted = 1;
412 if (restricted) {
413 static const char *const restr_com[] = {
414 "typeset", "-r", "PATH",
415 "ENV", "SHELL",
416 NULL
418 shcomexec((char **) restr_com);
419 /* After typeset command... */
420 Flag(FRESTRICTED) = 1;
422 if (errexit)
423 Flag(FERREXIT) = 1;
425 if (Flag(FTALKING)) {
426 hist_init(s);
427 alarm_init();
428 } else
429 Flag(FTRACKALL) = 1; /* set after ENV */
431 shell(s, true); /* doesn't return */
432 return 0;
435 static void
436 init_username(void)
438 char *p;
439 struct tbl *vp = global("USER");
441 if (vp->flag & ISSET)
442 p = ksheuid == 0 ? "root" : str_val(vp);
443 else
444 p = getlogin();
446 strlcpy(username, p != NULL ? p : "?", sizeof username);
450 include(const char *name, int argc, char **argv, int intr_ok)
452 Source *volatile s = NULL;
453 struct shf *shf;
454 char **volatile old_argv;
455 volatile int old_argc;
456 int i;
458 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
459 if (shf == NULL)
460 return -1;
462 if (argv) {
463 old_argv = genv->loc->argv;
464 old_argc = genv->loc->argc;
465 } else {
466 old_argv = NULL;
467 old_argc = 0;
469 newenv(E_INCL);
470 i = sigsetjmp(genv->jbuf, 0);
471 if (i) {
472 quitenv(s ? s->u.shf : NULL);
473 if (old_argv) {
474 genv->loc->argv = old_argv;
475 genv->loc->argc = old_argc;
477 switch (i) {
478 case LRETURN:
479 case LERROR:
480 return exstat & 0xff; /* see below */
481 case LINTR:
482 /* intr_ok is set if we are including .profile or $ENV.
483 * If user ^C's out, we don't want to kill the shell...
485 if (intr_ok && (exstat - 128) != SIGTERM)
486 return 1;
487 /* FALLTHROUGH */
488 case LEXIT:
489 case LLEAVE:
490 case LSHELL:
491 unwind(i);
492 /* NOTREACHED */
493 default:
494 internal_errorf("%s: %d", __func__, i);
495 /* NOTREACHED */
498 if (argv) {
499 genv->loc->argv = argv;
500 genv->loc->argc = argc;
502 s = pushs(SFILE, ATEMP);
503 s->u.shf = shf;
504 s->file = str_save(name, ATEMP);
505 i = shell(s, false);
506 quitenv(s->u.shf);
507 if (old_argv) {
508 genv->loc->argv = old_argv;
509 genv->loc->argc = old_argc;
511 return i & 0xff; /* & 0xff to ensure value not -1 */
515 * spawn a command into a shell optionally keeping track of line
516 * number.
519 command(const char *comm, int line)
521 Source *s;
523 s = pushs(SSTRING, ATEMP);
524 s->start = s->str = comm;
525 s->line = line;
526 return shell(s, false);
530 * run the commands from the input source, returning status.
533 shell(Source *volatile s, volatile int toplevel)
535 struct op *t;
536 volatile int wastty = s->flags & SF_TTY;
537 volatile int attempts = 13;
538 volatile int interactive = Flag(FTALKING) && toplevel;
539 Source *volatile old_source = source;
540 int i;
542 newenv(E_PARSE);
543 if (interactive)
544 really_exit = 0;
545 i = sigsetjmp(genv->jbuf, 0);
546 if (i) {
547 switch (i) {
548 case LINTR: /* we get here if SIGINT not caught or ignored */
549 case LERROR:
550 case LSHELL:
551 if (interactive) {
552 if (i == LINTR)
553 shellf("\n");
554 /* Reset any eof that was read as part of a
555 * multiline command.
557 if (Flag(FIGNOREEOF) && s->type == SEOF &&
558 wastty)
559 s->type = SSTDIN;
560 /* Used by exit command to get back to
561 * top level shell. Kind of strange since
562 * interactive is set if we are reading from
563 * a tty, but to have stopped jobs, one only
564 * needs FMONITOR set (not FTALKING/SF_TTY)...
566 /* toss any input we have so far */
567 s->start = s->str = null;
568 break;
570 /* FALLTHROUGH */
571 case LEXIT:
572 case LLEAVE:
573 case LRETURN:
574 source = old_source;
575 quitenv(NULL);
576 unwind(i); /* keep on going */
577 /* NOTREACHED */
578 default:
579 source = old_source;
580 quitenv(NULL);
581 internal_errorf("%s: %d", __func__, i);
582 /* NOTREACHED */
586 while (1) {
587 if (trap)
588 runtraps(0);
590 if (s->next == NULL) {
591 if (Flag(FVERBOSE))
592 s->flags |= SF_ECHO;
593 else
594 s->flags &= ~SF_ECHO;
597 if (interactive) {
598 got_sigwinch = 1;
599 j_notify();
600 mcheck();
601 set_prompt(PS1);
604 t = compile(s);
605 if (t != NULL && t->type == TEOF) {
606 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
607 shellf("Use `exit' to leave ksh\n");
608 s->type = SSTDIN;
609 } else if (wastty && !really_exit &&
610 j_stopped_running()) {
611 really_exit = 1;
612 s->type = SSTDIN;
613 } else {
614 /* this for POSIX, which says EXIT traps
615 * shall be taken in the environment
616 * immediately after the last command
617 * executed.
619 if (toplevel)
620 unwind(LEXIT);
621 break;
625 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
626 exstat = execute(t, 0, NULL);
628 if (t != NULL && t->type != TEOF && interactive && really_exit)
629 really_exit = 0;
631 reclaim();
633 quitenv(NULL);
634 source = old_source;
635 return exstat;
638 /* return to closest error handler or shell(), exit if none found */
639 void
640 unwind(int i)
642 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
643 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
644 sigtraps[SIGEXIT_].trap)) {
645 if (trap)
646 runtraps(0);
647 runtrap(&sigtraps[SIGEXIT_]);
648 i = LLEAVE;
649 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
650 if (trap)
651 runtraps(0);
652 runtrap(&sigtraps[SIGERR_]);
653 i = LLEAVE;
655 while (1) {
656 switch (genv->type) {
657 case E_PARSE:
658 case E_FUNC:
659 case E_INCL:
660 case E_LOOP:
661 case E_ERRH:
662 siglongjmp(genv->jbuf, i);
663 /* NOTREACHED */
665 case E_NONE:
666 if (i == LINTR)
667 genv->flags |= EF_FAKE_SIGDIE;
668 /* FALLTHROUGH */
670 default:
671 quitenv(NULL);
673 * quitenv() may have reclaimed the memory
674 * used by source which will end badly when
675 * we jump to a function that expects it to
676 * be valid
678 source = NULL;
683 void
684 newenv(int type)
686 struct env *ep;
688 ep = alloc(sizeof(*ep), ATEMP);
689 ep->type = type;
690 ep->flags = 0;
691 ainit(&ep->area);
692 ep->loc = genv->loc;
693 ep->savefd = NULL;
694 ep->oenv = genv;
695 ep->temps = NULL;
696 genv = ep;
699 void
700 quitenv(struct shf *shf)
702 struct env *ep = genv;
703 int fd;
705 if (ep->oenv && ep->oenv->loc != ep->loc)
706 popblock();
707 if (ep->savefd != NULL) {
708 for (fd = 0; fd < NUFILE; fd++)
709 /* if ep->savefd[fd] < 0, means fd was closed */
710 if (ep->savefd[fd])
711 restfd(fd, ep->savefd[fd]);
712 if (ep->savefd[2]) /* Clear any write errors */
713 shf_reopen(2, SHF_WR, shl_out);
716 /* Bottom of the stack.
717 * Either main shell is exiting or cleanup_parents_env() was called.
719 if (ep->oenv == NULL) {
720 if (ep->type == E_NONE) { /* Main shell exiting? */
721 if (Flag(FTALKING))
722 hist_finish();
723 j_exit();
724 if (ep->flags & EF_FAKE_SIGDIE) {
725 int sig = exstat - 128;
727 /* ham up our death a bit (at&t ksh
728 * only seems to do this for SIGTERM)
729 * Don't do it for SIGQUIT, since we'd
730 * dump a core..
732 if ((sig == SIGINT || sig == SIGTERM) &&
733 getpgrp() == kshpid) {
734 setsig(&sigtraps[sig], SIG_DFL,
735 SS_RESTORE_CURR|SS_FORCE);
736 kill(0, sig);
740 if (shf)
741 shf_close(shf);
742 reclaim();
743 exit(exstat);
745 if (shf)
746 shf_close(shf);
747 reclaim();
749 genv = genv->oenv;
750 afree(ep, ATEMP);
753 /* Called after a fork to cleanup stuff left over from parents environment */
754 void
755 cleanup_parents_env(void)
757 struct env *ep;
758 int fd;
760 /* Don't clean up temporary files - parent will probably need them.
761 * Also, can't easily reclaim memory since variables, etc. could be
762 * anywhere.
765 /* close all file descriptors hiding in savefd */
766 for (ep = genv; ep; ep = ep->oenv) {
767 if (ep->savefd) {
768 for (fd = 0; fd < NUFILE; fd++)
769 if (ep->savefd[fd] > 0)
770 close(ep->savefd[fd]);
771 afree(ep->savefd, &ep->area);
772 ep->savefd = NULL;
775 genv->oenv = NULL;
778 /* Called just before an execve cleanup stuff temporary files */
779 void
780 cleanup_proc_env(void)
782 struct env *ep;
784 for (ep = genv; ep; ep = ep->oenv)
785 remove_temps(ep->temps);
788 /* remove temp files and free ATEMP Area */
789 static void
790 reclaim(void)
792 remove_temps(genv->temps);
793 genv->temps = NULL;
794 afreeall(&genv->area);
797 static void
798 remove_temps(struct temp *tp)
801 for (; tp != NULL; tp = tp->next)
802 if (tp->pid == procpid) {
803 unlink(tp->name);
807 /* Returns true if name refers to a restricted shell */
808 static int
809 is_restricted(char *name)
811 char *p;
813 if ((p = strrchr(name, '/')))
814 name = p + 1;
815 /* accepts rsh, rksh, rpdksh, pdrksh */
816 if (strcmp(name, "rsh") && \
817 strcmp(name, "rksh") && \
818 strcmp(name, "rpdksh") && \
819 strcmp(name, "pdrksh"))
820 return(0);
821 else
822 return(1);