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