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 }