Home | History | Annotate | Line # | Download | only in ksh
c_sh.c revision 1.21
      1 /*	$NetBSD: c_sh.c,v 1.21 2017/06/30 03:43:57 kamil Exp $	*/
      2 
      3 /*
      4  * built-in Bourne commands
      5  */
      6 #include <sys/cdefs.h>
      7 
      8 #ifndef lint
      9 __RCSID("$NetBSD: c_sh.c,v 1.21 2017/06/30 03:43:57 kamil Exp $");
     10 #endif
     11 
     12 #include <sys/time.h>
     13 #include <sys/times.h>
     14 #include <time.h>
     15 
     16 #include "sh.h"
     17 #include "ksh_stat.h" 	/* umask() */
     18 
     19 
     20 static	char *clocktos ARGS((clock_t t));
     21 
     22 
     23 /* :, false and true */
     24 int
     25 c_label(wp)
     26 	char **wp;
     27 {
     28 	return wp[0][0] == 'f' ? 1 : 0;
     29 }
     30 
     31 int
     32 c_shift(wp)
     33 	char **wp;
     34 {
     35 	register struct block *l = e->loc;
     36 	register int n;
     37 	long val;
     38 	char *arg;
     39 
     40 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
     41 		return 1;
     42 	arg = wp[builtin_opt.optind];
     43 
     44 	if (arg) {
     45 		evaluate(arg, &val, KSH_UNWIND_ERROR);
     46 		n = val;
     47 	} else
     48 		n = 1;
     49 	if (n < 0) {
     50 		bi_errorf("%s: bad number", arg);
     51 		return (1);
     52 	}
     53 	if (l->argc < n) {
     54 		bi_errorf("nothing to shift");
     55 		return (1);
     56 	}
     57 	l->argv[n] = l->argv[0];
     58 	l->argv += n;
     59 	l->argc -= n;
     60 	return 0;
     61 }
     62 
     63 int
     64 c_umask(wp)
     65 	char **wp;
     66 {
     67 	register int i;
     68 	register char *cp;
     69 	int symbolic = 0;
     70 	int old_umask;
     71 	int optc;
     72 
     73 	while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
     74 		switch (optc) {
     75 		  case 'S':
     76 			symbolic = 1;
     77 			break;
     78 		  case '?':
     79 			return 1;
     80 		}
     81 	cp = wp[builtin_opt.optind];
     82 	if (cp == NULL) {
     83 		old_umask = umask(0);
     84 		umask(old_umask);
     85 		if (symbolic) {
     86 			char buf[18];
     87 			int j;
     88 
     89 			old_umask = ~old_umask;
     90 			cp = buf;
     91 			for (i = 0; i < 3; i++) {
     92 				*cp++ = "ugo"[i];
     93 				*cp++ = '=';
     94 				for (j = 0; j < 3; j++)
     95 					if (old_umask & (1 << (8 - (3*i + j))))
     96 						*cp++ = "rwx"[j];
     97 				*cp++ = ',';
     98 			}
     99 			cp[-1] = '\0';
    100 			shprintf("%s\n", buf);
    101 		} else
    102 			shprintf("%#3.3o\n", old_umask);
    103 	} else {
    104 		int new_umask;
    105 
    106 		if (digit(*cp)) {
    107 			for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
    108 				new_umask = new_umask * 8 + (*cp - '0');
    109 			if (*cp) {
    110 				bi_errorf("bad number");
    111 				return 1;
    112 			}
    113 		} else {
    114 			/* symbolic format */
    115 			int positions, new_val;
    116 			char op;
    117 
    118 			old_umask = umask(0);
    119 			umask(old_umask); /* in case of error */
    120 			old_umask = ~old_umask;
    121 			new_umask = old_umask;
    122 			positions = 0;
    123 			while (*cp) {
    124 				while (*cp && strchr("augo", *cp))
    125 					switch (*cp++) {
    126 					case 'a': positions |= 0111; break;
    127 					case 'u': positions |= 0100; break;
    128 					case 'g': positions |= 0010; break;
    129 					case 'o': positions |= 0001; break;
    130 					}
    131 				if (!positions)
    132 					positions = 0111; /* default is a */
    133 				if (!strchr("=+-", op = *cp))
    134 					break;
    135 				cp++;
    136 				new_val = 0;
    137 				while (*cp && strchr("rwxugoXs", *cp))
    138 					switch (*cp++) {
    139 					case 'r': new_val |= 04; break;
    140 					case 'w': new_val |= 02; break;
    141 					case 'x': new_val |= 01; break;
    142 					case 'u': new_val |= old_umask >> 6;
    143 						  break;
    144 					case 'g': new_val |= old_umask >> 3;
    145 						  break;
    146 					case 'o': new_val |= old_umask >> 0;
    147 						  break;
    148 					case 'X': if (old_umask & 0111)
    149 							new_val |= 01;
    150 						  break;
    151 					case 's': /* ignored */
    152 						  break;
    153 					}
    154 				new_val = (new_val & 07) * positions;
    155 				switch (op) {
    156 				case '-':
    157 					new_umask &= ~new_val;
    158 					break;
    159 				case '=':
    160 					new_umask = new_val
    161 					    | (new_umask & ~(positions * 07));
    162 					break;
    163 				case '+':
    164 					new_umask |= new_val;
    165 				}
    166 				if (*cp == ',') {
    167 					positions = 0;
    168 					cp++;
    169 				} else if (!strchr("=+-", *cp))
    170 					break;
    171 			}
    172 			if (*cp) {
    173 				bi_errorf("bad mask");
    174 				return 1;
    175 			}
    176 			new_umask = ~new_umask;
    177 		}
    178 		umask(new_umask);
    179 	}
    180 	return 0;
    181 }
    182 
    183 int
    184 c_dot(wp)
    185 	char **wp;
    186 {
    187 	char *file, *cp;
    188 	char **argv;
    189 	int argc;
    190 	int i;
    191 	int err;
    192 
    193 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    194 		return 1;
    195 
    196 	if ((cp = wp[builtin_opt.optind]) == NULL)
    197 		return 0;
    198 	file = search(cp, path, R_OK, &err);
    199 	if (file == NULL) {
    200 		bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
    201 		return 1;
    202 	}
    203 
    204 	/* Set positional parameters? */
    205 	if (wp[builtin_opt.optind + 1]) {
    206 		argv = wp + builtin_opt.optind;
    207 		argv[0] = e->loc->argv[0]; /* preserve $0 */
    208 		for (argc = 0; argv[argc + 1]; argc++)
    209 			;
    210 	} else {
    211 		argc = 0;
    212 		argv = (char **) 0;
    213 	}
    214 	i = include(file, argc, argv, 0);
    215 	if (i < 0) { /* should not happen */
    216 		bi_errorf("%s: %s", cp, strerror(errno));
    217 		return 1;
    218 	}
    219 	return i;
    220 }
    221 
    222 int
    223 c_wait(wp)
    224 	char **wp;
    225 {
    226 	int UNINITIALIZED(rv);
    227 	int sig;
    228 
    229 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    230 		return 1;
    231 	wp += builtin_opt.optind;
    232 	if (*wp == (char *) 0) {
    233 		while (waitfor((char *) 0, &sig) >= 0)
    234 			;
    235 		rv = sig;
    236 	} else {
    237 		for (; *wp; wp++)
    238 			rv = waitfor(*wp, &sig);
    239 		if (rv < 0)
    240 			rv = sig ? sig : 127; /* magic exit code: bad job-id */
    241 	}
    242 	return rv;
    243 }
    244 
    245 int
    246 c_read(wp)
    247 	char **wp;
    248 {
    249 	register int c = 0;
    250 	int expandv = 1, history = 0;
    251 	int expanding;
    252 	int ecode = 0;
    253 	register char *cp;
    254 	int fd = 0;
    255 	struct shf *shf;
    256 	int optc;
    257 	const char *emsg;
    258 	XString cs, xs;
    259 	struct tbl *vp;
    260 	char UNINITIALIZED(*xp);
    261 	static char REPLY[] = "REPLY";
    262 
    263 	while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
    264 		switch (optc) {
    265 #ifdef KSH
    266 		  case 'p':
    267 			if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
    268 				bi_errorf("-p: %s", emsg);
    269 				return 1;
    270 			}
    271 			break;
    272 #endif /* KSH */
    273 		  case 'r':
    274 			expandv = 0;
    275 			break;
    276 		  case 's':
    277 			history = 1;
    278 			break;
    279 		  case 'u':
    280 			if (!*(cp = builtin_opt.optarg))
    281 				fd = 0;
    282 			else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
    283 				bi_errorf("-u: %s: %s", cp, emsg);
    284 				return 1;
    285 			}
    286 			break;
    287 		  case '?':
    288 			return 1;
    289 		}
    290 	wp += builtin_opt.optind;
    291 
    292 	if (*wp == NULL)
    293 		*--wp = REPLY;
    294 
    295 	/* Since we can't necessarily seek backwards on non-regular files,
    296 	 * don't buffer them so we can't read too much.
    297 	 */
    298 	shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
    299 
    300 	if ((cp = strchr(*wp, '?')) != NULL) {
    301 		*cp = 0;
    302 		if (isatty(fd)) {
    303 			/* at&t ksh says it prints prompt on fd if it's open
    304 			 * for writing and is a tty, but it doesn't do it
    305 			 * (it also doesn't check the interactive flag,
    306 			 * as is indicated in the Kornshell book).
    307 			 */
    308 			shellf("%s", cp+1);
    309 		}
    310 	}
    311 
    312 #ifdef KSH
    313 	/* If we are reading from the co-process for the first time,
    314 	 * make sure the other side of the pipe is closed first.  This allows
    315 	 * the detection of eof.
    316 	 *
    317 	 * This is not compatible with at&t ksh... the fd is kept so another
    318 	 * coproc can be started with same output, however, this means eof
    319 	 * can't be detected...  This is why it is closed here.
    320 	 * If this call is removed, remove the eof check below, too.
    321 	 * coproc_readw_close(fd);
    322 	 */
    323 #endif /* KSH */
    324 
    325 	if (history)
    326 		Xinit(xs, xp, 128, ATEMP);
    327 	expanding = 0;
    328 	Xinit(cs, cp, 128, ATEMP);
    329 	for (; *wp != NULL; wp++) {
    330 		for (cp = Xstring(cs, cp); ; ) {
    331 			if (c == '\n' || c == EOF)
    332 				break;
    333 			while (1) {
    334 				c = shf_getc(shf);
    335 				if (c == '\0'
    336 				    )
    337 					continue;
    338 				if (c == EOF && shf_error(shf)
    339 				    && shf_errno(shf) == EINTR)
    340 				{
    341 					/* Was the offending signal one that
    342 					 * would normally kill a process?
    343 					 * If so, pretend the read was killed.
    344 					 */
    345 					ecode = fatal_trap_check();
    346 
    347 					/* non fatal (eg, CHLD), carry on */
    348 					if (!ecode) {
    349 						shf_clearerr(shf);
    350 						continue;
    351 					}
    352 				}
    353 				break;
    354 			}
    355 			if (history) {
    356 				Xcheck(xs, xp);
    357 				Xput(xs, xp, c);
    358 			}
    359 			Xcheck(cs, cp);
    360 			if (expanding) {
    361 				expanding = 0;
    362 				if (c == '\n') {
    363 					c = 0;
    364 					if (Flag(FTALKING_I) && isatty(fd)) {
    365 						/* set prompt in case this is
    366 						 * called from .profile or $ENV
    367 						 */
    368 						set_prompt(PS2, (Source *) 0);
    369 						pprompt(prompt, 0);
    370 					}
    371 				} else if (c != EOF)
    372 					Xput(cs, cp, c);
    373 				continue;
    374 			}
    375 			if (expandv && c == '\\') {
    376 				expanding = 1;
    377 				continue;
    378 			}
    379 			if (c == '\n' || c == EOF)
    380 				break;
    381 			if (ctype(c, C_IFS)) {
    382 				if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
    383 					continue;
    384 				if (wp[1])
    385 					break;
    386 			}
    387 			Xput(cs, cp, c);
    388 		}
    389 		/* strip trailing IFS white space from last variable */
    390 		if (!wp[1])
    391 			while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
    392 			       && ctype(cp[-1], C_IFSWS))
    393 				cp--;
    394 		Xput(cs, cp, '\0');
    395 		vp = global(*wp);
    396 		/* Must be done before setting export. */
    397 		if (vp->flag & RDONLY) {
    398 			shf_flush(shf);
    399 			bi_errorf("%s is read only", *wp);
    400 			return 1;
    401 		}
    402 		if (Flag(FEXPORT))
    403 			typeset(*wp, EXPORT, 0, 0, 0);
    404 		if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
    405 		    shf_flush(shf);
    406 		    return 1;
    407 		}
    408 	}
    409 
    410 	shf_flush(shf);
    411 	if (history) {
    412 		Xput(xs, xp, '\0');
    413 		source->line++;
    414 		histsave(source->line, Xstring(xs, xp), 1);
    415 		Xfree(xs, xp);
    416 	}
    417 #ifdef KSH
    418 	/* if this is the co-process fd, close the file descriptor
    419 	 * (can get eof if and only if all processes are have died, ie,
    420 	 * coproc.njobs is 0 and the pipe is closed).
    421 	 */
    422 	if (c == EOF && !ecode)
    423 		coproc_read_close(fd);
    424 #endif /* KSH */
    425 
    426 	return ecode ? ecode : c == EOF;
    427 }
    428 
    429 int
    430 c_eval(wp)
    431 	char **wp;
    432 {
    433 	register struct source *s;
    434 	int rv;
    435 
    436 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    437 		return 1;
    438 	s = pushs(SWORDS, ATEMP);
    439 	s->u.strv = wp + builtin_opt.optind;
    440 	if (!Flag(FPOSIX)) {
    441 		/*
    442 		 * Handle case where the command is empty due to failed
    443 		 * command substitution, eg, eval "$(false)".
    444 		 * In this case, shell() will not set/change exstat (because
    445 		 * compiled tree is empty), so will use this value.
    446 		 * subst_exstat is cleared in execute(), so should be 0 if
    447 		 * there were no substitutions.
    448 		 *
    449 		 * A strict reading of POSIX says we don't do this (though
    450 		 * it is traditionally done). [from 1003.2-1992]
    451 		 *    3.9.1: Simple Commands
    452 		 *	... If there is a command name, execution shall
    453 		 *	continue as described in 3.9.1.1.  If there
    454 		 *	is no command name, but the command contained a command
    455 		 *	substitution, the command shall complete with the exit
    456 		 *	status of the last command substitution
    457 		 *    3.9.1.1: Command Search and Execution
    458 		 *	...(1)...(a) If the command name matches the name of
    459 		 *	a special built-in utility, that special built-in
    460 		 *	utility shall be invoked.
    461 		 * 3.14.5: Eval
    462 		 *	... If there are no arguments, or only null arguments,
    463 		 *	eval shall return an exit status of zero.
    464 		 */
    465 		exstat = subst_exstat;
    466 	}
    467 
    468 	rv = shell(s, FALSE);
    469 	afree(s, ATEMP);
    470 	return rv;
    471 }
    472 
    473 int
    474 c_trap(wp)
    475 	char **wp;
    476 {
    477 	int i;
    478 	char *s;
    479 	register Trap *p;
    480 
    481 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    482 		return 1;
    483 	wp += builtin_opt.optind;
    484 
    485 	if (*wp == NULL) {
    486 		int anydfl = 0;
    487 
    488 		for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
    489 			if (p->trap == NULL)
    490 				anydfl = 1;
    491 			else {
    492 				shprintf("trap -- ");
    493 				print_value_quoted(p->trap);
    494 				shprintf(" %s\n", p->name);
    495 			}
    496 		}
    497 #if 0 /* this is ugly and not clear POSIX needs it */
    498 		/* POSIX may need this so output of trap can be saved and
    499 		 * used to restore trap conditions
    500 		 */
    501 		if (anydfl) {
    502 			shprintf("trap -- -");
    503 			for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
    504 				if (p->trap == NULL && p->name)
    505 					shprintf(" %s", p->name);
    506 			shprintf(newline);
    507 		}
    508 #else
    509 		__USE(anydfl);
    510 #endif
    511 		return 0;
    512 	}
    513 
    514 	/*
    515 	 * Use case sensitive lookup for first arg so the
    516 	 * command 'exit' isn't confused with the pseudo-signal
    517 	 * 'EXIT'.
    518 	 */
    519 	s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */
    520 	if (s != NULL && s[0] == '-' && s[1] == '\0')
    521 		s = NULL;
    522 
    523 	/* set/clear traps */
    524 	while (*wp != NULL) {
    525 		p = gettrap(*wp++, TRUE);
    526 		if (p == NULL) {
    527 			bi_errorf("bad signal %s", wp[-1]);
    528 			return 1;
    529 		}
    530 		settrap(p, s);
    531 	}
    532 	return 0;
    533 }
    534 
    535 int
    536 c_exitreturn(wp)
    537 	char **wp;
    538 {
    539 	int how = LEXIT;
    540 	int n;
    541 	char *arg;
    542 
    543 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    544 		return 1;
    545 	arg = wp[builtin_opt.optind];
    546 
    547 	if (arg) {
    548 	    if (!getn(arg, &n)) {
    549 		    exstat = 1;
    550 		    warningf(TRUE, "%s: bad number", arg);
    551 	    } else
    552 		    exstat = n;
    553 	}
    554 	if (wp[0][0] == 'r') { /* return */
    555 		struct env *ep;
    556 
    557 		/* need to tell if this is exit or return so trap exit will
    558 		 * work right (POSIX)
    559 		 */
    560 		for (ep = e; ep; ep = ep->oenv)
    561 			if (STOP_RETURN(ep->type)) {
    562 				how = LRETURN;
    563 				break;
    564 			}
    565 	}
    566 
    567 	if (how == LEXIT && !really_exit && j_stopped_running()) {
    568 		really_exit = 1;
    569 		how = LSHELL;
    570 	}
    571 
    572 	quitenv();	/* get rid of any i/o redirections */
    573 	unwind(how);
    574 	/*NOTREACHED*/
    575 	return 0;
    576 }
    577 
    578 int
    579 c_brkcont(wp)
    580 	char **wp;
    581 {
    582 	int n, quit;
    583 	struct env *ep, *last_ep = (struct env *) 0;
    584 	char *arg;
    585 
    586 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
    587 		return 1;
    588 	arg = wp[builtin_opt.optind];
    589 
    590 	if (!arg)
    591 		n = 1;
    592 	else if (!bi_getn(arg, &n))
    593 		return 1;
    594 	quit = n;
    595 	if (quit <= 0) {
    596 		/* at&t ksh does this for non-interactive shells only - weird */
    597 		bi_errorf("%s: bad value", arg);
    598 		return 1;
    599 	}
    600 
    601 	/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
    602 	for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
    603 		if (ep->type == E_LOOP) {
    604 			if (--quit == 0)
    605 				break;
    606 			ep->flags |= EF_BRKCONT_PASS;
    607 			last_ep = ep;
    608 		}
    609 
    610 	if (quit) {
    611 		/* at&t ksh doesn't print a message - just does what it
    612 		 * can.  We print a message 'cause it helps in debugging
    613 		 * scripts, but don't generate an error (ie, keep going).
    614 		 */
    615 		if (n == quit) {
    616 			warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
    617 			return 0;
    618 		}
    619 		/* POSIX says if n is too big, the last enclosing loop
    620 		 * shall be used.  Doesn't say to print an error but we
    621 		 * do anyway 'cause the user messed up.
    622 		 */
    623 		if (last_ep)
    624 			last_ep->flags &= ~EF_BRKCONT_PASS;
    625 		warningf(TRUE, "%s: can only %s %d level(s)",
    626 			wp[0], wp[0], n - quit);
    627 	}
    628 
    629 	unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
    630 	/*NOTREACHED*/
    631 }
    632 
    633 int
    634 c_set(wp)
    635 	char **wp;
    636 {
    637 	int argi, setargs;
    638 	struct block *l = e->loc;
    639 	register char **owp = wp;
    640 
    641 	if (wp[1] == NULL) {
    642 		static const char *const args [] = { "set", "-", NULL };
    643 		return c_typeset((char **)__UNCONST(args));
    644 	}
    645 
    646 	argi = parse_args(wp, OF_SET, &setargs);
    647 	if (argi < 0)
    648 		return 1;
    649 	/* set $# and $* */
    650 	if (setargs) {
    651 		owp = wp += argi - 1;
    652 		wp[0] = l->argv[0]; /* save $0 */
    653 		while (*++wp != NULL)
    654 			*wp = str_save(*wp, &l->area);
    655 		l->argc = wp - owp - 1;
    656 		l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
    657 		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
    658 			;
    659 	}
    660 	/* POSIX says set exit status is 0, but old scripts that use
    661 	 * getopt(1), use the construct: set -- `getopt ab:c "$@"`
    662 	 * which assumes the exit value set will be that of the ``
    663 	 * (subst_exstat is cleared in execute() so that it will be 0
    664 	 * if there are no command substitutions).
    665 	 */
    666 	return Flag(FPOSIX) ? 0 : subst_exstat;
    667 }
    668 
    669 int
    670 c_unset(wp)
    671 	char **wp;
    672 {
    673 	register char *id;
    674 	int optc, unset_var = 1;
    675 	int ret = 0;
    676 
    677 	while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
    678 		switch (optc) {
    679 		  case 'f':
    680 			unset_var = 0;
    681 			break;
    682 		  case 'v':
    683 			unset_var = 1;
    684 			break;
    685 		  case '?':
    686 			return 1;
    687 		}
    688 	wp += builtin_opt.optind;
    689 	for (; (id = *wp) != NULL; wp++)
    690 		if (unset_var) {	/* unset variable */
    691 			struct tbl *vp = global(id);
    692 
    693 			if ((vp->flag&RDONLY)) {
    694 				bi_errorf("%s is read only", vp->name);
    695 				return 1;
    696 			}
    697 			unset(vp, strchr(id, '[') ? 1 : 0);
    698 		} else {		/* unset function */
    699 			if (define(id, NULL))
    700 				ret = 1;
    701 		}
    702 	return ret;
    703 }
    704 
    705 int
    706 c_times(wp)
    707 	char **wp;
    708 {
    709 	struct tms all;
    710 
    711 	times(&all);
    712 	shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
    713 	shprintf("%8ss system\n", clocktos(all.tms_stime));
    714 	shprintf("Kids:  %8ss user ", clocktos(all.tms_cutime));
    715 	shprintf("%8ss system\n", clocktos(all.tms_cstime));
    716 
    717 	return 0;
    718 }
    719 
    720 /*
    721  * time pipeline (really a statement, not a built-in command)
    722  */
    723 int
    724 timex(t, f)
    725 	struct op *t;
    726 	int f;
    727 {
    728 #define TF_NOARGS	BIT(0)
    729 #define TF_NOREAL	BIT(1)		/* don't report real time */
    730 #define TF_POSIX	BIT(2)		/* report in posix format */
    731 	int rv = 0;
    732 	struct tms t0, t1, tms;
    733 	clock_t t0t, t1t = 0;
    734 	int tf = 0;
    735 	extern clock_t j_usrtime, j_systime; /* computed by j_wait */
    736 	char opts[1];
    737 
    738 	t0t = times(&t0);
    739 	if (t->left) {
    740 		/*
    741 		 * Two ways of getting cpu usage of a command: just use t0
    742 		 * and t1 (which will get cpu usage from other jobs that
    743 		 * finish while we are executing t->left), or get the
    744 		 * cpu usage of t->left. at&t ksh does the former, while
    745 		 * pdksh tries to do the later (the j_usrtime hack doesn't
    746 		 * really work as it only counts the last job).
    747 		 */
    748 		j_usrtime = j_systime = 0;
    749 		if (t->left->type == TCOM)
    750 			t->left->str = opts;
    751 		opts[0] = 0;
    752 		rv = execute(t->left, f | XTIME);
    753 		tf |= opts[0];
    754 		t1t = times(&t1);
    755 	} else
    756 		tf = TF_NOARGS;
    757 
    758 	if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
    759 		tf |= TF_NOREAL;
    760 		tms.tms_utime = t0.tms_utime + t0.tms_cutime;
    761 		tms.tms_stime = t0.tms_stime + t0.tms_cstime;
    762 	} else {
    763 		tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
    764 		tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
    765 	}
    766 
    767 	if (!(tf & TF_NOREAL))
    768 		shf_fprintf(shl_out,
    769 			tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
    770 			clocktos(t1t - t0t));
    771 	shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
    772 		clocktos(tms.tms_utime));
    773 	shf_fprintf(shl_out, tf & TF_POSIX ? "sys  %8s\n" : "%8ss system\n",
    774 		clocktos(tms.tms_stime));
    775 	shf_flush(shl_out);
    776 
    777 	return rv;
    778 }
    779 
    780 void
    781 timex_hook(t, app)
    782 	struct op *t;
    783 	char ** volatile *app;
    784 {
    785 	char **wp = *app;
    786 	int optc;
    787 	int i, j;
    788 	Getopt opt;
    789 
    790 	ksh_getopt_reset(&opt, 0);
    791 	opt.optind = 0;	/* start at the start */
    792 	while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
    793 		switch (optc) {
    794 		  case 'p':
    795 			t->str[0] |= TF_POSIX;
    796 			break;
    797 		  case '?':
    798 			errorf("time: -%s unknown option", opt.optarg);
    799 		  case ':':
    800 			errorf("time: -%s requires an argument",
    801 				opt.optarg);
    802 		}
    803 	/* Copy command words down over options. */
    804 	if (opt.optind != 0) {
    805 		for (i = 0; i < opt.optind; i++)
    806 			afree(wp[i], ATEMP);
    807 		for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
    808 			;
    809 	}
    810 	if (!wp[0])
    811 		t->str[0] |= TF_NOARGS;
    812 	*app = wp;
    813 }
    814 
    815 static char *
    816 clocktos(t)
    817 	clock_t t;
    818 {
    819 	static char temp[22]; /* enough for 64 bit clock_t */
    820 	register int i;
    821 	register char *cp = temp + sizeof(temp);
    822 
    823 	/* note: posix says must use max precision, ie, if clk_tck is
    824 	 * 1000, must print 3 places after decimal (if non-zero, else 1).
    825 	 */
    826 	if (CLK_TCK != 100)	/* convert to 1/100'ths */
    827 	    t = (t < (clock_t)(1000000000/CLK_TCK)) ?
    828 		    (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
    829 
    830 	*--cp = '\0';
    831 	for (i = -2; i <= 0 || t > 0; i++) {
    832 		if (i == 0)
    833 			*--cp = '.';
    834 		*--cp = '0' + (char)(t%10);
    835 		t /= 10;
    836 	}
    837 	return cp;
    838 }
    839 
    840 /* exec with no args - args case is taken care of in comexec() */
    841 int
    842 c_exec(wp)
    843 	char ** wp;
    844 {
    845 	int i;
    846 
    847 	/* make sure redirects stay in place */
    848 	if (e->savefd != NULL) {
    849 		for (i = 0; i < NUFILE; i++) {
    850 			if (e->savefd[i] > 0)
    851 				close(e->savefd[i]);
    852 			/*
    853 			 * For ksh keep anything > 2 private,
    854 			 * for sh, let them be (POSIX says what
    855 			 * happens is unspecified and the bourne shell
    856 			 * keeps them open).
    857 			 */
    858 #ifdef KSH
    859 			if (i > 2 && e->savefd[i])
    860 				fd_clexec(i);
    861 #endif /* KSH */
    862 		}
    863 		e->savefd = NULL;
    864 	}
    865 	return 0;
    866 }
    867 
    868 /* dummy function, special case in comexec() */
    869 int
    870 c_builtin(wp)
    871 	char ** wp;
    872 {
    873 	return 0;
    874 }
    875 
    876 extern	int c_test ARGS((char **wp));		/* in c_test.c */
    877 extern	int c_ulimit ARGS((char **wp));		/* in c_ulimit.c */
    878 
    879 /* A leading = means assignments before command are kept;
    880  * a leading * means a POSIX special builtin;
    881  * a leading + means a POSIX regular builtin
    882  * (* and + should not be combined).
    883  */
    884 const struct builtin shbuiltins [] = {
    885 	{"*=.", c_dot},
    886 	{"*=:", c_label},
    887 	{"[", c_test},
    888 	{"*=break", c_brkcont},
    889 	{"=builtin", c_builtin},
    890 	{"*=continue", c_brkcont},
    891 	{"*=eval", c_eval},
    892 	{"*=exec", c_exec},
    893 	{"*=exit", c_exitreturn},
    894 	{"+false", c_label},
    895 	{"*=return", c_exitreturn},
    896 	{"*=set", c_set},
    897 	{"*=shift", c_shift},
    898 	{"=times", c_times},
    899 	{"*=trap", c_trap},
    900 	{"+=wait", c_wait},
    901 	{"+read", c_read},
    902 	{"test", c_test},
    903 	{"+true", c_label},
    904 	{"ulimit", c_ulimit},
    905 	{"+umask", c_umask},
    906 	{"*=unset", c_unset},
    907 	{NULL, NULL}
    908 };
    909