1 1.197 kre /* $NetBSD: eval.c,v 1.197 2024/11/11 22:57:42 kre Exp $ */ 2 1.19 cgd 3 1.1 cgd /*- 4 1.7 jtc * Copyright (c) 1993 5 1.7 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.74 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.36 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.19 cgd #if 0 38 1.26 christos static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 39 1.19 cgd #else 40 1.197 kre __RCSID("$NetBSD: eval.c,v 1.197 2024/11/11 22:57:42 kre Exp $"); 41 1.24 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.90 tron #include <stdbool.h> 45 1.70 dsl #include <stdlib.h> 46 1.21 christos #include <signal.h> 47 1.69 agc #include <stdio.h> 48 1.116 christos #include <string.h> 49 1.100 christos #include <errno.h> 50 1.105 dsl #include <limits.h> 51 1.21 christos #include <unistd.h> 52 1.76 dsl #include <sys/fcntl.h> 53 1.129 christos #include <sys/stat.h> 54 1.68 christos #include <sys/times.h> 55 1.71 rafal #include <sys/param.h> 56 1.61 christos #include <sys/types.h> 57 1.61 christos #include <sys/wait.h> 58 1.70 dsl #include <sys/sysctl.h> 59 1.61 christos 60 1.1 cgd /* 61 1.1 cgd * Evaluate a command. 62 1.1 cgd */ 63 1.1 cgd 64 1.1 cgd #include "shell.h" 65 1.1 cgd #include "nodes.h" 66 1.1 cgd #include "syntax.h" 67 1.1 cgd #include "expand.h" 68 1.1 cgd #include "parser.h" 69 1.1 cgd #include "jobs.h" 70 1.1 cgd #include "eval.h" 71 1.1 cgd #include "builtins.h" 72 1.1 cgd #include "options.h" 73 1.1 cgd #include "exec.h" 74 1.1 cgd #include "redir.h" 75 1.1 cgd #include "input.h" 76 1.1 cgd #include "output.h" 77 1.1 cgd #include "trap.h" 78 1.1 cgd #include "var.h" 79 1.1 cgd #include "memalloc.h" 80 1.1 cgd #include "error.h" 81 1.21 christos #include "show.h" 82 1.1 cgd #include "mystring.h" 83 1.64 christos #include "main.h" 84 1.35 christos #ifndef SMALL 85 1.114 christos #include "nodenames.h" 86 1.7 jtc #include "myhistedit.h" 87 1.11 cgd #endif 88 1.1 cgd 89 1.1 cgd 90 1.168 kre STATIC struct skipsave s_k_i_p; 91 1.168 kre #define evalskip (s_k_i_p.state) 92 1.168 kre #define skipcount (s_k_i_p.count) 93 1.168 kre 94 1.109 christos STATIC int loopnest; /* current loop nesting level */ 95 1.109 christos STATIC int funcnest; /* depth of function calls */ 96 1.103 christos STATIC int builtin_flags; /* evalcommand flags for builtins */ 97 1.109 christos /* 98 1.109 christos * Base function nesting level inside a dot command. Set to 0 initially 99 1.189 kre * and to (funcnest + 1) before every dot command to enable 100 1.109 christos * 1) detection of being in a file sourced by a dot command and 101 1.109 christos * 2) counting of function nesting in that file for the implementation 102 1.109 christos * of the return command. 103 1.109 christos * The value is reset to its previous value after the dot command. 104 1.109 christos */ 105 1.109 christos STATIC int dot_funcnest; 106 1.1 cgd 107 1.1 cgd 108 1.89 matt const char *commandname; 109 1.1 cgd struct strlist *cmdenviron; 110 1.1 cgd int exitstatus; /* exit status of last command */ 111 1.68 christos int back_exitstatus; /* exit status of backquoted command */ 112 1.1 cgd 113 1.1 cgd 114 1.68 christos STATIC void evalloop(union node *, int); 115 1.68 christos STATIC void evalfor(union node *, int); 116 1.68 christos STATIC void evalcase(union node *, int); 117 1.68 christos STATIC void evalsubshell(union node *, int); 118 1.68 christos STATIC void expredir(union node *); 119 1.159 kre STATIC void evalredir(union node *, int); 120 1.68 christos STATIC void evalpipe(union node *); 121 1.68 christos STATIC void evalcommand(union node *, int, struct backcmd *); 122 1.68 christos STATIC void prehash(union node *); 123 1.1 cgd 124 1.109 christos STATIC char *find_dot_file(char *); 125 1.1 cgd 126 1.1 cgd /* 127 1.1 cgd * Called to reset things after an exception. 128 1.1 cgd */ 129 1.1 cgd 130 1.1 cgd #ifdef mkinit 131 1.1 cgd INCLUDE "eval.h" 132 1.1 cgd 133 1.1 cgd RESET { 134 1.109 christos reset_eval(); 135 1.1 cgd } 136 1.1 cgd 137 1.1 cgd SHELLPROC { 138 1.1 cgd exitstatus = 0; 139 1.1 cgd } 140 1.1 cgd #endif 141 1.1 cgd 142 1.109 christos void 143 1.109 christos reset_eval(void) 144 1.109 christos { 145 1.109 christos evalskip = SKIPNONE; 146 1.109 christos dot_funcnest = 0; 147 1.109 christos loopnest = 0; 148 1.109 christos funcnest = 0; 149 1.109 christos } 150 1.109 christos 151 1.76 dsl static int 152 1.76 dsl sh_pipe(int fds[2]) 153 1.76 dsl { 154 1.76 dsl int nfd; 155 1.76 dsl 156 1.76 dsl if (pipe(fds)) 157 1.76 dsl return -1; 158 1.76 dsl 159 1.76 dsl if (fds[0] < 3) { 160 1.76 dsl nfd = fcntl(fds[0], F_DUPFD, 3); 161 1.76 dsl if (nfd != -1) { 162 1.76 dsl close(fds[0]); 163 1.76 dsl fds[0] = nfd; 164 1.76 dsl } 165 1.76 dsl } 166 1.76 dsl 167 1.76 dsl if (fds[1] < 3) { 168 1.76 dsl nfd = fcntl(fds[1], F_DUPFD, 3); 169 1.76 dsl if (nfd != -1) { 170 1.76 dsl close(fds[1]); 171 1.76 dsl fds[1] = nfd; 172 1.76 dsl } 173 1.76 dsl } 174 1.76 dsl return 0; 175 1.76 dsl } 176 1.1 cgd 177 1.1 cgd 178 1.1 cgd /* 179 1.187 msaitoh * The eval command. 180 1.1 cgd */ 181 1.1 cgd 182 1.16 cgd int 183 1.68 christos evalcmd(int argc, char **argv) 184 1.1 cgd { 185 1.148 kre char *p; 186 1.148 kre char *concat; 187 1.148 kre char **ap; 188 1.148 kre 189 1.148 kre if (argc > 1) { 190 1.148 kre p = argv[1]; 191 1.148 kre if (argc > 2) { 192 1.148 kre STARTSTACKSTR(concat); 193 1.148 kre ap = argv + 2; 194 1.148 kre for (;;) { 195 1.148 kre while (*p) 196 1.148 kre STPUTC(*p++, concat); 197 1.148 kre if ((p = *ap++) == NULL) 198 1.148 kre break; 199 1.148 kre STPUTC(' ', concat); 200 1.148 kre } 201 1.148 kre STPUTC('\0', concat); 202 1.148 kre p = grabstackstr(concat); 203 1.148 kre } 204 1.148 kre evalstring(p, builtin_flags & EV_TESTED); 205 1.148 kre } else 206 1.133 kre exitstatus = 0; 207 1.148 kre return exitstatus; 208 1.1 cgd } 209 1.1 cgd 210 1.1 cgd 211 1.1 cgd /* 212 1.1 cgd * Execute a command or commands contained in a string. 213 1.1 cgd */ 214 1.1 cgd 215 1.1 cgd void 216 1.193 kre evalstring(const char *s, int flag) 217 1.68 christos { 218 1.1 cgd union node *n; 219 1.1 cgd struct stackmark smark; 220 1.159 kre int last; 221 1.159 kre int any; 222 1.159 kre 223 1.159 kre last = flag & EV_EXIT; 224 1.159 kre flag &= ~EV_EXIT; 225 1.1 cgd 226 1.1 cgd setstackmark(&smark); 227 1.143 kre setinputstring(s, 1, line_number); 228 1.64 christos 229 1.159 kre any = 0; /* to determine if exitstatus will have been set */ 230 1.1 cgd while ((n = parsecmd(0)) != NEOF) { 231 1.148 kre XTRACE(DBG_EVAL, ("evalstring: "), showtree(n)); 232 1.159 kre if (n && nflag == 0) { 233 1.159 kre if (last && at_eof()) 234 1.159 kre evaltree(n, flag | EV_EXIT); 235 1.159 kre else 236 1.159 kre evaltree(n, flag); 237 1.159 kre any = 1; 238 1.163 kre if (evalskip) 239 1.163 kre break; 240 1.159 kre } 241 1.160 kre rststackmark(&smark); 242 1.1 cgd } 243 1.1 cgd popfile(); 244 1.1 cgd popstackmark(&smark); 245 1.159 kre if (!any) 246 1.159 kre exitstatus = 0; 247 1.159 kre if (last) 248 1.159 kre exraise(EXEXIT); 249 1.1 cgd } 250 1.1 cgd 251 1.1 cgd 252 1.1 cgd 253 1.1 cgd /* 254 1.1 cgd * Evaluate a parse tree. The value is left in the global variable 255 1.1 cgd * exitstatus. 256 1.1 cgd */ 257 1.1 cgd 258 1.1 cgd void 259 1.68 christos evaltree(union node *n, int flags) 260 1.17 cgd { 261 1.90 tron bool do_etest; 262 1.136 kre int sflags = flags & ~EV_EXIT; 263 1.159 kre union node *next; 264 1.159 kre struct stackmark smark; 265 1.90 tron 266 1.90 tron do_etest = false; 267 1.115 christos if (n == NULL || nflag) { 268 1.148 kre VTRACE(DBG_EVAL, ("evaltree(%s) called\n", 269 1.148 kre n == NULL ? "NULL" : "-n")); 270 1.115 christos if (nflag == 0) 271 1.115 christos exitstatus = 0; 272 1.159 kre goto out2; 273 1.1 cgd } 274 1.159 kre 275 1.159 kre setstackmark(&smark); 276 1.159 kre do { 277 1.35 christos #ifndef SMALL 278 1.159 kre displayhist = 1; /* show history substitutions done with fc */ 279 1.10 cgd #endif 280 1.159 kre next = NULL; 281 1.159 kre CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n", 282 1.159 kre getpid(), n, NODETYPENAME(n->type), n->type, flags)); 283 1.181 kre /* 284 1.168 kre if (n->type != NCMD && traps_invalid) 285 1.168 kre free_traps(); 286 1.181 kre */ 287 1.159 kre switch (n->type) { 288 1.159 kre case NSEMI: 289 1.159 kre evaltree(n->nbinary.ch1, sflags); 290 1.159 kre if (nflag || evalskip) 291 1.159 kre goto out1; 292 1.159 kre next = n->nbinary.ch2; 293 1.159 kre break; 294 1.159 kre case NAND: 295 1.159 kre evaltree(n->nbinary.ch1, EV_TESTED); 296 1.159 kre if (nflag || evalskip || exitstatus != 0) 297 1.159 kre goto out1; 298 1.159 kre next = n->nbinary.ch2; 299 1.159 kre break; 300 1.159 kre case NOR: 301 1.159 kre evaltree(n->nbinary.ch1, EV_TESTED); 302 1.159 kre if (nflag || evalskip || exitstatus == 0) 303 1.159 kre goto out1; 304 1.159 kre next = n->nbinary.ch2; 305 1.159 kre break; 306 1.159 kre case NREDIR: 307 1.181 kre if (traps_invalid) 308 1.181 kre free_traps(); 309 1.159 kre evalredir(n, flags); 310 1.159 kre break; 311 1.159 kre case NSUBSHELL: 312 1.159 kre evalsubshell(n, flags); 313 1.159 kre do_etest = !(flags & EV_TESTED); 314 1.159 kre break; 315 1.159 kre case NBACKGND: 316 1.181 kre if (traps_invalid) 317 1.181 kre free_traps(); 318 1.159 kre evalsubshell(n, flags); 319 1.159 kre break; 320 1.159 kre case NIF: { 321 1.181 kre if (traps_invalid) 322 1.181 kre free_traps(); 323 1.159 kre evaltree(n->nif.test, EV_TESTED); 324 1.159 kre if (nflag || evalskip) 325 1.159 kre goto out1; 326 1.159 kre if (exitstatus == 0) 327 1.159 kre next = n->nif.ifpart; 328 1.159 kre else if (n->nif.elsepart) 329 1.159 kre next = n->nif.elsepart; 330 1.159 kre else 331 1.159 kre exitstatus = 0; 332 1.159 kre break; 333 1.151 kre } 334 1.159 kre case NWHILE: 335 1.159 kre case NUNTIL: 336 1.181 kre if (traps_invalid) 337 1.181 kre free_traps(); 338 1.159 kre evalloop(n, sflags); 339 1.159 kre break; 340 1.159 kre case NFOR: 341 1.181 kre if (traps_invalid) 342 1.181 kre free_traps(); 343 1.159 kre evalfor(n, sflags); 344 1.159 kre break; 345 1.159 kre case NCASE: 346 1.181 kre if (traps_invalid) 347 1.181 kre free_traps(); 348 1.159 kre evalcase(n, sflags); 349 1.159 kre break; 350 1.159 kre case NDEFUN: 351 1.181 kre if (traps_invalid) 352 1.181 kre free_traps(); 353 1.159 kre CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n", 354 1.159 kre n->narg.text, n->narg.lineno, 355 1.159 kre fnline1 ? " LINENO=1" : "")); 356 1.159 kre defun(n->narg.text, n->narg.next, n->narg.lineno); 357 1.29 pk exitstatus = 0; 358 1.159 kre break; 359 1.159 kre case NNOT: 360 1.159 kre evaltree(n->nnot.com, EV_TESTED); 361 1.159 kre exitstatus = !exitstatus; 362 1.159 kre break; 363 1.159 kre case NDNOT: 364 1.159 kre evaltree(n->nnot.com, EV_TESTED); 365 1.159 kre if (exitstatus != 0) 366 1.159 kre exitstatus = 1; 367 1.159 kre break; 368 1.159 kre case NPIPE: 369 1.181 kre if (traps_invalid) 370 1.181 kre free_traps(); 371 1.159 kre evalpipe(n); 372 1.159 kre do_etest = !(flags & EV_TESTED); 373 1.159 kre break; 374 1.159 kre case NCMD: 375 1.159 kre evalcommand(n, flags, NULL); 376 1.159 kre do_etest = !(flags & EV_TESTED); 377 1.159 kre break; 378 1.159 kre default: 379 1.115 christos #ifdef NODETYPENAME 380 1.159 kre out1fmt("Node type = %d(%s)\n", 381 1.159 kre n->type, NODETYPENAME(n->type)); 382 1.115 christos #else 383 1.159 kre out1fmt("Node type = %d\n", n->type); 384 1.115 christos #endif 385 1.159 kre flushout(&output); 386 1.159 kre break; 387 1.159 kre } 388 1.159 kre n = next; 389 1.160 kre rststackmark(&smark); 390 1.159 kre } while(n != NULL); 391 1.159 kre out1: 392 1.159 kre popstackmark(&smark); 393 1.159 kre out2: 394 1.1 cgd if (pendingsigs) 395 1.1 cgd dotrap(); 396 1.159 kre if (eflag && exitstatus != 0 && do_etest) 397 1.1 cgd exitshell(exitstatus); 398 1.159 kre if (flags & EV_EXIT) 399 1.159 kre exraise(EXEXIT); 400 1.1 cgd } 401 1.1 cgd 402 1.1 cgd 403 1.1 cgd STATIC void 404 1.68 christos evalloop(union node *n, int flags) 405 1.22 christos { 406 1.1 cgd int status; 407 1.1 cgd 408 1.1 cgd loopnest++; 409 1.1 cgd status = 0; 410 1.114 christos 411 1.148 kre CTRACE(DBG_EVAL, ("evalloop %s:", NODETYPENAME(n->type))); 412 1.148 kre VXTRACE(DBG_EVAL, (" "), showtree(n->nbinary.ch1)); 413 1.148 kre VXTRACE(DBG_EVAL, ("evalloop do: "), showtree(n->nbinary.ch2)); 414 1.148 kre VTRACE(DBG_EVAL, ("evalloop done\n")); 415 1.148 kre CTRACE(DBG_EVAL, ("\n")); 416 1.114 christos 417 1.1 cgd for (;;) { 418 1.158 kre evaltree(n->nbinary.ch1, EV_TESTED); 419 1.115 christos if (nflag) 420 1.115 christos break; 421 1.1 cgd if (evalskip) { 422 1.137 kre skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 423 1.109 christos evalskip = SKIPNONE; 424 1.1 cgd continue; 425 1.1 cgd } 426 1.1 cgd if (evalskip == SKIPBREAK && --skipcount <= 0) 427 1.109 christos evalskip = SKIPNONE; 428 1.175 kre if (evalskip == SKIPFUNC || evalskip == SKIPFILE) 429 1.175 kre status = exitstatus; 430 1.1 cgd break; 431 1.1 cgd } 432 1.1 cgd if (n->type == NWHILE) { 433 1.1 cgd if (exitstatus != 0) 434 1.1 cgd break; 435 1.1 cgd } else { 436 1.1 cgd if (exitstatus == 0) 437 1.1 cgd break; 438 1.1 cgd } 439 1.158 kre evaltree(n->nbinary.ch2, flags & EV_TESTED); 440 1.1 cgd status = exitstatus; 441 1.1 cgd if (evalskip) 442 1.1 cgd goto skipping; 443 1.1 cgd } 444 1.1 cgd loopnest--; 445 1.1 cgd exitstatus = status; 446 1.1 cgd } 447 1.1 cgd 448 1.1 cgd 449 1.1 cgd 450 1.1 cgd STATIC void 451 1.68 christos evalfor(union node *n, int flags) 452 1.22 christos { 453 1.1 cgd struct arglist arglist; 454 1.1 cgd union node *argp; 455 1.1 cgd struct strlist *sp; 456 1.1 cgd struct stackmark smark; 457 1.115 christos int status; 458 1.115 christos 459 1.115 christos status = nflag ? exitstatus : 0; 460 1.1 cgd 461 1.1 cgd setstackmark(&smark); 462 1.1 cgd arglist.lastp = &arglist.list; 463 1.1 cgd for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 464 1.78 dsl expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 465 1.1 cgd if (evalskip) 466 1.1 cgd goto out; 467 1.1 cgd } 468 1.1 cgd *arglist.lastp = NULL; 469 1.1 cgd 470 1.1 cgd loopnest++; 471 1.1 cgd for (sp = arglist.list ; sp ; sp = sp->next) { 472 1.184 kre line_number = n->nfor.lineno; 473 1.131 kre if (xflag) { 474 1.153 kre outxstr(expandstr(ps4val(), line_number)); 475 1.153 kre outxstr("for "); 476 1.153 kre outxstr(n->nfor.var); 477 1.153 kre outxc('='); 478 1.153 kre outxshstr(sp->text); 479 1.153 kre outxc('\n'); 480 1.153 kre flushout(outx); 481 1.131 kre } 482 1.131 kre 483 1.1 cgd setvar(n->nfor.var, sp->text, 0); 484 1.158 kre evaltree(n->nfor.body, flags & EV_TESTED); 485 1.68 christos status = exitstatus; 486 1.115 christos if (nflag) 487 1.115 christos break; 488 1.1 cgd if (evalskip) { 489 1.1 cgd if (evalskip == SKIPCONT && --skipcount <= 0) { 490 1.109 christos evalskip = SKIPNONE; 491 1.1 cgd continue; 492 1.1 cgd } 493 1.1 cgd if (evalskip == SKIPBREAK && --skipcount <= 0) 494 1.109 christos evalskip = SKIPNONE; 495 1.1 cgd break; 496 1.1 cgd } 497 1.1 cgd } 498 1.1 cgd loopnest--; 499 1.68 christos exitstatus = status; 500 1.148 kre out: 501 1.1 cgd popstackmark(&smark); 502 1.1 cgd } 503 1.1 cgd 504 1.1 cgd 505 1.1 cgd 506 1.1 cgd STATIC void 507 1.68 christos evalcase(union node *n, int flags) 508 1.16 cgd { 509 1.134 kre union node *cp, *ncp; 510 1.1 cgd union node *patp; 511 1.1 cgd struct arglist arglist; 512 1.1 cgd struct stackmark smark; 513 1.68 christos int status = 0; 514 1.1 cgd 515 1.1 cgd setstackmark(&smark); 516 1.1 cgd arglist.lastp = &arglist.list; 517 1.143 kre line_number = n->ncase.lineno; 518 1.7 jtc expandarg(n->ncase.expr, &arglist, EXP_TILDE); 519 1.134 kre for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 520 1.134 kre for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 521 1.143 kre line_number = patp->narg.lineno; 522 1.1 cgd if (casematch(patp, arglist.list->text)) { 523 1.134 kre while (cp != NULL && evalskip == 0 && 524 1.134 kre nflag == 0) { 525 1.134 kre if (cp->type == NCLISTCONT) 526 1.134 kre ncp = cp->nclist.next; 527 1.134 kre else 528 1.134 kre ncp = NULL; 529 1.143 kre line_number = cp->nclist.lineno; 530 1.158 kre evaltree(cp->nclist.body, flags); 531 1.68 christos status = exitstatus; 532 1.134 kre cp = ncp; 533 1.1 cgd } 534 1.1 cgd goto out; 535 1.1 cgd } 536 1.1 cgd } 537 1.1 cgd } 538 1.134 kre out: 539 1.68 christos exitstatus = status; 540 1.1 cgd popstackmark(&smark); 541 1.1 cgd } 542 1.1 cgd 543 1.1 cgd 544 1.1 cgd 545 1.1 cgd /* 546 1.1 cgd * Kick off a subshell to evaluate a tree. 547 1.1 cgd */ 548 1.1 cgd 549 1.1 cgd STATIC void 550 1.68 christos evalsubshell(union node *n, int flags) 551 1.16 cgd { 552 1.159 kre struct job *jp= NULL; 553 1.1 cgd int backgnd = (n->type == NBACKGND); 554 1.1 cgd 555 1.1 cgd expredir(n->nredir.redirect); 556 1.151 kre if (xflag && n->nredir.redirect) { 557 1.151 kre union node *rn; 558 1.151 kre 559 1.153 kre outxstr(expandstr(ps4val(), line_number)); 560 1.153 kre outxstr("using redirections:"); 561 1.151 kre for (rn = n->nredir.redirect; rn; rn = rn->nfile.next) 562 1.153 kre (void) outredir(outx, rn, ' '); 563 1.159 kre outxstr(" do subshell ("/*)*/); 564 1.159 kre if (backgnd) 565 1.159 kre outxstr(/*(*/") &"); 566 1.159 kre outxc('\n'); 567 1.153 kre flushout(outx); 568 1.151 kre } 569 1.172 kre INTOFF; 570 1.182 kre if ((!backgnd && flags & EV_EXIT && !have_traps() && !anyjobs()) || 571 1.159 kre forkshell(jp = makejob(n, 1), n, backgnd?FORK_BG:FORK_FG) == 0) { 572 1.1 cgd if (backgnd) 573 1.1 cgd flags &=~ EV_TESTED; 574 1.177 kre INTON; 575 1.119 christos redirect(n->nredir.redirect, REDIR_KEEP); 576 1.159 kre evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 577 1.192 kre } else if (backgnd) { 578 1.192 kre jobstarted(jp); 579 1.172 kre exitstatus = 0; 580 1.192 kre } else 581 1.159 kre exitstatus = waitforjob(jp); 582 1.172 kre INTON; 583 1.159 kre 584 1.151 kre if (!backgnd && xflag && n->nredir.redirect) { 585 1.153 kre outxstr(expandstr(ps4val(), line_number)); 586 1.159 kre outxstr(/*(*/") done subshell\n"); 587 1.153 kre flushout(outx); 588 1.151 kre } 589 1.1 cgd } 590 1.1 cgd 591 1.1 cgd 592 1.1 cgd 593 1.1 cgd /* 594 1.1 cgd * Compute the names of the files in a redirection list. 595 1.1 cgd */ 596 1.1 cgd 597 1.1 cgd STATIC void 598 1.68 christos expredir(union node *n) 599 1.22 christos { 600 1.34 tls union node *redir; 601 1.1 cgd 602 1.1 cgd for (redir = n ; redir ; redir = redir->nfile.next) { 603 1.14 jtc struct arglist fn; 604 1.120 christos 605 1.14 jtc fn.lastp = &fn.list; 606 1.14 jtc switch (redir->type) { 607 1.45 christos case NFROMTO: 608 1.14 jtc case NFROM: 609 1.14 jtc case NTO: 610 1.59 christos case NCLOBBER: 611 1.14 jtc case NAPPEND: 612 1.7 jtc expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 613 1.1 cgd redir->nfile.expfname = fn.list->text; 614 1.14 jtc break; 615 1.14 jtc case NFROMFD: 616 1.14 jtc case NTOFD: 617 1.14 jtc if (redir->ndup.vname) { 618 1.149 kre expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); 619 1.14 jtc fixredir(redir, fn.list->text, 1); 620 1.14 jtc } 621 1.14 jtc break; 622 1.186 kre case NHERE: 623 1.186 kre redir->nhere.text = redir->nhere.doc->narg.text; 624 1.186 kre break; 625 1.186 kre case NXHERE: 626 1.186 kre redir->nhere.text = expandhere(redir->nhere.doc); 627 1.186 kre break; 628 1.1 cgd } 629 1.1 cgd } 630 1.1 cgd } 631 1.1 cgd 632 1.159 kre /* 633 1.159 kre * Perform redirections for a compound command, and then do it (and restore) 634 1.159 kre */ 635 1.159 kre STATIC void 636 1.159 kre evalredir(union node *n, int flags) 637 1.159 kre { 638 1.159 kre struct jmploc jmploc; 639 1.159 kre struct jmploc * const savehandler = handler; 640 1.159 kre volatile int in_redirect = 1; 641 1.159 kre const char * volatile PS4 = NULL; 642 1.159 kre 643 1.159 kre expredir(n->nredir.redirect); 644 1.159 kre 645 1.159 kre if (xflag && n->nredir.redirect) { 646 1.159 kre union node *rn; 647 1.159 kre 648 1.159 kre outxstr(PS4 = expandstr(ps4val(), line_number)); 649 1.159 kre outxstr("using redirections:"); 650 1.159 kre for (rn = n->nredir.redirect; rn != NULL; rn = rn->nfile.next) 651 1.159 kre (void) outredir(outx, rn, ' '); 652 1.159 kre outxstr(" do {\n"); /* } */ 653 1.159 kre flushout(outx); 654 1.159 kre } 655 1.159 kre 656 1.159 kre if (setjmp(jmploc.loc)) { 657 1.159 kre int e; 658 1.159 kre 659 1.159 kre handler = savehandler; 660 1.159 kre e = exception; 661 1.197 kre popredir(POPREDIR_UNDO); 662 1.162 kre if (PS4 != NULL) { 663 1.159 kre outxstr(PS4); 664 1.159 kre /* { */ outxstr("} failed\n"); 665 1.159 kre flushout(outx); 666 1.159 kre } 667 1.159 kre if (e == EXERROR || e == EXEXEC) { 668 1.159 kre if (in_redirect) { 669 1.159 kre exitstatus = 2; 670 1.159 kre return; 671 1.159 kre } 672 1.159 kre } 673 1.159 kre longjmp(handler->loc, 1); 674 1.159 kre } else { 675 1.159 kre INTOFF; 676 1.159 kre handler = &jmploc; 677 1.159 kre redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP); 678 1.159 kre in_redirect = 0; 679 1.159 kre INTON; 680 1.159 kre evaltree(n->nredir.n, flags); 681 1.159 kre } 682 1.159 kre INTOFF; 683 1.159 kre handler = savehandler; 684 1.197 kre popredir(POPREDIR_UNDO); 685 1.159 kre INTON; 686 1.159 kre 687 1.162 kre if (PS4 != NULL) { 688 1.159 kre outxstr(PS4); 689 1.159 kre /* { */ outxstr("} done\n"); 690 1.159 kre flushout(outx); 691 1.159 kre } 692 1.159 kre } 693 1.1 cgd 694 1.1 cgd 695 1.1 cgd /* 696 1.1 cgd * Evaluate a pipeline. All the processes in the pipeline are children 697 1.1 cgd * of the process creating the pipeline. (This differs from some versions 698 1.1 cgd * of the shell, which make the last process in a pipeline the parent 699 1.1 cgd * of all the rest.) 700 1.1 cgd */ 701 1.1 cgd 702 1.1 cgd STATIC void 703 1.68 christos evalpipe(union node *n) 704 1.22 christos { 705 1.1 cgd struct job *jp; 706 1.1 cgd struct nodelist *lp; 707 1.1 cgd int pipelen; 708 1.1 cgd int prevfd; 709 1.1 cgd int pip[2]; 710 1.1 cgd 711 1.148 kre CTRACE(DBG_EVAL, ("evalpipe(%p) called\n", n)); 712 1.1 cgd pipelen = 0; 713 1.1 cgd for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 714 1.1 cgd pipelen++; 715 1.1 cgd INTOFF; 716 1.1 cgd jp = makejob(n, pipelen); 717 1.1 cgd prevfd = -1; 718 1.1 cgd for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 719 1.1 cgd prehash(lp->n); 720 1.1 cgd pip[1] = -1; 721 1.1 cgd if (lp->next) { 722 1.76 dsl if (sh_pipe(pip) < 0) { 723 1.87 christos if (prevfd >= 0) 724 1.87 christos close(prevfd); 725 1.159 kre error("Pipe call failed: %s", strerror(errno)); 726 1.1 cgd } 727 1.1 cgd } 728 1.159 kre if (forkshell(jp, lp->n, 729 1.159 kre n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) { 730 1.1 cgd INTON; 731 1.120 christos if (prevfd > 0) 732 1.120 christos movefd(prevfd, 0); 733 1.1 cgd if (pip[1] >= 0) { 734 1.1 cgd close(pip[0]); 735 1.120 christos movefd(pip[1], 1); 736 1.1 cgd } 737 1.65 christos evaltree(lp->n, EV_EXIT); 738 1.1 cgd } 739 1.1 cgd if (prevfd >= 0) 740 1.1 cgd close(prevfd); 741 1.1 cgd prevfd = pip[0]; 742 1.1 cgd close(pip[1]); 743 1.1 cgd } 744 1.1 cgd if (n->npipe.backgnd == 0) { 745 1.1 cgd exitstatus = waitforjob(jp); 746 1.148 kre CTRACE(DBG_EVAL, ("evalpipe: job done exit status %d\n", 747 1.148 kre exitstatus)); 748 1.192 kre } else { 749 1.192 kre jobstarted(jp); 750 1.115 christos exitstatus = 0; 751 1.192 kre } 752 1.60 mycroft INTON; 753 1.1 cgd } 754 1.1 cgd 755 1.1 cgd 756 1.1 cgd 757 1.1 cgd /* 758 1.1 cgd * Execute a command inside back quotes. If it's a builtin command, we 759 1.1 cgd * want to save its output in a block obtained from malloc. Otherwise 760 1.1 cgd * we fork off a subprocess and get the output of the command via a pipe. 761 1.1 cgd * Should be called with interrupts off. 762 1.1 cgd */ 763 1.1 cgd 764 1.1 cgd void 765 1.68 christos evalbackcmd(union node *n, struct backcmd *result) 766 1.22 christos { 767 1.1 cgd int pip[2]; 768 1.1 cgd struct job *jp; 769 1.159 kre struct stackmark smark; /* unnecessary (because we fork) */ 770 1.1 cgd 771 1.1 cgd result->fd = -1; 772 1.1 cgd result->buf = NULL; 773 1.1 cgd result->nleft = 0; 774 1.1 cgd result->jp = NULL; 775 1.159 kre 776 1.159 kre if (nflag || n == NULL) 777 1.7 jtc goto out; 778 1.159 kre 779 1.159 kre setstackmark(&smark); 780 1.159 kre 781 1.46 christos #ifdef notyet 782 1.46 christos /* 783 1.46 christos * For now we disable executing builtins in the same 784 1.46 christos * context as the shell, because we are not keeping 785 1.46 christos * enough state to recover from changes that are 786 1.46 christos * supposed only to affect subshells. eg. echo "`cd /`" 787 1.46 christos */ 788 1.7 jtc if (n->type == NCMD) { 789 1.159 kre exitstatus = oexitstatus; /* XXX o... no longer exists */ 790 1.65 christos evalcommand(n, EV_BACKCMD, result); 791 1.46 christos } else 792 1.46 christos #endif 793 1.46 christos { 794 1.63 mycroft INTOFF; 795 1.76 dsl if (sh_pipe(pip) < 0) 796 1.1 cgd error("Pipe call failed"); 797 1.1 cgd jp = makejob(n, 1); 798 1.65 christos if (forkshell(jp, n, FORK_NOJOB) == 0) { 799 1.1 cgd FORCEINTON; 800 1.1 cgd close(pip[0]); 801 1.120 christos movefd(pip[1], 1); 802 1.65 christos evaltree(n, EV_EXIT); 803 1.68 christos /* NOTREACHED */ 804 1.1 cgd } 805 1.1 cgd close(pip[1]); 806 1.1 cgd result->fd = pip[0]; 807 1.1 cgd result->jp = jp; 808 1.63 mycroft INTON; 809 1.1 cgd } 810 1.159 kre popstackmark(&smark); 811 1.148 kre out: 812 1.148 kre CTRACE(DBG_EVAL, ("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 813 1.1 cgd result->fd, result->buf, result->nleft, result->jp)); 814 1.1 cgd } 815 1.1 cgd 816 1.156 kre const char * 817 1.70 dsl syspath(void) 818 1.70 dsl { 819 1.70 dsl static char *sys_path = NULL; 820 1.70 dsl static int mib[] = {CTL_USER, USER_CS_PATH}; 821 1.80 christos static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin"; 822 1.72 agc size_t len; 823 1.70 dsl 824 1.70 dsl if (sys_path == NULL) { 825 1.70 dsl if (sysctl(mib, 2, 0, &len, 0, 0) != -1 && 826 1.70 dsl (sys_path = ckmalloc(len + 5)) != NULL && 827 1.70 dsl sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) { 828 1.70 dsl memcpy(sys_path, "PATH=", 5); 829 1.70 dsl } else { 830 1.70 dsl ckfree(sys_path); 831 1.70 dsl /* something to keep things happy */ 832 1.80 christos sys_path = def_path; 833 1.70 dsl } 834 1.70 dsl } 835 1.70 dsl return sys_path; 836 1.70 dsl } 837 1.70 dsl 838 1.70 dsl static int 839 1.70 dsl parse_command_args(int argc, char **argv, int *use_syspath) 840 1.70 dsl { 841 1.70 dsl int sv_argc = argc; 842 1.70 dsl char *cp, c; 843 1.70 dsl 844 1.70 dsl *use_syspath = 0; 845 1.70 dsl 846 1.70 dsl for (;;) { 847 1.70 dsl argv++; 848 1.70 dsl if (--argc == 0) 849 1.70 dsl break; 850 1.70 dsl cp = *argv; 851 1.70 dsl if (*cp++ != '-') 852 1.70 dsl break; 853 1.70 dsl if (*cp == '-' && cp[1] == 0) { 854 1.70 dsl argv++; 855 1.70 dsl argc--; 856 1.70 dsl break; 857 1.70 dsl } 858 1.70 dsl while ((c = *cp++)) { 859 1.70 dsl switch (c) { 860 1.70 dsl case 'p': 861 1.70 dsl *use_syspath = 1; 862 1.70 dsl break; 863 1.70 dsl default: 864 1.70 dsl /* run 'typecmd' for other options */ 865 1.70 dsl return 0; 866 1.70 dsl } 867 1.70 dsl } 868 1.70 dsl } 869 1.70 dsl return sv_argc - argc; 870 1.70 dsl } 871 1.1 cgd 872 1.61 christos int vforked = 0; 873 1.1 cgd 874 1.1 cgd /* 875 1.1 cgd * Execute a simple command. 876 1.1 cgd */ 877 1.1 cgd 878 1.1 cgd STATIC void 879 1.88 christos evalcommand(union node *cmd, int flgs, struct backcmd *backcmd) 880 1.16 cgd { 881 1.1 cgd struct stackmark smark; 882 1.1 cgd union node *argp; 883 1.1 cgd struct arglist arglist; 884 1.1 cgd struct arglist varlist; 885 1.88 christos volatile int flags = flgs; 886 1.88 christos char ** volatile argv; 887 1.88 christos volatile int argc; 888 1.1 cgd char **envp; 889 1.1 cgd int varflag; 890 1.1 cgd struct strlist *sp; 891 1.88 christos volatile int mode; 892 1.1 cgd int pip[2]; 893 1.1 cgd struct cmdentry cmdentry; 894 1.88 christos struct job * volatile jp; 895 1.1 cgd struct jmploc jmploc; 896 1.85 christos struct jmploc *volatile savehandler = NULL; 897 1.89 matt const char *volatile savecmdname; 898 1.1 cgd volatile struct shparam saveparam; 899 1.1 cgd struct localvar *volatile savelocalvars; 900 1.169 kre struct parsefile *volatile savetopfile; 901 1.1 cgd volatile int e; 902 1.88 christos char * volatile lastarg; 903 1.88 christos const char * volatile path = pathval(); 904 1.82 lukem volatile int temp_path; 905 1.143 kre const int savefuncline = funclinebase; 906 1.143 kre const int savefuncabs = funclineabs; 907 1.164 kre volatile int cmd_flags = 0; 908 1.1 cgd 909 1.61 christos vforked = 0; 910 1.1 cgd /* First expand the arguments. */ 911 1.153 kre CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called [%s]\n", cmd, flags, 912 1.153 kre cmd->ncmd.args ? cmd->ncmd.args->narg.text : "")); 913 1.1 cgd setstackmark(&smark); 914 1.68 christos back_exitstatus = 0; 915 1.68 christos 916 1.151 kre line_number = cmd->ncmd.lineno; 917 1.142 kre 918 1.1 cgd arglist.lastp = &arglist.list; 919 1.1 cgd varflag = 1; 920 1.78 dsl /* Expand arguments, ignoring the initial 'name=value' ones */ 921 1.1 cgd for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 922 1.166 kre if (varflag && isassignment(argp->narg.text)) 923 1.166 kre continue; 924 1.166 kre varflag = 0; 925 1.143 kre line_number = argp->narg.lineno; 926 1.7 jtc expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 927 1.1 cgd } 928 1.1 cgd *arglist.lastp = NULL; 929 1.68 christos 930 1.68 christos expredir(cmd->ncmd.redirect); 931 1.68 christos 932 1.78 dsl /* Now do the initial 'name=value' ones we skipped above */ 933 1.68 christos varlist.lastp = &varlist.list; 934 1.68 christos for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 935 1.143 kre line_number = argp->narg.lineno; 936 1.166 kre if (!isassignment(argp->narg.text)) 937 1.68 christos break; 938 1.191 kre /* EXP_CASE handles CTL* chars in expansions properly */ 939 1.191 kre expandarg(argp, &varlist, EXP_VARTILDE | EXP_CASE); 940 1.68 christos } 941 1.1 cgd *varlist.lastp = NULL; 942 1.68 christos 943 1.1 cgd argc = 0; 944 1.1 cgd for (sp = arglist.list ; sp ; sp = sp->next) 945 1.1 cgd argc++; 946 1.1 cgd argv = stalloc(sizeof (char *) * (argc + 1)); 947 1.7 jtc 948 1.7 jtc for (sp = arglist.list ; sp ; sp = sp->next) { 949 1.148 kre VTRACE(DBG_EVAL, ("evalcommand arg: %s\n", sp->text)); 950 1.1 cgd *argv++ = sp->text; 951 1.7 jtc } 952 1.1 cgd *argv = NULL; 953 1.1 cgd lastarg = NULL; 954 1.1 cgd if (iflag && funcnest == 0 && argc > 0) 955 1.1 cgd lastarg = argv[-1]; 956 1.1 cgd argv -= argc; 957 1.1 cgd 958 1.1 cgd /* Print the command if xflag is set. */ 959 1.1 cgd if (xflag) { 960 1.70 dsl char sep = 0; 961 1.151 kre union node *rn; 962 1.151 kre 963 1.153 kre outxstr(expandstr(ps4val(), line_number)); 964 1.1 cgd for (sp = varlist.list ; sp ; sp = sp->next) { 965 1.116 christos char *p; 966 1.116 christos 967 1.70 dsl if (sep != 0) 968 1.153 kre outxc(sep); 969 1.116 christos 970 1.116 christos /* 971 1.116 christos * The "var=" part should not be quoted, regardless 972 1.116 christos * of the value, or it would not represent an 973 1.116 christos * assignment, but rather a command 974 1.116 christos */ 975 1.116 christos p = strchr(sp->text, '='); 976 1.116 christos if (p != NULL) { 977 1.116 christos *p = '\0'; /*XXX*/ 978 1.153 kre outxshstr(sp->text); 979 1.153 kre outxc('='); 980 1.116 christos *p++ = '='; /*XXX*/ 981 1.116 christos } else 982 1.116 christos p = sp->text; 983 1.153 kre outxshstr(p); 984 1.70 dsl sep = ' '; 985 1.1 cgd } 986 1.1 cgd for (sp = arglist.list ; sp ; sp = sp->next) { 987 1.70 dsl if (sep != 0) 988 1.153 kre outxc(sep); 989 1.153 kre outxshstr(sp->text); 990 1.70 dsl sep = ' '; 991 1.1 cgd } 992 1.151 kre for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next) 993 1.153 kre if (outredir(outx, rn, sep)) 994 1.151 kre sep = ' '; 995 1.153 kre outxc('\n'); 996 1.153 kre flushout(outx); 997 1.1 cgd } 998 1.1 cgd 999 1.1 cgd /* Now locate the command. */ 1000 1.1 cgd if (argc == 0) { 1001 1.164 kre /* 1002 1.164 kre * the empty command begins as a normal builtin, and 1003 1.164 kre * remains that way while redirects are processed, then 1004 1.164 kre * will become special before we get to doing the 1005 1.164 kre * var assigns. 1006 1.164 kre */ 1007 1.164 kre cmdentry.cmdtype = CMDBUILTIN; 1008 1.68 christos cmdentry.u.bltin = bltincmd; 1009 1.190 msaitoh VTRACE(DBG_CMDS, ("No command name, assume \"command\"\n")); 1010 1.1 cgd } else { 1011 1.26 christos static const char PATH[] = "PATH="; 1012 1.26 christos 1013 1.26 christos /* 1014 1.26 christos * Modify the command lookup path, if a PATH= assignment 1015 1.26 christos * is present 1016 1.26 christos */ 1017 1.70 dsl for (sp = varlist.list; sp; sp = sp->next) 1018 1.26 christos if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 1019 1.26 christos path = sp->text + sizeof(PATH) - 1; 1020 1.26 christos 1021 1.70 dsl do { 1022 1.70 dsl int argsused, use_syspath; 1023 1.143 kre 1024 1.70 dsl find_command(argv[0], &cmdentry, cmd_flags, path); 1025 1.174 kre VTRACE(DBG_CMDS, ("Command %s type %d\n", argv[0], 1026 1.174 kre cmdentry.cmdtype)); 1027 1.157 kre #if 0 1028 1.157 kre /* 1029 1.157 kre * This short circuits all of the processing that 1030 1.157 kre * should be done (including processing the 1031 1.157 kre * redirects), so just don't ... 1032 1.157 kre * 1033 1.157 kre * (eventually this whole #if'd block will vanish) 1034 1.157 kre */ 1035 1.70 dsl if (cmdentry.cmdtype == CMDUNKNOWN) { 1036 1.68 christos exitstatus = 127; 1037 1.68 christos flushout(&errout); 1038 1.70 dsl goto out; 1039 1.1 cgd } 1040 1.157 kre #endif 1041 1.70 dsl 1042 1.70 dsl /* implement the 'command' builtin here */ 1043 1.70 dsl if (cmdentry.cmdtype != CMDBUILTIN || 1044 1.70 dsl cmdentry.u.bltin != bltincmd) 1045 1.70 dsl break; 1046 1.174 kre VTRACE(DBG_CMDS, ("Command \"command\"\n")); 1047 1.70 dsl cmd_flags |= DO_NOFUNC; 1048 1.70 dsl argsused = parse_command_args(argc, argv, &use_syspath); 1049 1.70 dsl if (argsused == 0) { 1050 1.154 kre /* use 'type' builtin to display info */ 1051 1.174 kre VTRACE(DBG_CMDS, 1052 1.174 kre ("Command \"command\" -> \"type\"\n")); 1053 1.70 dsl cmdentry.u.bltin = typecmd; 1054 1.70 dsl break; 1055 1.70 dsl } 1056 1.70 dsl argc -= argsused; 1057 1.70 dsl argv += argsused; 1058 1.70 dsl if (use_syspath) 1059 1.70 dsl path = syspath() + 5; 1060 1.70 dsl } while (argc != 0); 1061 1.70 dsl if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) 1062 1.70 dsl /* posix mandates that 'command <splbltin>' act as if 1063 1.70 dsl <splbltin> was a normal builtin */ 1064 1.70 dsl cmdentry.cmdtype = CMDBUILTIN; 1065 1.1 cgd } 1066 1.1 cgd 1067 1.170 kre /* 1068 1.170 kre * When traps are invalid, we permit the following: 1069 1.170 kre * trap 1070 1.170 kre * command trap 1071 1.170 kre * eval trap 1072 1.170 kre * command eval trap 1073 1.170 kre * eval command trap 1074 1.170 kre * without zapping the traps completely, in all other cases we do. 1075 1.181 kre * Function calls also do not zap the traps (but commands they execute 1076 1.181 kre * probably will) - this allows a function like 1077 1.181 kre * trapstate() { trap -p; } 1078 1.181 kre * called as save_traps=$(trapstate). 1079 1.170 kre * 1080 1.170 kre * The test here permits eval "anything" but when evalstring() comes 1081 1.170 kre * back here again, the "anything" will be validated. 1082 1.170 kre * This means we can actually do: 1083 1.170 kre * eval eval eval command eval eval command trap 1084 1.170 kre * as long as we end up with just "trap" 1085 1.170 kre * 1086 1.170 kre * We permit "command" by allowing CMDBUILTIN as well as CMDSPLBLTIN 1087 1.170 kre * 1088 1.170 kre * trapcmd() takes care of doing free_traps() if it is needed there. 1089 1.170 kre */ 1090 1.170 kre if (traps_invalid && 1091 1.181 kre cmdentry.cmdtype != CMDFUNCTION && 1092 1.170 kre ((cmdentry.cmdtype!=CMDSPLBLTIN && cmdentry.cmdtype!=CMDBUILTIN) || 1093 1.170 kre (cmdentry.u.bltin != trapcmd && cmdentry.u.bltin != evalcmd))) 1094 1.168 kre free_traps(); 1095 1.168 kre 1096 1.1 cgd /* Fork off a child process if necessary. */ 1097 1.176 kre if (cmd->ncmd.backgnd 1098 1.176 kre || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) 1099 1.176 kre && (have_traps() || (flags & EV_EXIT) == 0)) 1100 1.176 kre #ifdef notyet /* EV_BACKCMD is never set currently */ 1101 1.176 kre /* this will need more work if/when it gets used */ 1102 1.176 kre || ((flags & EV_BACKCMD) != 0 1103 1.176 kre && (cmdentry.cmdtype != CMDBUILTIN 1104 1.176 kre && cmdentry.cmdtype != CMDSPLBLTIN) 1105 1.176 kre || cmdentry.u.bltin == dotcmd 1106 1.176 kre || cmdentry.u.bltin == evalcmd) 1107 1.176 kre #endif 1108 1.176 kre ) { 1109 1.62 christos INTOFF; 1110 1.1 cgd jp = makejob(cmd, 1); 1111 1.1 cgd mode = cmd->ncmd.backgnd; 1112 1.1 cgd if (flags & EV_BACKCMD) { 1113 1.1 cgd mode = FORK_NOJOB; 1114 1.76 dsl if (sh_pipe(pip) < 0) 1115 1.1 cgd error("Pipe call failed"); 1116 1.1 cgd } 1117 1.61 christos #ifdef DO_SHAREDVFORK 1118 1.61 christos /* It is essential that if DO_SHAREDVFORK is defined that the 1119 1.61 christos * child's address space is actually shared with the parent as 1120 1.61 christos * we rely on this. 1121 1.61 christos */ 1122 1.177 kre if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL && 1123 1.177 kre (!cmd->ncmd.backgnd || cmd->ncmd.redirect == NULL)) { 1124 1.61 christos pid_t pid; 1125 1.108 christos int serrno; 1126 1.61 christos 1127 1.61 christos savelocalvars = localvars; 1128 1.61 christos localvars = NULL; 1129 1.61 christos vforked = 1; 1130 1.140 kre VFORK_BLOCK 1131 1.61 christos switch (pid = vfork()) { 1132 1.61 christos case -1: 1133 1.108 christos serrno = errno; 1134 1.148 kre VTRACE(DBG_EVAL, ("vfork() failed, errno=%d\n", 1135 1.148 kre serrno)); 1136 1.61 christos INTON; 1137 1.108 christos error("Cannot vfork (%s)", strerror(serrno)); 1138 1.61 christos break; 1139 1.61 christos case 0: 1140 1.61 christos /* Make sure that exceptions only unwind to 1141 1.61 christos * after the vfork(2) 1142 1.61 christos */ 1143 1.140 kre SHELL_FORKED(); 1144 1.61 christos if (setjmp(jmploc.loc)) { 1145 1.183 kre VTRACE(DBG_EVAL|DBG_ERRS| 1146 1.183 kre DBG_PROCS|DBG_CMDS|DBG_TRAP, 1147 1.183 kre ("vfork child exit exception:%d " 1148 1.183 kre "exitstatus:%d exerrno:%d\n", 1149 1.183 kre exception, exitstatus, exerrno)); 1150 1.183 kre 1151 1.61 christos if (exception == EXSHELLPROC) { 1152 1.148 kre /* 1153 1.148 kre * We can't progress with the 1154 1.148 kre * vfork, so, set vforked = 2 1155 1.148 kre * so the parent knows, 1156 1.148 kre * and _exit(); 1157 1.61 christos */ 1158 1.61 christos vforked = 2; 1159 1.61 christos _exit(0); 1160 1.61 christos } else { 1161 1.161 kre _exit(exception == EXEXIT ? 1162 1.161 kre exitstatus : exerrno); 1163 1.61 christos } 1164 1.61 christos } 1165 1.61 christos savehandler = handler; 1166 1.61 christos handler = &jmploc; 1167 1.167 kre listmklocal(varlist.list, 1168 1.167 kre VDOEXPORT | VEXPORT | VNOFUNC); 1169 1.65 christos forkchild(jp, cmd, mode, vforked); 1170 1.61 christos break; 1171 1.61 christos default: 1172 1.140 kre VFORK_UNDO(); 1173 1.148 kre /* restore from vfork(2) */ 1174 1.174 kre CTRACE(DBG_PROCS|DBG_CMDS, 1175 1.174 kre ("parent after vfork - vforked=%d\n", 1176 1.174 kre vforked)); 1177 1.148 kre handler = savehandler; 1178 1.61 christos poplocalvars(); 1179 1.61 christos localvars = savelocalvars; 1180 1.61 christos if (vforked == 2) { 1181 1.61 christos vforked = 0; 1182 1.61 christos 1183 1.61 christos (void)waitpid(pid, NULL, 0); 1184 1.148 kre /* 1185 1.148 kre * We need to progress in a 1186 1.148 kre * normal fork fashion 1187 1.148 kre */ 1188 1.61 christos goto normal_fork; 1189 1.61 christos } 1190 1.148 kre /* 1191 1.148 kre * Here the child has left home, 1192 1.148 kre * getting on with its life, so 1193 1.148 kre * so must we... 1194 1.148 kre */ 1195 1.61 christos vforked = 0; 1196 1.65 christos forkparent(jp, cmd, mode, pid); 1197 1.61 christos goto parent; 1198 1.61 christos } 1199 1.140 kre VFORK_END 1200 1.61 christos } else { 1201 1.148 kre normal_fork: 1202 1.61 christos #endif 1203 1.65 christos if (forkshell(jp, cmd, mode) != 0) 1204 1.61 christos goto parent; /* at end of routine */ 1205 1.174 kre CTRACE(DBG_PROCS|DBG_CMDS, ("Child sets EV_EXIT\n")); 1206 1.159 kre flags |= EV_EXIT; 1207 1.66 christos FORCEINTON; 1208 1.61 christos #ifdef DO_SHAREDVFORK 1209 1.61 christos } 1210 1.61 christos #endif 1211 1.1 cgd if (flags & EV_BACKCMD) { 1212 1.61 christos if (!vforked) { 1213 1.61 christos FORCEINTON; 1214 1.61 christos } 1215 1.1 cgd close(pip[0]); 1216 1.120 christos movefd(pip[1], 1); 1217 1.1 cgd } 1218 1.1 cgd flags |= EV_EXIT; 1219 1.1 cgd } 1220 1.1 cgd 1221 1.1 cgd /* This is the child process if a fork occurred. */ 1222 1.1 cgd /* Execute the command. */ 1223 1.70 dsl switch (cmdentry.cmdtype) { 1224 1.159 kre volatile int saved; 1225 1.188 kre struct funcdef * volatile savefunc; 1226 1.194 kre const char * volatile savectx; 1227 1.159 kre 1228 1.70 dsl case CMDFUNCTION: 1229 1.152 kre VXTRACE(DBG_EVAL, ("Shell function%s: ",vforked?" VF":""), 1230 1.152 kre trargs(argv)); 1231 1.197 kre redirect(cmd->ncmd.redirect, REDIR_KEEP | (saved = 1232 1.197 kre !(flags & EV_EXIT) || have_traps() ? REDIR_PUSH : 0)); 1233 1.1 cgd saveparam = shellparam; 1234 1.1 cgd shellparam.malloc = 0; 1235 1.32 christos shellparam.reset = 1; 1236 1.1 cgd shellparam.nparam = argc - 1; 1237 1.1 cgd shellparam.p = argv + 1; 1238 1.1 cgd shellparam.optnext = NULL; 1239 1.1 cgd INTOFF; 1240 1.1 cgd savelocalvars = localvars; 1241 1.194 kre savectx = currentcontext; 1242 1.1 cgd localvars = NULL; 1243 1.188 kre reffunc(savefunc = cmdentry.u.func); 1244 1.1 cgd INTON; 1245 1.1 cgd if (setjmp(jmploc.loc)) { 1246 1.47 christos if (exception == EXSHELLPROC) { 1247 1.47 christos freeparam((volatile struct shparam *) 1248 1.47 christos &saveparam); 1249 1.47 christos } else { 1250 1.1 cgd freeparam(&shellparam); 1251 1.1 cgd shellparam = saveparam; 1252 1.1 cgd } 1253 1.159 kre if (saved) 1254 1.197 kre popredir(POPREDIR_UNDO); 1255 1.188 kre unreffunc(savefunc); 1256 1.1 cgd poplocalvars(); 1257 1.1 cgd localvars = savelocalvars; 1258 1.143 kre funclinebase = savefuncline; 1259 1.143 kre funclineabs = savefuncabs; 1260 1.194 kre currentcontext = savectx; 1261 1.1 cgd handler = savehandler; 1262 1.1 cgd longjmp(handler->loc, 1); 1263 1.1 cgd } 1264 1.1 cgd savehandler = handler; 1265 1.1 cgd handler = &jmploc; 1266 1.143 kre if (cmdentry.u.func) { 1267 1.143 kre if (cmdentry.lno_frel) 1268 1.143 kre funclinebase = cmdentry.lineno - 1; 1269 1.143 kre else 1270 1.143 kre funclinebase = 0; 1271 1.143 kre funclineabs = cmdentry.lineno; 1272 1.194 kre currentcontext = argv[0]; 1273 1.143 kre 1274 1.143 kre VTRACE(DBG_EVAL, 1275 1.143 kre ("function: node: %d '%s' # %d%s; funclinebase=%d\n", 1276 1.155 kre getfuncnode(cmdentry.u.func)->type, 1277 1.155 kre NODETYPENAME(getfuncnode(cmdentry.u.func)->type), 1278 1.143 kre cmdentry.lineno, cmdentry.lno_frel?" (=1)":"", 1279 1.143 kre funclinebase)); 1280 1.143 kre } 1281 1.167 kre listmklocal(varlist.list, VDOEXPORT | VEXPORT); 1282 1.70 dsl /* stop shell blowing its stack */ 1283 1.70 dsl if (++funcnest > 1000) 1284 1.70 dsl error("too many nested function calls"); 1285 1.159 kre evaltree(getfuncnode(cmdentry.u.func), 1286 1.159 kre flags & (EV_TESTED|EV_EXIT)); 1287 1.1 cgd funcnest--; 1288 1.1 cgd INTOFF; 1289 1.155 kre unreffunc(cmdentry.u.func); 1290 1.1 cgd poplocalvars(); 1291 1.1 cgd localvars = savelocalvars; 1292 1.143 kre funclinebase = savefuncline; 1293 1.143 kre funclineabs = savefuncabs; 1294 1.194 kre currentcontext = savectx; 1295 1.1 cgd freeparam(&shellparam); 1296 1.1 cgd shellparam = saveparam; 1297 1.1 cgd handler = savehandler; 1298 1.159 kre if (saved) 1299 1.197 kre popredir(POPREDIR_UNDO); 1300 1.1 cgd INTON; 1301 1.1 cgd if (evalskip == SKIPFUNC) { 1302 1.109 christos evalskip = SKIPNONE; 1303 1.1 cgd skipcount = 0; 1304 1.1 cgd } 1305 1.1 cgd if (flags & EV_EXIT) 1306 1.1 cgd exitshell(exitstatus); 1307 1.70 dsl break; 1308 1.70 dsl 1309 1.164 kre case CMDSPLBLTIN: 1310 1.164 kre VTRACE(DBG_EVAL, ("special ")); 1311 1.70 dsl case CMDBUILTIN: 1312 1.164 kre VXTRACE(DBG_EVAL, ("builtin command [%d]%s: ", argc, 1313 1.164 kre vforked ? " VF" : ""), trargs(argv)); 1314 1.197 kre 1315 1.197 kre if (cmdentry.u.bltin == execcmd) { 1316 1.197 kre char **ap; 1317 1.197 kre 1318 1.197 kre /* 1319 1.197 kre * Work out how we should process redirections 1320 1.197 kre * on the "exec" command. We need REDIR_KEEP 1321 1.197 kre * if we must not set close-on-exec, and REDIR_PUSH 1322 1.197 kre * if we need to be able to undo them (in the 1323 1.197 kre * exec command, only on some kind of error). 1324 1.197 kre * 1325 1.197 kre * Skip "exec" (argv[0]) then examine args. 1326 1.197 kre * 1327 1.197 kre * This must be done manually, as nextopt() 1328 1.197 kre * hasn't been init'd for this command yet. 1329 1.197 kre * And it won't be until after redirections are done. 1330 1.197 kre * 1331 1.197 kre * "exec" currently takes no options (except "--"), 1332 1.197 kre * but might one day, and this needs to keep working, 1333 1.197 kre * so do it, kind of, properly. 1334 1.197 kre * 1335 1.197 kre * Note in the common cases argv[1] will be NULL 1336 1.197 kre * (for exec just setting up redirectons) or will 1337 1.197 kre * not start with a '-' ("exec cmd") so normally 1338 1.197 kre * this loop will either never start or will break 1339 1.197 kre * at the first test of the first iteration. 1340 1.197 kre */ 1341 1.197 kre for (ap = argv + 1; *ap != NULL; ap++) { 1342 1.197 kre 1343 1.197 kre if (ap[0][0] != '-') 1344 1.197 kre break; 1345 1.197 kre 1346 1.197 kre if (ap[0][1] == '\0') /* "exec -" */ 1347 1.197 kre break; /* or continue ?? */ 1348 1.197 kre 1349 1.197 kre if (ap[0][1] == '-' && ap[0][2] == '\0') { 1350 1.197 kre ap++; 1351 1.197 kre break; 1352 1.197 kre } 1353 1.197 kre 1354 1.197 kre #if defined(DUMMY_EXAMPLE_CODE) && 0 1355 1.197 kre /* 1356 1.197 kre * if options are added to "exec" then 1357 1.197 kre * any which take an arg (like the common 1358 1.197 kre * in other shells "-a cmdname") need to 1359 1.197 kre * be recognised here, lest "cmdname" be 1360 1.197 kre * thought to be the cmd to exec 1361 1.197 kre */ 1362 1.197 kre 1363 1.197 kre for (char *op = ap[0] + 1; *op; op++) { 1364 1.197 kre switch (*op) { 1365 1.197 kre case 'a': 1366 1.197 kre case any others similar: 1367 1.197 kre /* options needing an optarg */ 1368 1.197 kre if (op[1] == '\0' && ap[1]) 1369 1.197 kre ap++; 1370 1.197 kre break; 1371 1.197 kre 1372 1.197 kre default: 1373 1.197 kre /* options with no optarg */ 1374 1.197 kre continue; 1375 1.197 kre } 1376 1.197 kre break; 1377 1.197 kre } 1378 1.197 kre #endif /* DUMMY EXAMPLE CODE */ 1379 1.197 kre } 1380 1.197 kre 1381 1.197 kre if (*ap != NULL) 1382 1.197 kre mode = REDIR_KEEP; /* exec cmd <... */ 1383 1.197 kre else 1384 1.197 kre mode = 0; /* exec < .... */ 1385 1.197 kre 1386 1.197 kre /* 1387 1.197 kre * always save old fd setup in case of error() 1388 1.197 kre * execcmd() will undo this if no error occurs 1389 1.197 kre * (that is, in the case the shell has not vanished) 1390 1.197 kre */ 1391 1.197 kre mode |= REDIR_PUSH; 1392 1.197 kre } else /* any builtin execpt "exec" */ 1393 1.197 kre mode = REDIR_PUSH | REDIR_KEEP; 1394 1.197 kre 1395 1.1 cgd if (flags == EV_BACKCMD) { 1396 1.1 cgd memout.nleft = 0; 1397 1.1 cgd memout.nextc = memout.buf; 1398 1.1 cgd memout.bufsize = 64; 1399 1.1 cgd mode |= REDIR_BACKQ; 1400 1.1 cgd } 1401 1.197 kre 1402 1.70 dsl e = -1; 1403 1.169 kre savecmdname = commandname; 1404 1.169 kre savetopfile = getcurrentfile(); 1405 1.68 christos savehandler = handler; 1406 1.104 joerg temp_path = 0; 1407 1.197 kre 1408 1.68 christos if (!setjmp(jmploc.loc)) { 1409 1.169 kre handler = &jmploc; 1410 1.169 kre 1411 1.148 kre /* 1412 1.148 kre * We need to ensure the command hash table isn't 1413 1.130 christos * corrupted by temporary PATH assignments. 1414 1.70 dsl * However we must ensure the 'local' command works! 1415 1.70 dsl */ 1416 1.70 dsl if (path != pathval() && (cmdentry.u.bltin == hashcmd || 1417 1.70 dsl cmdentry.u.bltin == typecmd)) { 1418 1.70 dsl savelocalvars = localvars; 1419 1.70 dsl localvars = 0; 1420 1.104 joerg temp_path = 1; 1421 1.70 dsl mklocal(path - 5 /* PATH= */, 0); 1422 1.104 joerg } 1423 1.68 christos redirect(cmd->ncmd.redirect, mode); 1424 1.68 christos 1425 1.164 kre /* 1426 1.164 kre * the empty command is regarded as a normal 1427 1.164 kre * builtin for the purposes of redirects, but 1428 1.164 kre * is a special builtin for var assigns. 1429 1.164 kre * (unless we are the "command" command.) 1430 1.164 kre */ 1431 1.164 kre if (argc == 0 && !(cmd_flags & DO_NOFUNC)) 1432 1.164 kre cmdentry.cmdtype = CMDSPLBLTIN; 1433 1.164 kre 1434 1.68 christos /* exec is a special builtin, but needs this list... */ 1435 1.68 christos cmdenviron = varlist.list; 1436 1.68 christos /* we must check 'readonly' flag for all builtins */ 1437 1.68 christos listsetvar(varlist.list, 1438 1.68 christos cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); 1439 1.68 christos commandname = argv[0]; 1440 1.68 christos /* initialize nextopt */ 1441 1.68 christos argptr = argv + 1; 1442 1.68 christos optptr = NULL; 1443 1.68 christos /* and getopt */ 1444 1.68 christos optreset = 1; 1445 1.68 christos optind = 1; 1446 1.103 christos builtin_flags = flags; 1447 1.185 kre clr_err(out1); /* discard previous I/O errors */ 1448 1.68 christos exitstatus = cmdentry.u.bltin(argc, argv); 1449 1.68 christos } else { 1450 1.1 cgd e = exception; 1451 1.159 kre if (e == EXINT) 1452 1.159 kre exitstatus = SIGINT + 128; 1453 1.159 kre else if (e == EXEXEC) 1454 1.159 kre exitstatus = exerrno; 1455 1.159 kre else if (e != EXEXIT) 1456 1.159 kre exitstatus = 2; 1457 1.1 cgd } 1458 1.70 dsl handler = savehandler; 1459 1.1 cgd flushall(); 1460 1.1 cgd out1 = &output; 1461 1.1 cgd out2 = &errout; 1462 1.1 cgd freestdout(); 1463 1.70 dsl if (temp_path) { 1464 1.70 dsl poplocalvars(); 1465 1.70 dsl localvars = savelocalvars; 1466 1.70 dsl } 1467 1.39 thorpej cmdenviron = NULL; 1468 1.1 cgd if (e != EXSHELLPROC) { 1469 1.1 cgd commandname = savecmdname; 1470 1.44 mycroft if (flags & EV_EXIT) 1471 1.1 cgd exitshell(exitstatus); 1472 1.1 cgd } 1473 1.1 cgd if (e != -1) { 1474 1.31 christos if ((e != EXERROR && e != EXEXEC) 1475 1.70 dsl || cmdentry.cmdtype == CMDSPLBLTIN) 1476 1.1 cgd exraise(e); 1477 1.169 kre popfilesupto(savetopfile); 1478 1.1 cgd FORCEINTON; 1479 1.1 cgd } 1480 1.197 kre 1481 1.68 christos if (cmdentry.u.bltin != execcmd) 1482 1.197 kre popredir(POPREDIR_UNDO); 1483 1.197 kre 1484 1.1 cgd if (flags == EV_BACKCMD) { 1485 1.1 cgd backcmd->buf = memout.buf; 1486 1.1 cgd backcmd->nleft = memout.nextc - memout.buf; 1487 1.1 cgd memout.buf = NULL; 1488 1.1 cgd } 1489 1.70 dsl break; 1490 1.70 dsl 1491 1.70 dsl default: 1492 1.152 kre VXTRACE(DBG_EVAL, ("normal command%s: ", vforked?" VF":""), 1493 1.152 kre trargs(argv)); 1494 1.189 kre redirect(cmd->ncmd.redirect, 1495 1.117 christos (vforked ? REDIR_VFORK : 0) | REDIR_KEEP); 1496 1.61 christos if (!vforked) 1497 1.61 christos for (sp = varlist.list ; sp ; sp = sp->next) 1498 1.167 kre setvareq(sp->text, VDOEXPORT|VEXPORT|VSTACK); 1499 1.1 cgd envp = environment(); 1500 1.70 dsl shellexec(argv, envp, path, cmdentry.u.index, vforked); 1501 1.70 dsl break; 1502 1.1 cgd } 1503 1.1 cgd goto out; 1504 1.1 cgd 1505 1.148 kre parent: /* parent process gets here (if we forked) */ 1506 1.148 kre 1507 1.113 christos exitstatus = 0; /* if not altered just below */ 1508 1.68 christos if (mode == FORK_FG) { /* argument to fork */ 1509 1.1 cgd exitstatus = waitforjob(jp); 1510 1.68 christos } else if (mode == FORK_NOJOB) { 1511 1.1 cgd backcmd->fd = pip[0]; 1512 1.1 cgd close(pip[1]); 1513 1.1 cgd backcmd->jp = jp; 1514 1.192 kre } else 1515 1.192 kre jobstarted(jp); 1516 1.192 kre 1517 1.66 christos FORCEINTON; 1518 1.1 cgd 1519 1.148 kre out: 1520 1.1 cgd if (lastarg) 1521 1.132 kre /* implement $_ for whatever use that really is */ 1522 1.147 kre (void) setvarsafe("_", lastarg, VNOERROR); 1523 1.1 cgd popstackmark(&smark); 1524 1.1 cgd } 1525 1.1 cgd 1526 1.1 cgd 1527 1.1 cgd /* 1528 1.1 cgd * Search for a command. This is called before we fork so that the 1529 1.1 cgd * location of the command will be available in the parent as well as 1530 1.1 cgd * the child. The check for "goodname" is an overly conservative 1531 1.1 cgd * check that the name will not be subject to expansion. 1532 1.1 cgd */ 1533 1.1 cgd 1534 1.1 cgd STATIC void 1535 1.68 christos prehash(union node *n) 1536 1.22 christos { 1537 1.1 cgd struct cmdentry entry; 1538 1.1 cgd 1539 1.86 christos if (n && n->type == NCMD && n->ncmd.args) 1540 1.15 mycroft if (goodname(n->ncmd.args->narg.text)) 1541 1.26 christos find_command(n->ncmd.args->narg.text, &entry, 0, 1542 1.26 christos pathval()); 1543 1.1 cgd } 1544 1.1 cgd 1545 1.122 kre int 1546 1.109 christos in_function(void) 1547 1.109 christos { 1548 1.109 christos return funcnest; 1549 1.109 christos } 1550 1.1 cgd 1551 1.122 kre enum skipstate 1552 1.109 christos current_skipstate(void) 1553 1.109 christos { 1554 1.109 christos return evalskip; 1555 1.109 christos } 1556 1.109 christos 1557 1.122 kre void 1558 1.168 kre save_skipstate(struct skipsave *p) 1559 1.168 kre { 1560 1.168 kre *p = s_k_i_p; 1561 1.168 kre } 1562 1.168 kre 1563 1.168 kre void 1564 1.168 kre restore_skipstate(const struct skipsave *p) 1565 1.168 kre { 1566 1.168 kre s_k_i_p = *p; 1567 1.168 kre } 1568 1.168 kre 1569 1.168 kre void 1570 1.109 christos stop_skipping(void) 1571 1.109 christos { 1572 1.109 christos evalskip = SKIPNONE; 1573 1.109 christos skipcount = 0; 1574 1.109 christos } 1575 1.1 cgd 1576 1.1 cgd /* 1577 1.1 cgd * Builtin commands. Builtin commands whose functions are closely 1578 1.1 cgd * tied to evaluation are implemented here. 1579 1.1 cgd */ 1580 1.1 cgd 1581 1.1 cgd /* 1582 1.70 dsl * No command given. 1583 1.1 cgd */ 1584 1.1 cgd 1585 1.16 cgd int 1586 1.68 christos bltincmd(int argc, char **argv) 1587 1.16 cgd { 1588 1.31 christos /* 1589 1.22 christos * Preserve exitstatus of a previous possible redirection 1590 1.31 christos * as POSIX mandates 1591 1.22 christos */ 1592 1.68 christos return back_exitstatus; 1593 1.1 cgd } 1594 1.1 cgd 1595 1.1 cgd 1596 1.1 cgd /* 1597 1.1 cgd * Handle break and continue commands. Break, continue, and return are 1598 1.1 cgd * all handled by setting the evalskip flag. The evaluation routines 1599 1.1 cgd * above all check this flag, and if it is set they start skipping 1600 1.1 cgd * commands rather than executing them. The variable skipcount is 1601 1.1 cgd * the number of loops to break/continue, or the number of function 1602 1.1 cgd * levels to return. (The latter is always 1.) It should probably 1603 1.1 cgd * be an error to break out of more loops than exist, but it isn't 1604 1.1 cgd * in the standard shell so we don't make it one here. 1605 1.1 cgd */ 1606 1.1 cgd 1607 1.16 cgd int 1608 1.68 christos breakcmd(int argc, char **argv) 1609 1.16 cgd { 1610 1.30 christos int n = argc > 1 ? number(argv[1]) : 1; 1611 1.1 cgd 1612 1.135 kre if (n <= 0) 1613 1.135 kre error("invalid count: %d", n); 1614 1.1 cgd if (n > loopnest) 1615 1.1 cgd n = loopnest; 1616 1.1 cgd if (n > 0) { 1617 1.1 cgd evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 1618 1.1 cgd skipcount = n; 1619 1.1 cgd } 1620 1.1 cgd return 0; 1621 1.1 cgd } 1622 1.1 cgd 1623 1.109 christos int 1624 1.109 christos dotcmd(int argc, char **argv) 1625 1.109 christos { 1626 1.109 christos exitstatus = 0; 1627 1.109 christos 1628 1.178 kre (void) nextopt(NULL); /* ignore a leading "--" */ 1629 1.178 kre 1630 1.178 kre if (*argptr != NULL) { /* That's what SVR2 does */ 1631 1.109 christos char *fullname; 1632 1.109 christos /* 1633 1.109 christos * dot_funcnest needs to be 0 when not in a dotcmd, so it 1634 1.109 christos * cannot be restored with (funcnest + 1). 1635 1.109 christos */ 1636 1.109 christos int dot_funcnest_old; 1637 1.109 christos struct stackmark smark; 1638 1.109 christos 1639 1.109 christos setstackmark(&smark); 1640 1.178 kre fullname = find_dot_file(*argptr); 1641 1.109 christos setinputfile(fullname, 1); 1642 1.109 christos commandname = fullname; 1643 1.109 christos dot_funcnest_old = dot_funcnest; 1644 1.109 christos dot_funcnest = funcnest + 1; 1645 1.109 christos cmdloop(0); 1646 1.109 christos dot_funcnest = dot_funcnest_old; 1647 1.109 christos popfile(); 1648 1.109 christos popstackmark(&smark); 1649 1.109 christos } 1650 1.109 christos return exitstatus; 1651 1.109 christos } 1652 1.109 christos 1653 1.109 christos /* 1654 1.171 kre * allow dotfile function nesting to be manipulated 1655 1.171 kre * (for read_profile). This allows profile files to 1656 1.171 kre * be treated as if they were used as '.' commands, 1657 1.171 kre * (approximately) and in particular, for "return" to work. 1658 1.171 kre */ 1659 1.171 kre int 1660 1.171 kre set_dot_funcnest(int new) 1661 1.171 kre { 1662 1.171 kre int rv = dot_funcnest; 1663 1.171 kre 1664 1.171 kre if (new >= 0) 1665 1.171 kre dot_funcnest = new; 1666 1.171 kre 1667 1.171 kre return rv; 1668 1.171 kre } 1669 1.171 kre 1670 1.171 kre /* 1671 1.109 christos * Take commands from a file. To be compatible we should do a path 1672 1.109 christos * search for the file, which is necessary to find sub-commands. 1673 1.109 christos */ 1674 1.109 christos 1675 1.109 christos STATIC char * 1676 1.109 christos find_dot_file(char *basename) 1677 1.109 christos { 1678 1.109 christos char *fullname; 1679 1.109 christos const char *path = pathval(); 1680 1.109 christos struct stat statb; 1681 1.109 christos 1682 1.109 christos /* don't try this for absolute or relative paths */ 1683 1.121 kre if (strchr(basename, '/')) { 1684 1.121 kre if (stat(basename, &statb) == 0) { 1685 1.128 kre if (S_ISDIR(statb.st_mode)) 1686 1.128 kre error("%s: is a directory", basename); 1687 1.128 kre if (S_ISBLK(statb.st_mode)) 1688 1.128 kre error("%s: is a block device", basename); 1689 1.128 kre return basename; 1690 1.121 kre } 1691 1.141 kre } else while ((fullname = padvance(&path, basename, 1)) != NULL) { 1692 1.128 kre if ((stat(fullname, &statb) == 0)) { 1693 1.128 kre /* weird format is to ease future code... */ 1694 1.128 kre if (S_ISDIR(statb.st_mode) || S_ISBLK(statb.st_mode)) 1695 1.128 kre ; 1696 1.128 kre #if notyet 1697 1.128 kre else if (unreadable()) { 1698 1.128 kre /* 1699 1.128 kre * testing this via st_mode is ugly to get 1700 1.128 kre * correct (and would ignore ACLs). 1701 1.128 kre * better way is just to open the file. 1702 1.128 kre * But doing that here would (currently) 1703 1.128 kre * mean opening the file twice, which 1704 1.128 kre * might not be safe. So, defer this 1705 1.128 kre * test until code is restructures so 1706 1.128 kre * we can return a fd. Then we also 1707 1.128 kre * get to fix the mem leak just below... 1708 1.128 kre */ 1709 1.128 kre } 1710 1.128 kre #endif 1711 1.128 kre else { 1712 1.128 kre /* 1713 1.128 kre * Don't bother freeing here, since 1714 1.128 kre * it will be freed by the caller. 1715 1.128 kre * XXX no it won't - a bug for later. 1716 1.128 kre */ 1717 1.128 kre return fullname; 1718 1.128 kre } 1719 1.109 christos } 1720 1.109 christos stunalloc(fullname); 1721 1.109 christos } 1722 1.109 christos 1723 1.109 christos /* not found in the PATH */ 1724 1.109 christos error("%s: not found", basename); 1725 1.109 christos /* NOTREACHED */ 1726 1.109 christos } 1727 1.109 christos 1728 1.109 christos 1729 1.1 cgd 1730 1.1 cgd /* 1731 1.1 cgd * The return command. 1732 1.109 christos * 1733 1.109 christos * Quoth the POSIX standard: 1734 1.109 christos * The return utility shall cause the shell to stop executing the current 1735 1.109 christos * function or dot script. If the shell is not currently executing 1736 1.109 christos * a function or dot script, the results are unspecified. 1737 1.109 christos * 1738 1.109 christos * As for the unspecified part, there seems to be no de-facto standard: bash 1739 1.109 christos * ignores the return with a warning, zsh ignores the return in interactive 1740 1.109 christos * mode but seems to liken it to exit in a script. (checked May 2014) 1741 1.109 christos * 1742 1.109 christos * We choose to silently ignore the return. Older versions of this shell 1743 1.109 christos * set evalskip to SKIPFILE causing the shell to (indirectly) exit. This 1744 1.109 christos * had at least the problem of circumventing the check for stopped jobs, 1745 1.109 christos * which would occur for exit or ^D. 1746 1.1 cgd */ 1747 1.1 cgd 1748 1.16 cgd int 1749 1.68 christos returncmd(int argc, char **argv) 1750 1.16 cgd { 1751 1.68 christos int ret = argc > 1 ? number(argv[1]) : exitstatus; 1752 1.1 cgd 1753 1.109 christos if ((dot_funcnest == 0 && funcnest) 1754 1.109 christos || (dot_funcnest > 0 && funcnest - (dot_funcnest - 1) > 0)) { 1755 1.1 cgd evalskip = SKIPFUNC; 1756 1.1 cgd skipcount = 1; 1757 1.109 christos } else if (dot_funcnest > 0) { 1758 1.27 christos evalskip = SKIPFILE; 1759 1.27 christos skipcount = 1; 1760 1.109 christos } else { 1761 1.109 christos /* XXX: should a warning be issued? */ 1762 1.109 christos ret = 0; 1763 1.1 cgd } 1764 1.109 christos 1765 1.109 christos return ret; 1766 1.1 cgd } 1767 1.1 cgd 1768 1.1 cgd 1769 1.16 cgd int 1770 1.68 christos falsecmd(int argc, char **argv) 1771 1.16 cgd { 1772 1.8 jtc return 1; 1773 1.8 jtc } 1774 1.8 jtc 1775 1.8 jtc 1776 1.16 cgd int 1777 1.68 christos truecmd(int argc, char **argv) 1778 1.16 cgd { 1779 1.1 cgd return 0; 1780 1.1 cgd } 1781 1.1 cgd 1782 1.1 cgd 1783 1.16 cgd int 1784 1.68 christos execcmd(int argc, char **argv) 1785 1.16 cgd { 1786 1.197 kre /* 1787 1.197 kre * BEWARE: if any options are added here, they must 1788 1.197 kre * also be added in evalcommand(), look for "DUMMY_EXAMPLE_CODE" 1789 1.197 kre * for example code for there. Here the options would be 1790 1.197 kre * processed completely normally. 1791 1.197 kre */ 1792 1.197 kre (void) nextopt(""); /* ignore a leading "--" */ 1793 1.178 kre 1794 1.178 kre if (*argptr) { 1795 1.20 christos struct strlist *sp; 1796 1.20 christos 1797 1.1 cgd iflag = 0; /* exit on error */ 1798 1.7 jtc mflag = 0; 1799 1.7 jtc optschanged(); 1800 1.70 dsl for (sp = cmdenviron; sp; sp = sp->next) 1801 1.167 kre setvareq(sp->text, VDOEXPORT|VEXPORT|VSTACK); 1802 1.178 kre shellexec(argptr, environment(), pathval(), 0, 0); 1803 1.197 kre /* NOTREACHED */ 1804 1.1 cgd } 1805 1.197 kre popredir(POPREDIR_PERMANENT); /* make any redirections permanent */ 1806 1.68 christos return 0; 1807 1.68 christos } 1808 1.68 christos 1809 1.68 christos static int 1810 1.73 itojun conv_time(clock_t ticks, char *seconds, size_t l) 1811 1.68 christos { 1812 1.68 christos static clock_t tpm = 0; 1813 1.68 christos clock_t mins; 1814 1.68 christos int i; 1815 1.68 christos 1816 1.68 christos if (!tpm) 1817 1.68 christos tpm = sysconf(_SC_CLK_TCK) * 60; 1818 1.68 christos 1819 1.68 christos mins = ticks / tpm; 1820 1.73 itojun snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm ); 1821 1.68 christos 1822 1.68 christos if (seconds[0] == '6' && seconds[1] == '0') { 1823 1.68 christos /* 59.99995 got rounded up... */ 1824 1.68 christos mins++; 1825 1.73 itojun strlcpy(seconds, "0.0", l); 1826 1.68 christos return mins; 1827 1.68 christos } 1828 1.68 christos 1829 1.68 christos /* suppress trailing zeros */ 1830 1.68 christos i = strlen(seconds) - 1; 1831 1.68 christos for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--) 1832 1.68 christos seconds[i] = 0; 1833 1.68 christos return mins; 1834 1.68 christos } 1835 1.68 christos 1836 1.68 christos int 1837 1.68 christos timescmd(int argc, char **argv) 1838 1.68 christos { 1839 1.68 christos struct tms tms; 1840 1.68 christos int u, s, cu, cs; 1841 1.68 christos char us[8], ss[8], cus[8], css[8]; 1842 1.68 christos 1843 1.68 christos nextopt(""); 1844 1.68 christos 1845 1.68 christos times(&tms); 1846 1.68 christos 1847 1.73 itojun u = conv_time(tms.tms_utime, us, sizeof(us)); 1848 1.73 itojun s = conv_time(tms.tms_stime, ss, sizeof(ss)); 1849 1.73 itojun cu = conv_time(tms.tms_cutime, cus, sizeof(cus)); 1850 1.73 itojun cs = conv_time(tms.tms_cstime, css, sizeof(css)); 1851 1.68 christos 1852 1.68 christos outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n", 1853 1.68 christos u, us, s, ss, cu, cus, cs, css); 1854 1.68 christos 1855 1.1 cgd return 0; 1856 1.1 cgd } 1857