GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/c_sh.c Lines: 226 428 52.8 %
Date: 2016-12-06 Branches: 146 334 43.7 %

Line Branch Exec Source
1
/*	$OpenBSD: c_sh.c,v 1.59 2016/03/04 15:11:06 deraadt Exp $	*/
2
3
/*
4
 * built-in Bourne commands
5
 */
6
7
#include <sys/resource.h>
8
#include <sys/stat.h>
9
#include <sys/time.h>
10
11
#include <ctype.h>
12
#include <errno.h>
13
#include <fcntl.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <unistd.h>
18
19
#include "sh.h"
20
21
static void p_time(struct shf *, int, struct timeval *, int, char *, char *);
22
23
/* :, false and true */
24
int
25
c_label(char **wp)
26
1280
{
27
1280
	return wp[0][0] == 'f' ? 1 : 0;
28
}
29
30
int
31
c_shift(char **wp)
32
134
{
33
134
	struct block *l = genv->loc;
34
	int n;
35
	long val;
36
	char *arg;
37
38
134
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
39
		return 1;
40
134
	arg = wp[builtin_opt.optind];
41
42
134
	if (arg) {
43
		evaluate(arg, &val, KSH_UNWIND_ERROR, false);
44
		n = val;
45
	} else
46
134
		n = 1;
47
134
	if (n < 0) {
48
		bi_errorf("%s: bad number", arg);
49
		return (1);
50
	}
51
134
	if (l->argc < n) {
52
		bi_errorf("nothing to shift");
53
		return (1);
54
	}
55
134
	l->argv[n] = l->argv[0];
56
134
	l->argv += n;
57
134
	l->argc -= n;
58
134
	return 0;
59
}
60
61
int
62
c_umask(char **wp)
63
14
{
64
	int i;
65
	char *cp;
66
14
	int symbolic = 0;
67
	mode_t old_umask;
68
	int optc;
69
70
28
	while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
71
		switch (optc) {
72
		case 'S':
73
			symbolic = 1;
74
			break;
75
		case '?':
76
			return 1;
77
		}
78
14
	cp = wp[builtin_opt.optind];
79
14
	if (cp == NULL) {
80
2
		old_umask = umask(0);
81
2
		umask(old_umask);
82
2
		if (symbolic) {
83
			char buf[18];
84
			int j;
85
86
			old_umask = ~old_umask;
87
			cp = buf;
88
			for (i = 0; i < 3; i++) {
89
				*cp++ = "ugo"[i];
90
				*cp++ = '=';
91
				for (j = 0; j < 3; j++)
92
					if (old_umask & (1 << (8 - (3*i + j))))
93
						*cp++ = "rwx"[j];
94
				*cp++ = ',';
95
			}
96
			cp[-1] = '\0';
97
			shprintf("%s\n", buf);
98
		} else
99
2
			shprintf("%#3.3o\n", old_umask);
100
	} else {
101
		mode_t new_umask;
102
103
12
		if (digit(*cp)) {
104
48
			for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
105
36
				new_umask = new_umask * 8 + (*cp - '0');
106
12
			if (*cp) {
107
				bi_errorf("bad number");
108
				return 1;
109
			}
110
		} else {
111
			/* symbolic format */
112
			int positions, new_val;
113
			char op;
114
115
			old_umask = umask(0);
116
			umask(old_umask); /* in case of error */
117
			old_umask = ~old_umask;
118
			new_umask = old_umask;
119
			positions = 0;
120
			while (*cp) {
121
				while (*cp && strchr("augo", *cp))
122
					switch (*cp++) {
123
					case 'a':
124
						positions |= 0111;
125
						break;
126
					case 'u':
127
						positions |= 0100;
128
						break;
129
					case 'g':
130
						positions |= 0010;
131
						break;
132
					case 'o':
133
						positions |= 0001;
134
						break;
135
					}
136
				if (!positions)
137
					positions = 0111; /* default is a */
138
				if (!strchr("=+-", op = *cp))
139
					break;
140
				cp++;
141
				new_val = 0;
142
				while (*cp && strchr("rwxugoXs", *cp))
143
					switch (*cp++) {
144
					case 'r': new_val |= 04; break;
145
					case 'w': new_val |= 02; break;
146
					case 'x': new_val |= 01; break;
147
					case 'u': new_val |= old_umask >> 6;
148
						  break;
149
					case 'g': new_val |= old_umask >> 3;
150
						  break;
151
					case 'o': new_val |= old_umask >> 0;
152
						  break;
153
					case 'X': if (old_umask & 0111)
154
							new_val |= 01;
155
						  break;
156
					case 's': /* ignored */
157
						  break;
158
					}
159
				new_val = (new_val & 07) * positions;
160
				switch (op) {
161
				case '-':
162
					new_umask &= ~new_val;
163
					break;
164
				case '=':
165
					new_umask = new_val |
166
					    (new_umask & ~(positions * 07));
167
					break;
168
				case '+':
169
					new_umask |= new_val;
170
				}
171
				if (*cp == ',') {
172
					positions = 0;
173
					cp++;
174
				} else if (!strchr("=+-", *cp))
175
					break;
176
			}
177
			if (*cp) {
178
				bi_errorf("bad mask");
179
				return 1;
180
			}
181
			new_umask = ~new_umask;
182
		}
183
12
		umask(new_umask);
184
	}
185
14
	return 0;
186
}
187
188
int
189
c_dot(char **wp)
190
14
{
191
	char *file, *cp;
192
	char **argv;
193
	int argc;
194
	int i;
195
	int err;
196
197
14
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
198
		return 1;
199
200
14
	if ((cp = wp[builtin_opt.optind]) == NULL)
201
		return 0;
202
14
	file = search(cp, path, R_OK, &err);
203
14
	if (file == NULL) {
204
4
		bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
205
		return 1;
206
	}
207
208
	/* Set positional parameters? */
209
10
	if (wp[builtin_opt.optind + 1]) {
210
		argv = wp + builtin_opt.optind;
211
		argv[0] = genv->loc->argv[0]; /* preserve $0 */
212
		for (argc = 0; argv[argc + 1]; argc++)
213
			;
214
	} else {
215
10
		argc = 0;
216
10
		argv = NULL;
217
	}
218
10
	i = include(file, argc, argv, 0);
219
10
	if (i < 0) { /* should not happen */
220
		bi_errorf("%s: %s", cp, strerror(errno));
221
		return 1;
222
	}
223
10
	return i;
224
}
225
226
int
227
c_wait(char **wp)
228
{
229
	int rv = 0;
230
	int sig;
231
232
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
233
		return 1;
234
	wp += builtin_opt.optind;
235
	if (*wp == NULL) {
236
		while (waitfor(NULL, &sig) >= 0)
237
			;
238
		rv = sig;
239
	} else {
240
		for (; *wp; wp++)
241
			rv = waitfor(*wp, &sig);
242
		if (rv < 0)
243
			rv = sig ? sig : 127; /* magic exit code: bad job-id */
244
	}
245
	return rv;
246
}
247
248
int
249
c_read(char **wp)
250
50
{
251
50
	int c = 0;
252
50
	int expand = 1, history = 0;
253
	int expanding;
254
50
	int ecode = 0;
255
	char *cp;
256
50
	int fd = 0;
257
	struct shf *shf;
258
	int optc;
259
	const char *emsg;
260
	XString cs, xs;
261
	struct tbl *vp;
262
50
	char *xp = NULL;
263
264
100
	while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1)
265
		switch (optc) {
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
		case 'r':
273
			expand = 0;
274
			break;
275
		case 's':
276
			history = 1;
277
			break;
278
		case 'u':
279
			if (!*(cp = builtin_opt.optarg))
280
				fd = 0;
281
			else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
282
				bi_errorf("-u: %s: %s", cp, emsg);
283
				return 1;
284
			}
285
			break;
286
		case '?':
287
			return 1;
288
		}
289
50
	wp += builtin_opt.optind;
290
291
50
	if (*wp == NULL)
292
2
		*--wp = "REPLY";
293
294
	/* Since we can't necessarily seek backwards on non-regular files,
295
	 * don't buffer them so we can't read too much.
296
	 */
297
50
	shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
298
299
50
	if ((cp = strchr(*wp, '?')) != NULL) {
300
		*cp = 0;
301
		if (isatty(fd)) {
302
			/* at&t ksh says it prints prompt on fd if it's open
303
			 * for writing and is a tty, but it doesn't do it
304
			 * (it also doesn't check the interactive flag,
305
			 * as is indicated in the Kornshell book).
306
			 */
307
			shellf("%s", cp+1);
308
		}
309
	}
310
311
	/* If we are reading from the co-process for the first time,
312
	 * make sure the other side of the pipe is closed first.  This allows
313
	 * the detection of eof.
314
	 *
315
	 * This is not compatible with at&t ksh... the fd is kept so another
316
	 * coproc can be started with same output, however, this means eof
317
	 * can't be detected...  This is why it is closed here.
318
	 * If this call is removed, remove the eof check below, too.
319
	 * coproc_readw_close(fd);
320
	 */
321
322
50
	if (history)
323
		Xinit(xs, xp, 128, ATEMP);
324
50
	expanding = 0;
325
50
	Xinit(cs, cp, 128, ATEMP);
326
136
	for (; *wp != NULL; wp++) {
327
86
		for (cp = Xstring(cs, cp); ; ) {
328
996
			if (c == '\n' || c == EOF)
329
8
				break;
330
			while (1) {
331
988
				c = shf_getc(shf);
332
988
				if (c == '\0')
333
					continue;
334

988
				if (c == EOF && shf_error(shf) &&
335
				    shf->errno_ == EINTR) {
336
					/* Was the offending signal one that
337
					 * would normally kill a process?
338
					 * If so, pretend the read was killed.
339
					 */
340
					ecode = fatal_trap_check();
341
342
					/* non fatal (eg, CHLD), carry on */
343
					if (!ecode) {
344
						shf_clearerr(shf);
345
						continue;
346
					}
347
				}
348
				break;
349
			}
350
988
			if (history) {
351
				Xcheck(xs, xp);
352
				Xput(xs, xp, c);
353
			}
354
988
			Xcheck(cs, cp);
355
988
			if (expanding) {
356
				expanding = 0;
357
				if (c == '\n') {
358
					c = 0;
359
					if (Flag(FTALKING_I) && isatty(fd)) {
360
						/* set prompt in case this is
361
						 * called from .profile or $ENV
362
						 */
363
						set_prompt(PS2, NULL);
364
						pprompt(prompt, 0);
365
					}
366
				} else if (c != EOF)
367
					Xput(cs, cp, c);
368
				continue;
369
			}
370
988
			if (expand && c == '\\') {
371
				expanding = 1;
372
				continue;
373
			}
374
988
			if (c == '\n' || c == EOF)
375
50
				break;
376
938
			if (ctype(c, C_IFS)) {
377

32
				if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
378
					continue;
379
32
				if (wp[1])
380
28
					break;
381
			}
382
910
			Xput(cs, cp, c);
383
		}
384
		/* strip trailing IFS white space from last variable */
385
86
		if (!wp[1])
386

52
			while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) &&
387
			    ctype(cp[-1], C_IFSWS))
388
2
				cp--;
389
86
		Xput(cs, cp, '\0');
390
86
		vp = global(*wp);
391
		/* Must be done before setting export. */
392
86
		if (vp->flag & RDONLY) {
393
			shf_flush(shf);
394
			bi_errorf("%s is read only", *wp);
395
			return 1;
396
		}
397
86
		if (Flag(FEXPORT))
398
			typeset(*wp, EXPORT, 0, 0, 0);
399
86
		if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
400
		    shf_flush(shf);
401
		    return 1;
402
		}
403
	}
404
405
50
	shf_flush(shf);
406
50
	if (history) {
407
		Xput(xs, xp, '\0');
408
		source->line++;
409
		histsave(source->line, Xstring(xs, xp), 1);
410
		Xfree(xs, xp);
411
	}
412
	/* if this is the co-process fd, close the file descriptor
413
	 * (can get eof if and only if all processes are have died, ie,
414
	 * coproc.njobs is 0 and the pipe is closed).
415
	 */
416
50
	if (c == EOF && !ecode)
417
10
		coproc_read_close(fd);
418
419
50
	return ecode ? ecode : c == EOF;
420
}
421
422
int
423
c_eval(char **wp)
424
8246
{
425
	struct source *s;
426
	int rv;
427
428
8246
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
429
		return 1;
430
8246
	s = pushs(SWORDS, ATEMP);
431
8246
	s->u.strv = wp + builtin_opt.optind;
432
8246
	if (!Flag(FPOSIX)) {
433
		/*
434
		 * Handle case where the command is empty due to failed
435
		 * command substitution, eg, eval "$(false)".
436
		 * In this case, shell() will not set/change exstat (because
437
		 * compiled tree is empty), so will use this value.
438
		 * subst_exstat is cleared in execute(), so should be 0 if
439
		 * there were no substitutions.
440
		 *
441
		 * A strict reading of POSIX says we don't do this (though
442
		 * it is traditionally done). [from 1003.2-1992]
443
		 *    3.9.1: Simple Commands
444
		 *	... If there is a command name, execution shall
445
		 *	continue as described in 3.9.1.1.  If there
446
		 *	is no command name, but the command contained a command
447
		 *	substitution, the command shall complete with the exit
448
		 *	status of the last command substitution
449
		 *    3.9.1.1: Command Search and Execution
450
		 *	...(1)...(a) If the command name matches the name of
451
		 *	a special built-in utility, that special built-in
452
		 *	utility shall be invoked.
453
		 * 3.14.5: Eval
454
		 *	... If there are no arguments, or only null arguments,
455
		 *	eval shall return an exit status of zero.
456
		 */
457
3682
		exstat = subst_exstat;
458
	}
459
460
8246
	rv = shell(s, false);
461
8245
	afree(s, ATEMP);
462
8245
	return (rv);
463
}
464
465
int
466
c_trap(char **wp)
467
31
{
468
	int i;
469
	char *s;
470
	Trap *p;
471
472
31
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
473
		return 1;
474
31
	wp += builtin_opt.optind;
475
476
31
	if (*wp == NULL) {
477
		for (p = sigtraps, i = NSIG+1; --i >= 0; p++) {
478
			if (p->trap != NULL) {
479
				shprintf("trap -- ");
480
				print_value_quoted(p->trap);
481
				shprintf(" %s\n", p->name);
482
			}
483
		}
484
		return 0;
485
	}
486
487
	/*
488
	 * Use case sensitive lookup for first arg so the
489
	 * command 'exit' isn't confused with the pseudo-signal
490
	 * 'EXIT'.
491
	 */
492
31
	s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; /* get command */
493

31
	if (s != NULL && s[0] == '-' && s[1] == '\0')
494
		s = NULL;
495
496
	/* set/clear traps */
497
74
	while (*wp != NULL) {
498
43
		p = gettrap(*wp++, true);
499
43
		if (p == NULL) {
500
			bi_errorf("bad signal %s", wp[-1]);
501
			return 1;
502
		}
503
43
		settrap(p, s);
504
	}
505
31
	return 0;
506
}
507
508
int
509
c_exitreturn(char **wp)
510
398
{
511
398
	int how = LEXIT;
512
	int n;
513
	char *arg;
514
515
398
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
516
		return 1;
517
398
	arg = wp[builtin_opt.optind];
518
519
398
	if (arg) {
520
388
		if (!getn(arg, &n)) {
521
			exstat = 1;
522
			warningf(true, "%s: bad number", arg);
523
		} else
524
388
			exstat = n;
525
	}
526
398
	if (wp[0][0] == 'r') { /* return */
527
		struct env *ep;
528
529
		/* need to tell if this is exit or return so trap exit will
530
		 * work right (POSIX)
531
		 */
532
596
		for (ep = genv; ep; ep = ep->oenv)
533
596
			if (STOP_RETURN(ep->type)) {
534
196
				how = LRETURN;
535
196
				break;
536
			}
537
	}
538
539

398
	if (how == LEXIT && !really_exit && j_stopped_running()) {
540
		really_exit = 1;
541
		how = LSHELL;
542
	}
543
544
398
	quitenv(NULL);	/* get rid of any i/o redirections */
545
398
	unwind(how);
546
	/* NOTREACHED */
547
	return 0;
548
}
549
550
int
551
c_brkcont(char **wp)
552
196
{
553
	int n, quit;
554
196
	struct env *ep, *last_ep = NULL;
555
	char *arg;
556
557
196
	if (ksh_getopt(wp, &builtin_opt, null) == '?')
558
		return 1;
559
196
	arg = wp[builtin_opt.optind];
560
561
196
	if (!arg)
562
161
		n = 1;
563
35
	else if (!bi_getn(arg, &n))
564
		return 1;
565
192
	quit = n;
566
192
	if (quit <= 0) {
567
		/* at&t ksh does this for non-interactive shells only - weird */
568
		bi_errorf("%s: bad value", arg);
569
		return 1;
570
	}
571
572
	/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
573

777
	for (ep = genv; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
574
765
		if (ep->type == E_LOOP) {
575
205
			if (--quit == 0)
576
180
				break;
577
25
			ep->flags |= EF_BRKCONT_PASS;
578
25
			last_ep = ep;
579
		}
580
581
192
	if (quit) {
582
		/* at&t ksh doesn't print a message - just does what it
583
		 * can.  We print a message 'cause it helps in debugging
584
		 * scripts, but don't generate an error (ie, keep going).
585
		 */
586
12
		if (n == quit) {
587
4
			warningf(true, "%s: cannot %s", wp[0], wp[0]);
588
4
			return 0;
589
		}
590
		/* POSIX says if n is too big, the last enclosing loop
591
		 * shall be used.  Doesn't say to print an error but we
592
		 * do anyway 'cause the user messed up.
593
		 */
594
8
		if (last_ep)
595
8
			last_ep->flags &= ~EF_BRKCONT_PASS;
596
8
		warningf(true, "%s: can only %s %d level(s)",
597
		    wp[0], wp[0], n - quit);
598
	}
599
600
188
	unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
601
	/* NOTREACHED */
602
}
603
604
int
605
c_set(char **wp)
606
1551
{
607
	int argi, setargs;
608
1551
	struct block *l = genv->loc;
609
1551
	char **owp = wp;
610
611
1551
	if (wp[1] == NULL) {
612
		static const char *const args [] = { "set", "-", NULL };
613
18
		return c_typeset((char **) args);
614
	}
615
616
1533
	argi = parse_args(wp, OF_SET, &setargs);
617
1533
	if (argi < 0)
618
		return 1;
619
	/* set $# and $* */
620
1533
	if (setargs) {
621
118
		owp = wp += argi - 1;
622
118
		wp[0] = l->argv[0]; /* save $0 */
623
538
		while (*++wp != NULL)
624
302
			*wp = str_save(*wp, &l->area);
625
118
		l->argc = wp - owp - 1;
626
118
		l->argv = areallocarray(NULL, l->argc+2, sizeof(char *), &l->area);
627
118
		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
628
			;
629
	}
630
	/* POSIX says set exit status is 0, but old scripts that use
631
	 * getopt(1), use the construct: set -- `getopt ab:c "$@"`
632
	 * which assumes the exit value set will be that of the ``
633
	 * (subst_exstat is cleared in execute() so that it will be 0
634
	 * if there are no command substitutions).
635
	 */
636
1533
	return Flag(FPOSIX) ? 0 : subst_exstat;
637
}
638
639
int
640
c_unset(char **wp)
641
250
{
642
	char *id;
643
250
	int optc, unset_var = 1;
644
645
502
	while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
646

2
		switch (optc) {
647
		case 'f':
648
2
			unset_var = 0;
649
2
			break;
650
		case 'v':
651
			unset_var = 1;
652
			break;
653
		case '?':
654
			return 1;
655
		}
656
250
	wp += builtin_opt.optind;
657
507
	for (; (id = *wp) != NULL; wp++)
658
257
		if (unset_var) {	/* unset variable */
659
255
			struct tbl *vp = global(id);
660
661
255
			if ((vp->flag&RDONLY)) {
662
				bi_errorf("%s is read only", vp->name);
663
				return 1;
664
			}
665
255
			unset(vp, strchr(id, '[') ? 1 : 0);
666
		} else {		/* unset function */
667
2
			define(id, NULL);
668
		}
669
250
	return 0;
670
}
671
672
static void
673
p_time(struct shf *shf, int posix, struct timeval *tv, int width, char *prefix,
674
    char *suffix)
675
6
{
676
6
	if (posix)
677
		shf_fprintf(shf, "%s%*lld.%02ld%s", prefix ? prefix : "",
678
		    width, (long long)tv->tv_sec, tv->tv_usec / 10000, suffix);
679
	else
680
6
		shf_fprintf(shf, "%s%*lldm%02lld.%02lds%s", prefix ? prefix : "",
681
		    width, (long long)tv->tv_sec / 60,
682
		    (long long)tv->tv_sec % 60,
683
		    tv->tv_usec / 10000, suffix);
684
6
}
685
686
int
687
c_times(char **wp)
688
{
689
	struct rusage usage;
690
691
	(void) getrusage(RUSAGE_SELF, &usage);
692
	p_time(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
693
	p_time(shl_stdout, 0, &usage.ru_stime, 0, NULL, "\n");
694
695
	(void) getrusage(RUSAGE_CHILDREN, &usage);
696
	p_time(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
697
	p_time(shl_stdout, 0, &usage.ru_stime, 0, NULL, "\n");
698
699
	return 0;
700
}
701
702
/*
703
 * time pipeline (really a statement, not a built-in command)
704
 */
705
int
706
timex(struct op *t, int f, volatile int *xerrok)
707
2
{
708
#define TF_NOARGS	BIT(0)
709
#define TF_NOREAL	BIT(1)		/* don't report real time */
710
#define TF_POSIX	BIT(2)		/* report in posix format */
711
2
	int rv = 0;
712
	struct rusage ru0, ru1, cru0, cru1;
713
	struct timeval usrtime, systime, tv0, tv1;
714
2
	int tf = 0;
715
	extern struct timeval j_usrtime, j_systime; /* computed by j_wait */
716
717
2
	gettimeofday(&tv0, NULL);
718
2
	getrusage(RUSAGE_SELF, &ru0);
719
2
	getrusage(RUSAGE_CHILDREN, &cru0);
720
2
	if (t->left) {
721
		/*
722
		 * Two ways of getting cpu usage of a command: just use t0
723
		 * and t1 (which will get cpu usage from other jobs that
724
		 * finish while we are executing t->left), or get the
725
		 * cpu usage of t->left. at&t ksh does the former, while
726
		 * pdksh tries to do the later (the j_usrtime hack doesn't
727
		 * really work as it only counts the last job).
728
		 */
729
2
		timerclear(&j_usrtime);
730
2
		timerclear(&j_systime);
731
2
		rv = execute(t->left, f | XTIME, xerrok);
732
2
		if (t->left->type == TCOM)
733
2
			tf |= t->left->str[0];
734
2
		gettimeofday(&tv1, NULL);
735
2
		getrusage(RUSAGE_SELF, &ru1);
736
2
		getrusage(RUSAGE_CHILDREN, &cru1);
737
	} else
738
		tf = TF_NOARGS;
739
740
2
	if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
741
		tf |= TF_NOREAL;
742
		timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime);
743
		timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime);
744
	} else {
745
2
		timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime);
746
2
		timeradd(&usrtime, &j_usrtime, &usrtime);
747
2
		timersub(&ru1.ru_stime, &ru0.ru_stime, &systime);
748
2
		timeradd(&systime, &j_systime, &systime);
749
	}
750
751
2
	if (!(tf & TF_NOREAL)) {
752
2
		timersub(&tv1, &tv0, &tv1);
753
2
		if (tf & TF_POSIX)
754
			p_time(shl_out, 1, &tv1, 5, "real ", "\n");
755
		else
756
2
			p_time(shl_out, 0, &tv1, 5, NULL, " real ");
757
	}
758
2
	if (tf & TF_POSIX)
759
		p_time(shl_out, 1, &usrtime, 5, "user ", "\n");
760
	else
761
2
		p_time(shl_out, 0, &usrtime, 5, NULL, " user ");
762
2
	if (tf & TF_POSIX)
763
		p_time(shl_out, 1, &systime, 5, "sys  ", "\n");
764
	else
765
2
		p_time(shl_out, 0, &systime, 5, NULL, " system\n");
766
2
	shf_flush(shl_out);
767
768
2
	return rv;
769
}
770
771
void
772
timex_hook(struct op *t, char **volatile *app)
773
2
{
774
2
	char **wp = *app;
775
	int optc;
776
	int i, j;
777
	Getopt opt;
778
779
2
	ksh_getopt_reset(&opt, 0);
780
2
	opt.optind = 0;	/* start at the start */
781
4
	while ((optc = ksh_getopt(wp, &opt, ":p")) != -1)
782
		switch (optc) {
783
		case 'p':
784
			t->str[0] |= TF_POSIX;
785
			break;
786
		case '?':
787
			errorf("time: -%s unknown option", opt.optarg);
788
		case ':':
789
			errorf("time: -%s requires an argument",
790
			    opt.optarg);
791
		}
792
	/* Copy command words down over options. */
793
2
	if (opt.optind != 0) {
794
		for (i = 0; i < opt.optind; i++)
795
			afree(wp[i], ATEMP);
796
		for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
797
			;
798
	}
799
2
	if (!wp[0])
800
		t->str[0] |= TF_NOARGS;
801
2
	*app = wp;
802
2
}
803
804
/* exec with no args - args case is taken care of in comexec() */
805
int
806
c_exec(char **wp)
807
15
{
808
	int i;
809
810
	/* make sure redirects stay in place */
811
15
	if (genv->savefd != NULL) {
812
495
		for (i = 0; i < NUFILE; i++) {
813
480
			if (genv->savefd[i] > 0)
814
12
				close(genv->savefd[i]);
815
			/*
816
			 * For ksh keep anything > 2 private,
817
			 * for sh, let them be (POSIX says what
818
			 * happens is unspecified and the bourne shell
819
			 * keeps them open).
820
			 */
821

480
			if (!Flag(FSH) && i > 2 && genv->savefd[i])
822
				fcntl(i, F_SETFD, FD_CLOEXEC);
823
		}
824
15
		genv->savefd = NULL;
825
	}
826
15
	return 0;
827
}
828
829
static int
830
c_suspend(char **wp)
831
{
832
	if (wp[1] != NULL) {
833
		bi_errorf("too many arguments");
834
		return 1;
835
	}
836
	if (Flag(FLOGIN)) {
837
		/* Can't suspend an orphaned process group. */
838
		pid_t parent = getppid();
839
		if (getpgid(parent) == getpgid(0) ||
840
		    getsid(parent) != getsid(0)) {
841
			bi_errorf("can't suspend a login shell");
842
			return 1;
843
		}
844
	}
845
	j_suspend();
846
	return 0;
847
}
848
849
/* dummy function, special case in comexec() */
850
int
851
c_builtin(char **wp)
852
{
853
	return 0;
854
}
855
856
extern	int c_test(char **wp);			/* in c_test.c */
857
extern	int c_ulimit(char **wp);		/* in c_ulimit.c */
858
859
/* A leading = means assignments before command are kept;
860
 * a leading * means a POSIX special builtin;
861
 * a leading + means a POSIX regular builtin
862
 * (* and + should not be combined).
863
 */
864
const struct builtin shbuiltins [] = {
865
	{"*=.", c_dot},
866
	{"*=:", c_label},
867
	{"[", c_test},
868
	{"*=break", c_brkcont},
869
	{"=builtin", c_builtin},
870
	{"*=continue", c_brkcont},
871
	{"*=eval", c_eval},
872
	{"*=exec", c_exec},
873
	{"*=exit", c_exitreturn},
874
	{"+false", c_label},
875
	{"*=return", c_exitreturn},
876
	{"*=set", c_set},
877
	{"*=shift", c_shift},
878
	{"*=times", c_times},
879
	{"*=trap", c_trap},
880
	{"+=wait", c_wait},
881
	{"+read", c_read},
882
	{"test", c_test},
883
	{"+true", c_label},
884
	{"ulimit", c_ulimit},
885
	{"+umask", c_umask},
886
	{"*=unset", c_unset},
887
	{"suspend", c_suspend},
888
	{NULL, NULL}
889
};