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