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