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