1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 1996,2002-2003 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 /* 33 * 34 * UNIX shell 35 * 36 */ 37 38 39 #include "defs.h" 40 #include <errno.h> 41 #include "sym.h" 42 #include "hash.h" 43 #include <sys/types.h> 44 #include <sys/times.h> 45 46 pid_t parent; 47 48 /* ======== command execution ======== */ 49 50 51 execute(argt, xflags, errorflg, pf1, pf2) 52 struct trenod *argt; 53 int *pf1, *pf2; 54 { 55 /* 56 * `stakbot' is preserved by this routine 57 */ 58 register struct trenod *t; 59 unsigned char *sav = savstak(); 60 61 sigchk(); 62 if (!errorflg) 63 flags &= ~errflg; 64 65 if ((t = argt) && execbrk == 0) { 66 register int treeflgs; 67 register unsigned char **com; 68 int type; 69 short pos; 70 71 treeflgs = t->tretyp; 72 type = treeflgs & COMMSK; 73 74 switch (type) 75 { 76 case TFND: 77 { 78 struct fndnod *f = (struct fndnod *)t; 79 struct namnod *n = lookup(f->fndnam); 80 81 exitval = 0; 82 83 if (n->namflg & N_RDONLY) 84 failed(n->namid, wtfailed); 85 86 if (flags & rshflg && (n == &pathnod || 87 eq(n->namid, "SHELL"))) 88 failed(n->namid, restricted); 89 if (n->namflg & N_FUNCTN) 90 freefunc(n); 91 else 92 { 93 free(n->namval); 94 free(n->namenv); 95 96 n->namval = 0; 97 n->namflg &= ~(N_EXPORT | N_ENVCHG); 98 } 99 100 if (funcnt) 101 f->fndval->tretyp++; 102 103 n->namenv = (unsigned char *)f->fndval; 104 attrib(n, N_FUNCTN); 105 hash_func(n->namid); 106 break; 107 } 108 109 case TCOM: 110 { 111 unsigned char *a1, *name; 112 int argn, internal; 113 struct argnod *schain = gchain; 114 struct ionod *io = t->treio; 115 short cmdhash; 116 short comtype; 117 118 exitval = 0; 119 120 gchain = 0; 121 argn = getarg(t); 122 com = scan(argn); 123 a1 = com[1]; 124 gchain = schain; 125 126 if (argn != 0) 127 cmdhash = pathlook(com[0], 1, comptr(t)->comset); 128 129 if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN) { 130 setlist(comptr(t)->comset, 0); 131 } 132 133 if (argn && (flags&noexec) == 0) 134 { 135 136 /* print command if execpr */ 137 if (flags & execpr) 138 execprint(com); 139 140 if (comtype == NOTFOUND) 141 { 142 pos = hashdata(cmdhash); 143 if (pos == 1) 144 failure(*com, notfound); 145 else if (pos == 2) 146 failure(*com, badexec); 147 else 148 failure(*com, badperm); 149 break; 150 } 151 152 else if (comtype == PATH_COMMAND) 153 { 154 pos = -1; 155 } 156 157 else if (comtype & (COMMAND | REL_COMMAND)) 158 { 159 pos = hashdata(cmdhash); 160 } 161 162 else if (comtype == BUILTIN) { 163 builtin(hashdata(cmdhash),argn,com,t); 164 freejobs(); 165 break; 166 } 167 else if (comtype == FUNCTION) 168 { 169 struct dolnod *olddolh; 170 struct namnod *n, *opt; 171 short index; 172 unsigned char **olddolv = dolv; 173 int olddolc = dolc; 174 n = findnam(com[0]); 175 /* save current positional parameters */ 176 olddolh = (struct dolnod *)savargs(funcnt); 177 funcnt++; 178 index = initio(io, 1); 179 setargs(com); 180 execute((struct trenod *)(n->namenv), xflags, errorflg, pf1, pf2); 181 execbrk = 0; 182 restore(index); 183 (void) restorargs(olddolh, funcnt); 184 dolv = olddolv; 185 dolc = olddolc; 186 funcnt--; 187 188 break; 189 } 190 } 191 else if (t->treio == 0) 192 { 193 chktrap(); 194 break; 195 } 196 197 } 198 199 case TFORK: 200 { 201 int monitor = 0; 202 int linked = 0; 203 204 exitval = 0; 205 206 if (!(xflags & XEC_EXECED) || treeflgs&(FPOU|FAMP)) 207 { 208 209 int forkcnt = 1; 210 211 if (!(treeflgs&FPOU)) 212 { 213 monitor = (!(xflags & XEC_NOSTOP) 214 && (flags&(monitorflg|jcflg|jcoff)) 215 == (monitorflg|jcflg)); 216 if (monitor) { 217 int savefd; 218 unsigned char *savebot; 219 savefd = setb(-1); 220 savebot = stakbot; 221 prcmd(t); 222 (void)setb(savefd); 223 allocjob(savebot, cwdget(), monitor); 224 } else 225 allocjob("", "", 0); 226 227 } 228 229 if (treeflgs & (FPOU|FAMP)) { 230 link_iodocs(iotemp); 231 linked = 1; 232 } 233 234 while ((parent = fork()) == -1) 235 { 236 /* 237 * FORKLIM is the max period between forks - 238 * power of 2 usually. Currently shell tries 239 * after 2,4,8,16, and 32 seconds and then quits 240 */ 241 242 if ((forkcnt = (forkcnt * 2)) > FORKLIM) 243 { 244 switch (errno) 245 { 246 case ENOMEM: 247 deallocjob(); 248 error(noswap); 249 break; 250 default: 251 deallocjob(); 252 error(nofork); 253 break; 254 } 255 } else if (errno == EPERM) { 256 deallocjob(); 257 error(eacces); 258 break; 259 } 260 sigchk(); 261 sleep(forkcnt); 262 } 263 264 if (parent) { 265 if (monitor) 266 setpgid(parent, 0); 267 if (treeflgs & FPIN) 268 closepipe(pf1); 269 if (!(treeflgs&FPOU)) { 270 postjob(parent,!(treeflgs&FAMP)); 271 freejobs(); 272 } 273 chktrap(); 274 break; 275 } 276 mypid = getpid(); 277 } 278 279 /* 280 * Forked process: assume it is not a subshell for 281 * now. If it is, the presence of a left parenthesis 282 * will trigger the jcoff flag to be turned off. 283 * When jcoff is turned on, monitoring is not going on 284 * and waitpid will not look for WUNTRACED. 285 */ 286 287 flags |= (forked|jcoff); 288 289 fiotemp = 0; 290 291 if (linked == 1) { 292 swap_iodoc_nm(iotemp); 293 xflags |= XEC_LINKED; 294 } else if (!(xflags & XEC_LINKED)) 295 iotemp = 0; 296 #ifdef ACCT 297 suspacct(); 298 #endif 299 settmp(); 300 oldsigs(); 301 302 if (!(treeflgs & FPOU)) 303 makejob(monitor, !(treeflgs & FAMP)); 304 305 /* 306 * pipe in or out 307 */ 308 if (treeflgs & FPIN) 309 { 310 renamef(pf1[INPIPE], 0); 311 close(pf1[OTPIPE]); 312 } 313 314 if (treeflgs & FPOU) 315 { 316 close(pf2[INPIPE]); 317 renamef(pf2[OTPIPE], 1); 318 } 319 320 /* 321 * io redirection 322 */ 323 initio(t->treio, 0); 324 325 if (type == TFORK) 326 execute(forkptr(t)->forktre, xflags | XEC_EXECED, errorflg); 327 else if (com[0] != ENDARGS) 328 { 329 eflag = 0; 330 setlist(comptr(t)->comset, N_EXPORT); 331 rmtemp(0); 332 clearjobs(); 333 execa(com, pos); 334 } 335 done(0); 336 } 337 338 case TPAR: 339 /* Forked process is subshell: may want job control */ 340 flags &= ~jcoff; 341 clearjobs(); 342 execute(parptr(t)->partre, xflags, errorflg); 343 done(0); 344 345 case TFIL: 346 { 347 int pv[2]; 348 349 chkpipe(pv); 350 if (execute(lstptr(t)->lstlef, xflags & XEC_NOSTOP, errorflg, pf1, pv) == 0) 351 execute(lstptr(t)->lstrit, xflags, errorflg, pv, pf2); 352 else 353 closepipe(pv); 354 } 355 break; 356 357 case TLST: 358 execute(lstptr(t)->lstlef, xflags&XEC_NOSTOP, errorflg); 359 /* Update errorflg if set -e is invoked in the sub-sh*/ 360 execute(lstptr(t)->lstrit, xflags, (errorflg | (eflag & errflg))); 361 break; 362 363 case TAND: 364 case TORF: 365 { 366 register xval; 367 xval = execute(lstptr(t)->lstlef, XEC_NOSTOP, 0); 368 if ((xval == 0) == (type == TAND)) 369 execute(lstptr(t)->lstrit, xflags|XEC_NOSTOP, errorflg); 370 break; 371 } 372 373 case TFOR: 374 { 375 struct namnod *n = lookup(forptr(t)->fornam); 376 unsigned char **args; 377 struct dolnod *argsav = 0; 378 379 if (forptr(t)->forlst == 0) 380 { 381 args = dolv + 1; 382 argsav = useargs(); 383 } 384 else 385 { 386 struct argnod *schain = gchain; 387 388 gchain = 0; 389 args = scan(getarg(forptr(t)->forlst)); 390 gchain = schain; 391 } 392 loopcnt++; 393 while (*args != ENDARGS && execbrk == 0) 394 { 395 assign(n, *args++); 396 execute(forptr(t)->fortre, XEC_NOSTOP, errorflg); 397 if (breakcnt < 0) 398 execbrk = (++breakcnt != 0); 399 } 400 if (breakcnt > 0) 401 execbrk = (--breakcnt != 0); 402 403 loopcnt--; 404 if(argsav) 405 argfor = (struct dolnod *)freeargs(argsav); 406 } 407 break; 408 409 case TWH: 410 case TUN: 411 { 412 int i = 0; 413 414 loopcnt++; 415 while (execbrk == 0 && (execute(whptr(t)->whtre, 416 XEC_NOSTOP, 0) == 0) == (type == TWH) && 417 (flags&noexec) == 0) 418 { 419 i = execute(whptr(t)->dotre, XEC_NOSTOP, errorflg); 420 if (breakcnt < 0) 421 execbrk = (++breakcnt != 0); 422 } 423 if (breakcnt > 0) 424 execbrk = (--breakcnt != 0); 425 426 loopcnt--; 427 exitval = i; 428 } 429 break; 430 431 case TIF: 432 if (execute(ifptr(t)->iftre, XEC_NOSTOP, 0) == 0) 433 execute(ifptr(t)->thtre, xflags|XEC_NOSTOP, errorflg); 434 else if (ifptr(t)->eltre) 435 execute(ifptr(t)->eltre, xflags|XEC_NOSTOP, errorflg); 436 else 437 exitval = 0; /* force zero exit for if-then-fi */ 438 break; 439 440 case TSW: 441 { 442 register unsigned char *r = mactrim(swptr(t)->swarg); 443 register struct regnod *regp; 444 445 regp = swptr(t)->swlst; 446 while (regp) 447 { 448 struct argnod *rex = regp->regptr; 449 450 while (rex) 451 { 452 register unsigned char *s; 453 454 if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s))) 455 { 456 execute(regp->regcom, XEC_NOSTOP, errorflg); 457 regp = 0; 458 break; 459 } 460 else 461 rex = rex->argnxt; 462 } 463 if (regp) 464 regp = regp->regnxt; 465 } 466 } 467 break; 468 } 469 exitset(); 470 } 471 sigchk(); 472 tdystak(sav); 473 flags |= eflag; 474 return(exitval); 475 } 476 477 execexp(s, f) 478 unsigned char *s; 479 int f; 480 { 481 struct fileblk fb; 482 483 push(&fb); 484 if (s) 485 { 486 estabf(s); 487 fb.feval = (unsigned char **)(f); 488 } 489 else if (f >= 0) 490 initf(f); 491 execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg)); 492 pop(); 493 } 494 495 execprint(com) 496 unsigned char **com; 497 { 498 register int argn = 0; 499 unsigned char *s; 500 501 prs(execpmsg); 502 while(com[argn] != ENDARGS) 503 { 504 s = com[argn++]; 505 write(output, s, length(s) - 1); 506 blank(); 507 } 508 509 newline(); 510 } 511