1 /* $OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $ */
4 * startup, main loop, environments and error handling
7 #define EXTERN /* define EXTERNs in sh.h */
13 extern char **environ
;
19 static void reclaim(void);
20 static void remove_temps(struct temp
*tp
);
21 static int is_restricted(char *name
);
22 static void init_username(void);
25 * shell initialization
28 static const char initifs
[] = "IFS= \t\n";
30 static const char initsubs
[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
32 static const char *initcoms
[] = {
33 "typeset", "-r", "KSH_VERSION", NULL
,
34 "typeset", "-x", "SHELL", "PATH", "HOME", NULL
,
35 "typeset", "-i", "PPID", NULL
,
36 "typeset", "-i", "OPTIND=1", NULL
,
37 "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL
,
39 /* Standard ksh aliases */
40 "hash=alias -t", /* not "alias -t --": hash -r needs to work */
44 "suspend=kill -STOP $$",
46 "autoload=typeset -fu",
47 "functions=typeset -f",
55 /* Aliases that are builtin commands in at&t */
58 /* this is what at&t ksh seems to track, with the addition of emacs */
60 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
61 "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
66 char username
[_PW_NAME_LEN
+ 1];
68 #define version_param (initcoms[2])
70 /* The shell uses its own variation on argv, to build variables like
72 * If we need to alter argv, allocate a new array first since
73 * modifying the original argv will modify ps output.
76 make_argv(int argc
, char *argv
[])
81 if (strcmp(argv
[0], kshname
) != 0) {
82 nargv
= alloc(sizeof(char *) * (argc
+ 1), &aperm
);
83 nargv
[0] = (char *) kshname
;
84 for (i
= 1; i
< argc
; i
++)
93 main(int argc
, char *argv
[])
99 int restricted
, errexit
;
104 /* make sure argv[] is sane */
106 static const char *empty_argv
[] = {
110 argv
= (char **) empty_argv
;
115 ainit(&aperm
); /* initialize permanent Area */
117 /* set up base environment */
118 memset(&env
, 0, sizeof(env
));
122 newblock(); /* set up global l->vars and l->funs */
124 /* Do this first so output routines (eg, errorf, shellf) can work */
135 /* set up variable and command dictionaries */
136 ktinit(&taliases
, APERM
, 0);
137 ktinit(&aliases
, APERM
, 0);
138 ktinit(&homedirs
, APERM
, 0);
140 /* define shell keywords */
143 /* define built-in commands */
144 ktinit(&builtins
, APERM
, 64); /* must be 2^n (currently 40 builtins) */
145 for (i
= 0; shbuiltins
[i
].name
!= NULL
; i
++)
146 builtin(shbuiltins
[i
].name
, shbuiltins
[i
].func
);
147 for (i
= 0; kshbuiltins
[i
].name
!= NULL
; i
++)
148 builtin(kshbuiltins
[i
].name
, kshbuiltins
[i
].func
);
152 def_path
= _PATH_DEFPATH
;
154 size_t len
= confstr(_CS_PATH
, (char *) 0, 0);
158 confstr(_CS_PATH
, new = alloc(len
+ 1, APERM
), len
+ 1);
163 /* Set PATH to def_path (will set the path global variable).
164 * (import of environment below will probably change this setting).
167 struct tbl
*vp
= global("PATH");
168 /* setstr can't fail here */
169 setstr(vp
, def_path
, KSH_RETURN_ERROR
);
173 /* Turn on nohup by default for now - will change to off
174 * by default once people are aware of its existence
175 * (at&t ksh does not have a nohup option - it always sends
180 /* Turn on brace expansion by default. At&t ksh's that have
181 * alternation always have it on. BUT, posix doesn't have
182 * brace expansion, so set this before setting up FPOSIX
183 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
186 Flag(FBRACEEXPAND
) = 1;
187 #endif /* BRACE_EXPAND */
189 /* set posix flag just before environment so that it will have
190 * exactly the same effect as the POSIXLY_CORRECT environment
191 * variable. If this needs to be done sooner to ensure correct posix
192 * operation, an initial scan of the environment will also have
195 #ifdef POSIXLY_CORRECT
196 change_flag(FPOSIX
, OF_SPECIAL
, 1);
197 #endif /* POSIXLY_CORRECT */
199 /* Check to see if we're /bin/sh. */
200 if (!strcmp(kshname
, "sh") || !strcmp(kshname
, "-sh") ||
201 (strlen(kshname
) >= 3 &&
202 !strcmp(&kshname
[strlen(kshname
) - 3], "/sh"))) {
204 version_param
= "SH_VERSION";
207 /* Set edit mode to emacs by default, may be overridden
208 * by the environment or the user. Also, we want tab completion
209 * on in vi by default. */
210 #if defined(EDIT) && defined(EMACS)
211 change_flag(FEMACS
, OF_SPECIAL
, 1);
212 #endif /* EDIT && EMACS */
213 #if defined(EDIT) && defined(VI)
214 Flag(FVITABCOMPLETE
) = 1;
215 #endif /* EDIT && VI */
217 /* import environment */
219 for (wp
= environ
; *wp
!= NULL
; wp
++)
220 typeset(*wp
, IMPORT
|EXPORT
, 0, 0, 0);
222 kshpid
= procpid
= getpid();
223 typeset(initifs
, 0, 0, 0, 0); /* for security */
225 /* assign default shell variable values */
226 substitute(initsubs
, 0);
228 /* Figure out the current working directory and set $PWD */
230 struct stat s_pwd
, s_dot
;
231 struct tbl
*pwd_v
= global("PWD");
232 char *pwd
= str_val(pwd_v
);
235 /* Try to use existing $PWD if it is valid */
237 stat(pwd
, &s_pwd
) < 0 || stat(".", &s_dot
) < 0 ||
238 s_pwd
.st_dev
!= s_dot
.st_dev
||
239 s_pwd
.st_ino
!= s_dot
.st_ino
)
241 set_current_wd(pwdx
);
243 simplify_path(current_wd
);
244 /* Only set pwd if we know where we are or if it had a
247 if (current_wd
[0] || pwd
!= null
)
248 /* setstr can't fail here */
249 setstr(pwd_v
, current_wd
, KSH_RETURN_ERROR
);
252 setint(global("PPID"), (long) ppid
);
253 /* setstr can't fail here */
254 setstr(global(version_param
), ksh_version
, KSH_RETURN_ERROR
);
256 /* execute initialization statements */
257 for (wp
= (char**) initcoms
; *wp
!= NULL
; wp
++) {
259 for (; *wp
!= NULL
; wp
++)
266 safe_prompt
= ksheuid
? "$ " : "# ";
268 struct tbl
*vp
= global("PS1");
270 /* Set PS1 if it isn't set, or we are root and prompt doesn't
271 * contain a # or \$ (only in ksh mode).
273 if (!(vp
->flag
& ISSET
) ||
274 (!ksheuid
&& !strchr(str_val(vp
), '#') &&
275 (Flag(FSH
) || !strstr(str_val(vp
), "\\$"))))
276 /* setstr can't fail here */
277 setstr(vp
, safe_prompt
, KSH_RETURN_ERROR
);
280 /* Set this before parsing arguments */
281 Flag(FPRIVILEGED
) = getuid() != ksheuid
|| getgid() != getegid();
283 /* this to note if monitor is set on command line (see below) */
284 Flag(FMONITOR
) = 127;
285 argi
= parse_args(argv
, OF_CMDLINE
, (int *) 0);
289 if (Flag(FCOMMAND
)) {
290 s
= pushs(SSTRING
, ATEMP
);
291 if (!(s
->start
= s
->str
= argv
[argi
++]))
292 errorf("-c requires an argument");
294 kshname
= argv
[argi
++];
295 } else if (argi
< argc
&& !Flag(FSTDIN
)) {
296 s
= pushs(SFILE
, ATEMP
);
297 s
->file
= argv
[argi
++];
298 s
->u
.shf
= shf_open(s
->file
, O_RDONLY
, 0, SHF_MAPHI
|SHF_CLEXEC
);
299 if (s
->u
.shf
== NULL
) {
300 exstat
= 127; /* POSIX */
301 errorf("%s: %s", s
->file
, strerror(errno
));
306 s
= pushs(SSTDIN
, ATEMP
);
308 s
->u
.shf
= shf_fdopen(0, SHF_RD
| can_seek(0),
310 if (isatty(0) && isatty(2)) {
311 Flag(FTALKING
) = Flag(FTALKING_I
) = 1;
312 /* The following only if isatty(0) */
314 s
->u
.shf
->flags
|= SHF_INTERRUPT
;
315 s
->file
= (char *) 0;
319 /* This bizarreness is mandated by POSIX */
323 if (fstat(0, &s_stdin
) >= 0 && S_ISCHR(s_stdin
.st_mode
) &&
328 /* initialize job control */
329 i
= Flag(FMONITOR
) != 127;
333 /* Do this after j_init(), as tty_fd is not initialized 'til then */
339 l
->argv
= make_argv(argc
- (argi
- 1), &argv
[argi
- 1]);
340 l
->argc
= argc
- argi
;
343 /* Disable during .profile/ENV reading */
344 restricted
= Flag(FRESTRICTED
);
345 Flag(FRESTRICTED
) = 0;
346 errexit
= Flag(FERREXIT
);
349 /* Do this before profile/$ENV so that if it causes problems in them,
350 * user will know why things broke.
352 if (!current_wd
[0] && Flag(FTALKING
))
353 warningf(false, "Cannot determine current working directory");
356 include(KSH_SYSTEM_PROFILE
, 0, (char **) 0, 1);
357 if (!Flag(FPRIVILEGED
))
358 include(substitute("$HOME/.profile", 0), 0,
362 if (Flag(FPRIVILEGED
))
363 include("/etc/suid_profile", 0, (char **) 0, 1);
364 else if (Flag(FTALKING
)) {
368 env_file
= str_val(global("ENV"));
371 /* If env isn't set, include default environment */
372 if (env_file
== null
)
373 env_file
= DEFAULT_ENV
;
374 #endif /* DEFAULT_ENV */
375 env_file
= substitute(env_file
, DOTILDE
);
376 if (*env_file
!= '\0')
377 include(env_file
, 0, (char **) 0, 1);
380 if (is_restricted(argv
[0]) || is_restricted(str_val(global("SHELL"))))
383 static const char *const restr_com
[] = {
384 "typeset", "-r", "PATH",
388 shcomexec((char **) restr_com
);
389 /* After typeset command... */
390 Flag(FRESTRICTED
) = 1;
395 if (Flag(FTALKING
)) {
399 Flag(FTRACKALL
) = 1; /* set after ENV */
401 shell(s
, true); /* doesn't return */
409 struct tbl
*vp
= global("USER");
411 if (vp
->flag
& ISSET
)
412 p
= ksheuid
== 0 ? "root" : str_val(vp
);
416 strlcpy(username
, p
!= NULL
? p
: "?", sizeof username
);
420 include(const char *name
, int argc
, char **argv
, int intr_ok
)
422 Source
*volatile s
= NULL
;
424 char **volatile old_argv
;
425 volatile int old_argc
;
428 shf
= shf_open(name
, O_RDONLY
, 0, SHF_MAPHI
|SHF_CLEXEC
);
433 old_argv
= e
->loc
->argv
;
434 old_argc
= e
->loc
->argc
;
436 old_argv
= (char **) 0;
440 i
= sigsetjmp(e
->jbuf
, 0);
442 quitenv(s
? s
->u
.shf
: NULL
);
444 e
->loc
->argv
= old_argv
;
445 e
->loc
->argc
= old_argc
;
450 return exstat
& 0xff; /* see below */
452 /* intr_ok is set if we are including .profile or $ENV.
453 * If user ^C's out, we don't want to kill the shell...
455 if (intr_ok
&& (exstat
- 128) != SIGTERM
)
464 internal_errorf(1, "include: %d", i
);
472 s
= pushs(SFILE
, ATEMP
);
474 s
->file
= str_save(name
, ATEMP
);
478 e
->loc
->argv
= old_argv
;
479 e
->loc
->argc
= old_argc
;
481 return i
& 0xff; /* & 0xff to ensure value not -1 */
485 * spawn a command into a shell optionally keeping track of line
489 command(const char *comm
, int line
)
493 s
= pushs(SSTRING
, ATEMP
);
494 s
->start
= s
->str
= comm
;
496 return shell(s
, false);
500 * run the commands from the input source, returning status.
503 shell(Source
*volatile s
, volatile int toplevel
)
506 volatile int wastty
= s
->flags
& SF_TTY
;
507 volatile int attempts
= 13;
508 volatile int interactive
= Flag(FTALKING
) && toplevel
;
509 Source
*volatile old_source
= source
;
515 i
= sigsetjmp(e
->jbuf
, 0);
518 case LINTR
: /* we get here if SIGINT not caught or ignored */
524 /* Reset any eof that was read as part of a
527 if (Flag(FIGNOREEOF
) && s
->type
== SEOF
&&
530 /* Used by exit command to get back to
531 * top level shell. Kind of strange since
532 * interactive is set if we are reading from
533 * a tty, but to have stopped jobs, one only
534 * needs FMONITOR set (not FTALKING/SF_TTY)...
536 /* toss any input we have so far */
537 s
->start
= s
->str
= null
;
546 unwind(i
); /* keep on going */
551 internal_errorf(1, "shell: %d", i
);
560 if (s
->next
== NULL
) {
564 s
->flags
&= ~SF_ECHO
;
575 if (t
!= NULL
&& t
->type
== TEOF
) {
576 if (wastty
&& Flag(FIGNOREEOF
) && --attempts
> 0) {
577 shellf("Use `exit' to leave ksh\n");
579 } else if (wastty
&& !really_exit
&&
580 j_stopped_running()) {
584 /* this for POSIX, which says EXIT traps
585 * shall be taken in the environment
586 * immediately after the last command
595 if (t
&& (!Flag(FNOEXEC
) || (s
->flags
& SF_TTY
)))
596 exstat
= execute(t
, 0, NULL
);
598 if (t
!= NULL
&& t
->type
!= TEOF
&& interactive
&& really_exit
)
608 /* return to closest error handler or shell(), exit if none found */
612 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
613 if (i
== LEXIT
|| (Flag(FERREXIT
) && (i
== LERROR
|| i
== LINTR
) &&
614 sigtraps
[SIGEXIT_
].trap
)) {
617 runtrap(&sigtraps
[SIGEXIT_
]);
619 } else if (Flag(FERREXIT
) && (i
== LERROR
|| i
== LINTR
)) {
622 runtrap(&sigtraps
[SIGERR_
]);
632 siglongjmp(e
->jbuf
, i
);
637 e
->flags
|= EF_FAKE_SIGDIE
;
651 ep
= (struct env
*) alloc(sizeof(*ep
), ATEMP
);
663 quitenv(struct shf
*shf
)
668 if (ep
->oenv
&& ep
->oenv
->loc
!= ep
->loc
)
670 if (ep
->savefd
!= NULL
) {
671 for (fd
= 0; fd
< NUFILE
; fd
++)
672 /* if ep->savefd[fd] < 0, means fd was closed */
674 restfd(fd
, ep
->savefd
[fd
]);
675 if (ep
->savefd
[2]) /* Clear any write errors */
676 shf_reopen(2, SHF_WR
, shl_out
);
679 /* Bottom of the stack.
680 * Either main shell is exiting or cleanup_parents_env() was called.
682 if (ep
->oenv
== NULL
) {
683 if (ep
->type
== E_NONE
) { /* Main shell exiting? */
687 if (ep
->flags
& EF_FAKE_SIGDIE
) {
688 int sig
= exstat
- 128;
690 /* ham up our death a bit (at&t ksh
691 * only seems to do this for SIGTERM)
692 * Don't do it for SIGQUIT, since we'd
695 if ((sig
== SIGINT
|| sig
== SIGTERM
) &&
696 getpgrp() == kshpid
) {
697 setsig(&sigtraps
[sig
], SIG_DFL
,
698 SS_RESTORE_CURR
|SS_FORCE
);
716 /* Called after a fork to cleanup stuff left over from parents environment */
718 cleanup_parents_env(void)
723 /* Don't clean up temporary files - parent will probably need them.
724 * Also, can't easily reclaim memory since variables, etc. could be
728 /* close all file descriptors hiding in savefd */
729 for (ep
= e
; ep
; ep
= ep
->oenv
) {
731 for (fd
= 0; fd
< NUFILE
; fd
++)
732 if (ep
->savefd
[fd
] > 0)
733 close(ep
->savefd
[fd
]);
734 afree(ep
->savefd
, &ep
->area
);
735 ep
->savefd
= (short *) 0;
738 e
->oenv
= (struct env
*) 0;
741 /* Called just before an execve cleanup stuff temporary files */
743 cleanup_proc_env(void)
747 for (ep
= e
; ep
; ep
= ep
->oenv
)
748 remove_temps(ep
->temps
);
751 /* remove temp files and free ATEMP Area */
755 remove_temps(e
->temps
);
761 remove_temps(struct temp
*tp
)
764 for (; tp
!= NULL
; tp
= tp
->next
)
765 if (tp
->pid
== procpid
) {
770 /* Returns true if name refers to a restricted shell */
772 is_restricted(char *name
)
776 if ((p
= strrchr(name
, '/')))
778 /* accepts rsh, rksh, rpdksh, pdrksh, etc. */
779 return (p
= strchr(name
, 'r')) && strstr(p
, "sh");