1/*	$OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $	*/
2/*	$OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $	*/
3/*	$OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $	*/
4/*	$OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $	*/
5
6/*-
7 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
8 *		 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
9 *	mirabilos <m@mirbsd.org>
10 *
11 * Provided that these terms and disclaimer and all copyright notices
12 * are retained or reproduced in an accompanying document, permission
13 * is granted to deal in this work without restriction, including un-
14 * limited rights to use, publicly perform, distribute, sell, modify,
15 * merge, give away, or sublicence.
16 *
17 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
18 * the utmost extent permitted by applicable law, neither express nor
19 * implied; without malicious intent or gross negligence. In no event
20 * may a licensor, author or contributor be held liable for indirect,
21 * direct, other damage, loss, or other issues arising in any way out
22 * of dealing in the work, even if advised of the possibility of such
23 * damage or existence of a defect, except proven that it results out
24 * of said person's immediate fault when using the work as intended.
25 */
26
27#include "sh.h"
28
29#if HAVE_SELECT
30#if HAVE_SYS_BSDTYPES_H
31#include <sys/bsdtypes.h>
32#endif
33#if HAVE_SYS_SELECT_H
34#include <sys/select.h>
35#endif
36#if HAVE_BSTRING_H
37#include <bstring.h>
38#endif
39#endif
40
41__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.353 2018/01/14 01:26:49 tg Exp $");
42
43#if HAVE_KILLPG
44/*
45 * use killpg if < -1 since -1 does special things
46 * for some non-killpg-endowed kills
47 */
48#define mksh_kill(p,s)	((p) < -1 ? killpg(-(p), (s)) : kill((p), (s)))
49#else
50/* cross fingers and hope kill is killpg-endowed */
51#define mksh_kill	kill
52#endif
53
54/* XXX conditions correct? */
55#if !defined(RLIM_INFINITY) && !defined(MKSH_NO_LIMITS)
56#define MKSH_NO_LIMITS	1
57#endif
58
59#ifdef MKSH_NO_LIMITS
60#define c_ulimit	c_true
61#endif
62
63#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
64static int c_suspend(const char **);
65#endif
66
67static int do_whence(const char **, int, bool, bool);
68
69/* getn() that prints error */
70static int
71bi_getn(const char *as, int *ai)
72{
73	int rv;
74
75	if (!(rv = getn(as, ai)))
76		bi_errorf(Tf_sD_s, Tbadnum, as);
77	return (rv);
78}
79
80static int
81c_true(const char **wp MKSH_A_UNUSED)
82{
83	return (0);
84}
85
86static int
87c_false(const char **wp MKSH_A_UNUSED)
88{
89	return (1);
90}
91
92/*
93 * A leading = means assignments before command are kept.
94 * A leading * means a POSIX special builtin.
95 * A leading ^ means declaration utility, - forwarder.
96 */
97const struct builtin mkshbuiltins[] = {
98	{Tsgdot, c_dot},
99	{"*=:", c_true},
100	{Tbracket, c_test},
101	/* no =: AT&T manual wrong */
102	{Talias, c_alias},
103	{Tsgbreak, c_brkcont},
104	{T__builtin, c_builtin},
105	{Tbuiltin, c_builtin},
106#if !defined(__ANDROID__)
107	{Tbcat, c_cat},
108#endif
109	{Tcd, c_cd},
110	/* dash compatibility hack */
111	{"chdir", c_cd},
112	{T_command, c_command},
113	{Tsgcontinue, c_brkcont},
114	{"echo", c_print},
115	{"*=eval", c_eval},
116	{"*=exec", c_exec},
117	{"*=exit", c_exitreturn},
118	{Tdsgexport, c_typeset},
119	{Tfalse, c_false},
120	{"fc", c_fc},
121	{Tgetopts, c_getopts},
122	/* deprecated, replaced by typeset -g */
123	{"^=global", c_typeset},
124	{Tjobs, c_jobs},
125	{"kill", c_kill},
126	{"let", c_let},
127	{"print", c_print},
128	{"pwd", c_pwd},
129	{Tread, c_read},
130	{Tdsgreadonly, c_typeset},
131#if !defined(__ANDROID__)
132	{"!realpath", c_realpath},
133#endif
134	{"~rename", c_rename},
135	{"*=return", c_exitreturn},
136	{Tsgset, c_set},
137	{"*=shift", c_shift},
138	{Tgsource, c_dot},
139#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
140	{Tsuspend, c_suspend},
141#endif
142	{"test", c_test},
143	{"*=times", c_times},
144	{"*=trap", c_trap},
145	{Ttrue, c_true},
146	{Tdgtypeset, c_typeset},
147	{"ulimit", c_ulimit},
148	{"umask", c_umask},
149	{Tunalias, c_unalias},
150	{"*=unset", c_unset},
151	{"wait", c_wait},
152	{"whence", c_whence},
153#ifndef MKSH_UNEMPLOYED
154	{Tbg, c_fgbg},
155	{Tfg, c_fgbg},
156#endif
157#ifndef MKSH_NO_CMDLINE_EDITING
158	{"bind", c_bind},
159#endif
160#if HAVE_MKNOD
161	{"mknod", c_mknod},
162#endif
163#ifdef MKSH_PRINTF_BUILTIN
164	{"~printf", c_printf},
165#endif
166#if HAVE_SELECT
167#if !defined(__ANDROID__)
168	{"sleep", c_sleep},
169#endif
170#endif
171#ifdef __MirBSD__
172	/* alias to "true" for historical reasons */
173	{"domainname", c_true},
174#endif
175#ifdef __OS2__
176	{Textproc, c_true},
177#endif
178	{NULL, (int (*)(const char **))NULL}
179};
180
181struct kill_info {
182	int num_width;
183	int name_width;
184};
185
186static const struct t_op {
187	char op_text[4];
188	Test_op op_num;
189} u_ops[] = {
190	{"-a",	TO_FILAXST },
191	{"-b",	TO_FILBDEV },
192	{"-c",	TO_FILCDEV },
193	{"-d",	TO_FILID },
194	{"-e",	TO_FILEXST },
195	{"-f",	TO_FILREG },
196	{"-G",	TO_FILGID },
197	{"-g",	TO_FILSETG },
198	{"-H",	TO_FILCDF },
199	{"-h",	TO_FILSYM },
200	{"-k",	TO_FILSTCK },
201	{"-L",	TO_FILSYM },
202	{"-n",	TO_STNZE },
203	{"-O",	TO_FILUID },
204	{"-o",	TO_OPTION },
205	{"-p",	TO_FILFIFO },
206	{"-r",	TO_FILRD },
207	{"-S",	TO_FILSOCK },
208	{"-s",	TO_FILGZ },
209	{"-t",	TO_FILTT },
210	{"-u",	TO_FILSETU },
211	{"-v",	TO_ISSET },
212	{"-w",	TO_FILWR },
213	{"-x",	TO_FILEX },
214	{"-z",	TO_STZER },
215	{"",	TO_NONOP }
216};
217static const struct t_op b_ops[] = {
218	{"=",	TO_STEQL },
219	{"==",	TO_STEQL },
220	{"!=",	TO_STNEQ },
221	{"<",	TO_STLT },
222	{">",	TO_STGT },
223	{"-eq",	TO_INTEQ },
224	{"-ne",	TO_INTNE },
225	{"-gt",	TO_INTGT },
226	{"-ge",	TO_INTGE },
227	{"-lt",	TO_INTLT },
228	{"-le",	TO_INTLE },
229	{"-ef",	TO_FILEQ },
230	{"-nt",	TO_FILNT },
231	{"-ot",	TO_FILOT },
232	{"",	TO_NONOP }
233};
234
235static int test_oexpr(Test_env *, bool);
236static int test_aexpr(Test_env *, bool);
237static int test_nexpr(Test_env *, bool);
238static int test_primary(Test_env *, bool);
239static Test_op ptest_isa(Test_env *, Test_meta);
240static const char *ptest_getopnd(Test_env *, Test_op, bool);
241static void ptest_error(Test_env *, int, const char *);
242static void kill_fmt_entry(char *, size_t, unsigned int, const void *);
243static void p_time(struct shf *, bool, long, int, int,
244    const char *, const char *);
245
246int
247c_pwd(const char **wp)
248{
249	int optc;
250	bool physical = tobool(Flag(FPHYSICAL));
251	char *p, *allocd = NULL;
252
253	while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
254		switch (optc) {
255		case 'L':
256			physical = false;
257			break;
258		case 'P':
259			physical = true;
260			break;
261		case '?':
262			return (1);
263		}
264	wp += builtin_opt.optind;
265
266	if (wp[0]) {
267		bi_errorf(Ttoo_many_args);
268		return (1);
269	}
270	p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) :
271	    current_wd) : NULL;
272	/* LINTED use of access */
273	if (p && access(p, R_OK) < 0)
274		p = NULL;
275	if (!p && !(p = allocd = ksh_get_wd())) {
276		bi_errorf(Tf_sD_s, "can't determine current directory",
277		    cstrerror(errno));
278		return (1);
279	}
280	shprintf(Tf_sN, p);
281	afree(allocd, ATEMP);
282	return (0);
283}
284
285static const char *s_ptr;
286static int s_get(void);
287static void s_put(int);
288
289int
290c_print(const char **wp)
291{
292	int c;
293	const char *s;
294	char *xp;
295	XString xs;
296	struct {
297		/* storage for columnisation */
298		XPtrV words;
299		/* temporary storage for a wide character */
300		mksh_ari_t wc;
301		/* output file descriptor (if any) */
302		int fd;
303		/* temporary storage for a multibyte character */
304		char ts[4];
305		/* output word separator */
306		char ws;
307		/* output line separator */
308		char ls;
309		/* output a trailing line separator? */
310		bool nl;
311		/* expand backslash sequences? */
312		bool exp;
313		/* columnise output? */
314		bool col;
315		/* print to history instead of file descriptor / stdout? */
316		bool hist;
317		/* print words as wide characters? */
318		bool chars;
319		/* writing to a coprocess (SIGPIPE blocked)? */
320		bool coproc;
321		bool copipe;
322	} po;
323
324	memset(&po, 0, sizeof(po));
325	po.fd = 1;
326	po.ws = ' ';
327	po.ls = '\n';
328	po.nl = true;
329
330	if (wp[0][0] == 'e') {
331		/* "echo" builtin */
332		if (Flag(FPOSIX) ||
333#ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
334		    Flag(FSH) ||
335#endif
336		    Flag(FAS_BUILTIN)) {
337			/* BSD "echo" cmd, Debian Policy 10.4 compliant */
338			++wp;
339 bsd_echo:
340			if (*wp && !strcmp(*wp, "-n")) {
341				po.nl = false;
342				++wp;
343			}
344			po.exp = false;
345		} else {
346			bool new_exp, new_nl = true;
347
348			/*-
349			 * compromise between various historic echos: only
350			 * recognise -Een if they appear in arguments with
351			 * no illegal options; e.g. echo -nq outputs '-nq'
352			 */
353#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
354			/* MidnightBSD /bin/sh needs -e supported but off */
355			if (Flag(FSH))
356				new_exp = false;
357			else
358#endif
359			/* otherwise compromise on -e enabled by default */
360			  new_exp = true;
361			goto print_tradparse_beg;
362
363 print_tradparse_arg:
364			if ((s = *wp) && *s++ == '-' && *s) {
365 print_tradparse_ch:
366				switch ((c = *s++)) {
367				case 'E':
368					new_exp = false;
369					goto print_tradparse_ch;
370				case 'e':
371					new_exp = true;
372					goto print_tradparse_ch;
373				case 'n':
374					new_nl = false;
375					goto print_tradparse_ch;
376				case '\0':
377 print_tradparse_beg:
378					po.exp = new_exp;
379					po.nl = new_nl;
380					++wp;
381					goto print_tradparse_arg;
382				}
383			}
384		}
385	} else {
386		/* "print" builtin */
387		const char *opts = "AcelNnpRrsu,";
388		const char *emsg;
389
390		po.exp = true;
391
392		while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
393			switch (c) {
394			case 'A':
395				po.chars = true;
396				break;
397			case 'c':
398				po.col = true;
399				break;
400			case 'e':
401				po.exp = true;
402				break;
403			case 'l':
404				po.ws = '\n';
405				break;
406			case 'N':
407				po.ws = '\0';
408				po.ls = '\0';
409				break;
410			case 'n':
411				po.nl = false;
412				break;
413			case 'p':
414				if ((po.fd = coproc_getfd(W_OK, &emsg)) < 0) {
415					bi_errorf(Tf_coproc, emsg);
416					return (1);
417				}
418				break;
419			case 'R':
420				/* fake BSD echo but don't reset other flags */
421				wp += builtin_opt.optind;
422				goto bsd_echo;
423			case 'r':
424				po.exp = false;
425				break;
426			case 's':
427				po.hist = true;
428				break;
429			case 'u':
430				if (!*(s = builtin_opt.optarg))
431					po.fd = 0;
432				else if ((po.fd = check_fd(s, W_OK, &emsg)) < 0) {
433					bi_errorf("-u%s: %s", s, emsg);
434					return (1);
435				}
436				break;
437			case '?':
438				return (1);
439			}
440
441		if (!(builtin_opt.info & GI_MINUSMINUS)) {
442			/* treat a lone "-" like "--" */
443			if (wp[builtin_opt.optind] &&
444			    ksh_isdash(wp[builtin_opt.optind]))
445				builtin_opt.optind++;
446		}
447		wp += builtin_opt.optind;
448	}
449
450	if (po.col) {
451		if (*wp == NULL)
452			return (0);
453
454		XPinit(po.words, 16);
455	}
456
457	Xinit(xs, xp, 128, ATEMP);
458
459	if (*wp == NULL)
460		goto print_no_arg;
461 print_read_arg:
462	if (po.chars) {
463		while (*wp != NULL) {
464			s = *wp++;
465			if (*s == '\0')
466				break;
467			if (!evaluate(s, &po.wc, KSH_RETURN_ERROR, true))
468				return (1);
469			Xcheck(xs, xp);
470			if (UTFMODE) {
471				po.ts[utf_wctomb(po.ts, po.wc)] = 0;
472				c = 0;
473				do {
474					Xput(xs, xp, po.ts[c]);
475				} while (po.ts[++c]);
476			} else
477				Xput(xs, xp, po.wc & 0xFF);
478		}
479	} else {
480		s = *wp++;
481		while ((c = *s++) != '\0') {
482			Xcheck(xs, xp);
483			if (po.exp && c == '\\') {
484				s_ptr = s;
485				c = unbksl(false, s_get, s_put);
486				s = s_ptr;
487				if (c == -1) {
488					/* rejected by generic function */
489					switch ((c = *s++)) {
490					case 'c':
491						po.nl = false;
492						/* AT&T brain damage */
493						continue;
494					case '\0':
495						--s;
496						c = '\\';
497						break;
498					default:
499						Xput(xs, xp, '\\');
500					}
501				} else if ((unsigned int)c > 0xFF) {
502					/* generic function returned Unicode */
503					po.ts[utf_wctomb(po.ts, c - 0x100)] = 0;
504					c = 0;
505					do {
506						Xput(xs, xp, po.ts[c]);
507					} while (po.ts[++c]);
508					continue;
509				}
510			}
511			Xput(xs, xp, c);
512		}
513	}
514	if (po.col) {
515		Xput(xs, xp, '\0');
516		XPput(po.words, Xclose(xs, xp));
517		Xinit(xs, xp, 128, ATEMP);
518	}
519	if (*wp != NULL) {
520		if (!po.col)
521			Xput(xs, xp, po.ws);
522		goto print_read_arg;
523	}
524	if (po.col) {
525		size_t w = XPsize(po.words);
526		struct columnise_opts co;
527
528		XPput(po.words, NULL);
529		co.shf = shf_sopen(NULL, 128, SHF_WR | SHF_DYNAMIC, NULL);
530		co.linesep = po.ls;
531		co.prefcol = co.do_last = false;
532		pr_list(&co, (char **)XPptrv(po.words));
533		while (w--)
534			afree(XPptrv(po.words)[w], ATEMP);
535		XPfree(po.words);
536		w = co.shf->wp - co.shf->buf;
537		XcheckN(xs, xp, w);
538		memcpy(xp, co.shf->buf, w);
539		xp += w;
540		shf_sclose(co.shf);
541	}
542 print_no_arg:
543	if (po.nl)
544		Xput(xs, xp, po.ls);
545
546	c = 0;
547	if (po.hist) {
548		Xput(xs, xp, '\0');
549		histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
550	} else {
551		size_t len = Xlength(xs, xp);
552
553		/*
554		 * Ensure we aren't killed by a SIGPIPE while writing to
555		 * a coprocess. AT&T ksh doesn't seem to do this (seems
556		 * to just check that the co-process is alive which is
557		 * not enough).
558		 */
559		if (coproc.write >= 0 && coproc.write == po.fd) {
560			po.coproc = true;
561			po.copipe = block_pipe();
562		} else
563			po.coproc = po.copipe = false;
564
565		s = Xstring(xs, xp);
566		while (len > 0) {
567			ssize_t nwritten;
568
569			if ((nwritten = write(po.fd, s, len)) < 0) {
570				if (errno == EINTR) {
571					if (po.copipe)
572						restore_pipe();
573					/* give the user a chance to ^C out */
574					intrcheck();
575					/* interrupted, try again */
576					if (po.coproc)
577						po.copipe = block_pipe();
578					continue;
579				}
580				c = 1;
581				break;
582			}
583			s += nwritten;
584			len -= nwritten;
585		}
586		if (po.copipe)
587			restore_pipe();
588	}
589	Xfree(xs, xp);
590
591	return (c);
592}
593
594static int
595s_get(void)
596{
597	return (ord(*s_ptr++));
598}
599
600static void
601s_put(int c MKSH_A_UNUSED)
602{
603	--s_ptr;
604}
605
606int
607c_whence(const char **wp)
608{
609	int optc;
610	bool pflag = false, vflag = false;
611
612	while ((optc = ksh_getopt(wp, &builtin_opt, Tpv)) != -1)
613		switch (optc) {
614		case 'p':
615			pflag = true;
616			break;
617		case 'v':
618			vflag = true;
619			break;
620		case '?':
621			return (1);
622		}
623	wp += builtin_opt.optind;
624
625	return (do_whence(wp, pflag ? FC_PATH :
626	    FC_BI | FC_FUNC | FC_PATH | FC_WHENCE, vflag, false));
627}
628
629/* note: command without -vV is dealt with in comexec() */
630int
631c_command(const char **wp)
632{
633	int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE;
634	bool vflag = false;
635
636	while ((optc = ksh_getopt(wp, &builtin_opt, TpVv)) != -1)
637		switch (optc) {
638		case 'p':
639			fcflags |= FC_DEFPATH;
640			break;
641		case 'V':
642			vflag = true;
643			break;
644		case 'v':
645			vflag = false;
646			break;
647		case '?':
648			return (1);
649		}
650	wp += builtin_opt.optind;
651
652	return (do_whence(wp, fcflags, vflag, true));
653}
654
655static int
656do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
657{
658	uint32_t h;
659	int rv = 0;
660	struct tbl *tp;
661	const char *id;
662
663	while ((vflag || rv == 0) && (id = *wp++) != NULL) {
664		h = hash(id);
665		tp = NULL;
666
667		if (fcflags & FC_WHENCE)
668			tp = ktsearch(&keywords, id, h);
669		if (!tp && (fcflags & FC_WHENCE)) {
670			tp = ktsearch(&aliases, id, h);
671			if (tp && !(tp->flag & ISSET))
672				tp = NULL;
673		}
674		if (!tp)
675			tp = findcom(id, fcflags);
676
677		switch (tp->type) {
678		case CSHELL:
679		case CFUNC:
680		case CKEYWD:
681			shf_puts(id, shl_stdout);
682			break;
683		}
684
685		switch (tp->type) {
686		case CSHELL:
687			if (vflag)
688				shprintf(" is a %sshell %s",
689				    (tp->flag & SPEC_BI) ? "special " : "",
690				    Tbuiltin);
691			break;
692		case CFUNC:
693			if (vflag) {
694				shf_puts(" is a", shl_stdout);
695				if (tp->flag & EXPORT)
696					shf_puts("n exported", shl_stdout);
697				if (tp->flag & TRACE)
698					shf_puts(" traced", shl_stdout);
699				if (!(tp->flag & ISSET)) {
700					shf_puts(" undefined", shl_stdout);
701					if (tp->u.fpath)
702						shprintf(" (autoload from %s)",
703						    tp->u.fpath);
704				}
705				shf_puts(T_function, shl_stdout);
706			}
707			break;
708		case CEXEC:
709		case CTALIAS:
710			if (tp->flag & ISSET) {
711				if (vflag) {
712					shprintf("%s is ", id);
713					if (tp->type == CTALIAS)
714						shprintf("a tracked %s%s for ",
715						    (tp->flag & EXPORT) ?
716						    "exported " : "",
717						    Talias);
718				}
719				shf_puts(tp->val.s, shl_stdout);
720			} else {
721				if (vflag)
722					shprintf(Tnot_found_s, id);
723				rv = 1;
724			}
725			break;
726		case CALIAS:
727			if (vflag) {
728				shprintf("%s is an %s%s for ", id,
729				    (tp->flag & EXPORT) ? "exported " : "",
730				    Talias);
731			} else if (iscommand)
732				shprintf("%s %s=", Talias, id);
733			print_value_quoted(shl_stdout, tp->val.s);
734			break;
735		case CKEYWD:
736			if (vflag)
737				shf_puts(" is a reserved word", shl_stdout);
738			break;
739#ifndef MKSH_SMALL
740		default:
741			bi_errorf(Tunexpected_type, id, Tcommand, tp->type);
742			return (1);
743#endif
744		}
745		if (vflag || !rv)
746			shf_putc('\n', shl_stdout);
747	}
748	return (rv);
749}
750
751bool
752valid_alias_name(const char *cp)
753{
754	if (ord(*cp) == ORD('-'))
755		return (false);
756	if (ord(cp[0]) == ORD('[') && ord(cp[1]) == ORD('[') && !cp[2])
757		return (false);
758	while (*cp)
759		if (ctype(*cp, C_ALIAS))
760			++cp;
761		else
762			return (false);
763	return (true);
764}
765
766int
767c_alias(const char **wp)
768{
769	struct table *t = &aliases;
770	int rv = 0, prefix = 0;
771	bool rflag = false, tflag, Uflag = false, pflag = false, chkalias;
772	uint32_t xflag = 0;
773	int optc;
774
775	builtin_opt.flags |= GF_PLUSOPT;
776	while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) {
777		prefix = builtin_opt.info & GI_PLUS ? '+' : '-';
778		switch (optc) {
779		case 'd':
780#ifdef MKSH_NOPWNAM
781			t = NULL;	/* fix "alias -dt" */
782#else
783			t = &homedirs;
784#endif
785			break;
786		case 'p':
787			pflag = true;
788			break;
789		case 'r':
790			rflag = true;
791			break;
792		case 't':
793			t = &taliases;
794			break;
795		case 'U':
796			/*
797			 * kludge for tracked alias initialization
798			 * (don't do a path search, just make an entry)
799			 */
800			Uflag = true;
801			break;
802		case 'x':
803			xflag = EXPORT;
804			break;
805		case '?':
806			return (1);
807		}
808	}
809#ifdef MKSH_NOPWNAM
810	if (t == NULL)
811		return (0);
812#endif
813	wp += builtin_opt.optind;
814
815	if (!(builtin_opt.info & GI_MINUSMINUS) && *wp &&
816	    ctype(wp[0][0], C_MINUS | C_PLUS) && wp[0][1] == '\0') {
817		prefix = wp[0][0];
818		wp++;
819	}
820
821	tflag = t == &taliases;
822	chkalias = t == &aliases;
823
824	/* "hash -r" means reset all the tracked aliases.. */
825	if (rflag) {
826		static const char *args[] = {
827			Tunalias, "-ta", NULL
828		};
829
830		if (!tflag || *wp) {
831			shprintf("%s: -r flag can only be used with -t"
832			    " and without arguments\n", Talias);
833			return (1);
834		}
835		ksh_getopt_reset(&builtin_opt, GF_ERROR);
836		return (c_unalias(args));
837	}
838
839	if (*wp == NULL) {
840		struct tbl *ap, **p;
841
842		for (p = ktsort(t); (ap = *p++) != NULL; )
843			if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
844				if (pflag)
845					shprintf(Tf_s_, Talias);
846				shf_puts(ap->name, shl_stdout);
847				if (prefix != '+') {
848					shf_putc('=', shl_stdout);
849					print_value_quoted(shl_stdout, ap->val.s);
850				}
851				shf_putc('\n', shl_stdout);
852			}
853	}
854
855	for (; *wp != NULL; wp++) {
856		const char *alias = *wp, *val, *newval;
857		char *xalias = NULL;
858		struct tbl *ap;
859		uint32_t h;
860
861		if ((val = cstrchr(alias, '='))) {
862			strndupx(xalias, alias, val++ - alias, ATEMP);
863			alias = xalias;
864		}
865		if (chkalias && !valid_alias_name(alias)) {
866			bi_errorf(Tinvname, alias, Talias);
867			afree(xalias, ATEMP);
868			return (1);
869		}
870		h = hash(alias);
871		if (val == NULL && !tflag && !xflag) {
872			ap = ktsearch(t, alias, h);
873			if (ap != NULL && (ap->flag&ISSET)) {
874				if (pflag)
875					shprintf(Tf_s_, Talias);
876				shf_puts(ap->name, shl_stdout);
877				if (prefix != '+') {
878					shf_putc('=', shl_stdout);
879					print_value_quoted(shl_stdout, ap->val.s);
880				}
881				shf_putc('\n', shl_stdout);
882			} else {
883				shprintf(Tf_s_s_sN, alias, Talias, Tnot_found);
884				rv = 1;
885			}
886			continue;
887		}
888		ap = ktenter(t, alias, h);
889		ap->type = tflag ? CTALIAS : CALIAS;
890		/* Are we setting the value or just some flags? */
891		if ((val && !tflag) || (!val && tflag && !Uflag)) {
892			if (ap->flag&ALLOC) {
893				ap->flag &= ~(ALLOC|ISSET);
894				afree(ap->val.s, APERM);
895			}
896			/* ignore values for -t (AT&T ksh does this) */
897			newval = tflag ?
898			    search_path(alias, path, X_OK, NULL) :
899			    val;
900			if (newval) {
901				strdupx(ap->val.s, newval, APERM);
902				ap->flag |= ALLOC|ISSET;
903			} else
904				ap->flag &= ~ISSET;
905		}
906		ap->flag |= DEFINED;
907		if (prefix == '+')
908			ap->flag &= ~xflag;
909		else
910			ap->flag |= xflag;
911		afree(xalias, ATEMP);
912	}
913
914	return (rv);
915}
916
917int
918c_unalias(const char **wp)
919{
920	struct table *t = &aliases;
921	struct tbl *ap;
922	int optc, rv = 0;
923	bool all = false;
924
925	while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1)
926		switch (optc) {
927		case 'a':
928			all = true;
929			break;
930		case 'd':
931#ifdef MKSH_NOPWNAM
932			/* fix "unalias -dt" */
933			t = NULL;
934#else
935			t = &homedirs;
936#endif
937			break;
938		case 't':
939			t = &taliases;
940			break;
941		case '?':
942			return (1);
943		}
944#ifdef MKSH_NOPWNAM
945	if (t == NULL)
946		return (0);
947#endif
948	wp += builtin_opt.optind;
949
950	for (; *wp != NULL; wp++) {
951		ap = ktsearch(t, *wp, hash(*wp));
952		if (ap == NULL) {
953			/* POSIX */
954			rv = 1;
955			continue;
956		}
957		if (ap->flag&ALLOC) {
958			ap->flag &= ~(ALLOC|ISSET);
959			afree(ap->val.s, APERM);
960		}
961		ap->flag &= ~(DEFINED|ISSET|EXPORT);
962	}
963
964	if (all) {
965		struct tstate ts;
966
967		for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) {
968			if (ap->flag&ALLOC) {
969				ap->flag &= ~(ALLOC|ISSET);
970				afree(ap->val.s, APERM);
971			}
972			ap->flag &= ~(DEFINED|ISSET|EXPORT);
973		}
974	}
975
976	return (rv);
977}
978
979int
980c_let(const char **wp)
981{
982	int rv = 1;
983	mksh_ari_t val;
984
985	if (wp[1] == NULL)
986		/* AT&T ksh does this */
987		bi_errorf(Tno_args);
988	else
989		for (wp++; *wp; wp++)
990			if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) {
991				/* distinguish error from zero result */
992				rv = 2;
993				break;
994			} else
995				rv = val == 0;
996	return (rv);
997}
998
999int
1000c_jobs(const char **wp)
1001{
1002	int optc, flag = 0, nflag = 0, rv = 0;
1003
1004	while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1)
1005		switch (optc) {
1006		case 'l':
1007			flag = 1;
1008			break;
1009		case 'p':
1010			flag = 2;
1011			break;
1012		case 'n':
1013			nflag = 1;
1014			break;
1015		case 'z':
1016			/* debugging: print zombies */
1017			nflag = -1;
1018			break;
1019		case '?':
1020			return (1);
1021		}
1022	wp += builtin_opt.optind;
1023	if (!*wp) {
1024		if (j_jobs(NULL, flag, nflag))
1025			rv = 1;
1026	} else {
1027		for (; *wp; wp++)
1028			if (j_jobs(*wp, flag, nflag))
1029				rv = 1;
1030	}
1031	return (rv);
1032}
1033
1034#ifndef MKSH_UNEMPLOYED
1035int
1036c_fgbg(const char **wp)
1037{
1038	bool bg = strcmp(*wp, Tbg) == 0;
1039	int rv = 0;
1040
1041	if (!Flag(FMONITOR)) {
1042		bi_errorf("job control not enabled");
1043		return (1);
1044	}
1045	if (ksh_getopt(wp, &builtin_opt, null) == '?')
1046		return (1);
1047	wp += builtin_opt.optind;
1048	if (*wp)
1049		for (; *wp; wp++)
1050			rv = j_resume(*wp, bg);
1051	else
1052		rv = j_resume("%%", bg);
1053	/* fg returns $? of the job unless POSIX */
1054	return ((bg | Flag(FPOSIX)) ? 0 : rv);
1055}
1056#endif
1057
1058/* format a single kill item */
1059static void
1060kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
1061{
1062	const struct kill_info *ki = (const struct kill_info *)arg;
1063
1064	i++;
1065	shf_snprintf(buf, buflen, "%*u %*s %s",
1066	    ki->num_width, i,
1067	    ki->name_width, sigtraps[i].name,
1068	    sigtraps[i].mess);
1069}
1070
1071int
1072c_kill(const char **wp)
1073{
1074	Trap *t = NULL;
1075	const char *p;
1076	bool lflag = false;
1077	int i, n, rv, sig;
1078
1079	/* assume old style options if -digits or -UPPERCASE */
1080	if ((p = wp[1]) && *p == '-' && ctype(p[1], C_DIGIT | C_UPPER)) {
1081		if (!(t = gettrap(p + 1, false, false))) {
1082			bi_errorf(Tbad_sig_s, p + 1);
1083			return (1);
1084		}
1085		i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
1086	} else {
1087		int optc;
1088
1089		while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1)
1090			switch (optc) {
1091			case 'l':
1092				lflag = true;
1093				break;
1094			case 's':
1095				if (!(t = gettrap(builtin_opt.optarg,
1096				    true, false))) {
1097					bi_errorf(Tbad_sig_s,
1098					    builtin_opt.optarg);
1099					return (1);
1100				}
1101				break;
1102			case '?':
1103				return (1);
1104			}
1105		i = builtin_opt.optind;
1106	}
1107	if ((lflag && t) || (!wp[i] && !lflag)) {
1108#ifndef MKSH_SMALL
1109		shf_puts("usage:\tkill [-s signame | -signum | -signame]"
1110		    " { job | pid | pgrp } ...\n"
1111		    "\tkill -l [exit_status ...]\n", shl_out);
1112#endif
1113		bi_errorfz();
1114		return (1);
1115	}
1116
1117	if (lflag) {
1118		if (wp[i]) {
1119			for (; wp[i]; i++) {
1120				if (!bi_getn(wp[i], &n))
1121					return (1);
1122#if (ksh_NSIG <= 128)
1123				if (n > 128 && n < 128 + ksh_NSIG)
1124					n -= 128;
1125#endif
1126				if (n > 0 && n < ksh_NSIG)
1127					shprintf(Tf_sN, sigtraps[n].name);
1128				else
1129					shprintf(Tf_dN, n);
1130			}
1131		} else if (Flag(FPOSIX)) {
1132			n = 1;
1133			while (n < ksh_NSIG) {
1134				shf_puts(sigtraps[n].name, shl_stdout);
1135				shf_putc(++n == ksh_NSIG ? '\n' : ' ',
1136				    shl_stdout);
1137			}
1138		} else {
1139			ssize_t w, mess_cols = 0, mess_octs = 0;
1140			int j = ksh_NSIG - 1;
1141			struct kill_info ki = { 0, 0 };
1142			struct columnise_opts co;
1143
1144			do {
1145				ki.num_width++;
1146			} while ((j /= 10));
1147
1148			for (j = 1; j < ksh_NSIG; j++) {
1149				w = strlen(sigtraps[j].name);
1150				if (w > ki.name_width)
1151					ki.name_width = w;
1152				w = strlen(sigtraps[j].mess);
1153				if (w > mess_octs)
1154					mess_octs = w;
1155				w = utf_mbswidth(sigtraps[j].mess);
1156				if (w > mess_cols)
1157					mess_cols = w;
1158			}
1159
1160			co.shf = shl_stdout;
1161			co.linesep = '\n';
1162			co.prefcol = co.do_last = true;
1163
1164			print_columns(&co, (unsigned int)(ksh_NSIG - 1),
1165			    kill_fmt_entry, (void *)&ki,
1166			    ki.num_width + 1 + ki.name_width + 1 + mess_octs,
1167			    ki.num_width + 1 + ki.name_width + 1 + mess_cols);
1168		}
1169		return (0);
1170	}
1171	rv = 0;
1172	sig = t ? t->signal : SIGTERM;
1173	for (; (p = wp[i]); i++) {
1174		if (*p == '%') {
1175			if (j_kill(p, sig))
1176				rv = 1;
1177		} else if (!getn(p, &n)) {
1178			bi_errorf(Tf_sD_s, p,
1179			    "arguments must be jobs or process IDs");
1180			rv = 1;
1181		} else {
1182			if (mksh_kill(n, sig) < 0) {
1183				bi_errorf(Tf_sD_s, p, cstrerror(errno));
1184				rv = 1;
1185			}
1186		}
1187	}
1188	return (rv);
1189}
1190
1191void
1192getopts_reset(int val)
1193{
1194	if (val >= 1) {
1195		ksh_getopt_reset(&user_opt, GF_NONAME |
1196		    (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
1197		user_opt.optind = user_opt.uoptind = val;
1198	}
1199}
1200
1201int
1202c_getopts(const char **wp)
1203{
1204	int argc, optc, rv;
1205	const char *opts, *var;
1206	char buf[3];
1207	struct tbl *vq, *voptarg;
1208
1209	if (ksh_getopt(wp, &builtin_opt, null) == '?')
1210		return (1);
1211	wp += builtin_opt.optind;
1212
1213	opts = *wp++;
1214	if (!opts) {
1215		bi_errorf(Tf_sD_s, "options", Tno_args);
1216		return (1);
1217	}
1218
1219	var = *wp++;
1220	if (!var) {
1221		bi_errorf(Tf_sD_s, Tname, Tno_args);
1222		return (1);
1223	}
1224	if (!*var || *skip_varname(var, true)) {
1225		bi_errorf(Tf_sD_s, var, Tnot_ident);
1226		return (1);
1227	}
1228
1229	if (e->loc->next == NULL) {
1230		internal_warningf(Tf_sD_s, Tgetopts, Tno_args);
1231		return (1);
1232	}
1233	/* Which arguments are we parsing... */
1234	if (*wp == NULL)
1235		wp = e->loc->next->argv;
1236	else
1237		*--wp = e->loc->next->argv[0];
1238
1239	/* Check that our saved state won't cause a core dump... */
1240	for (argc = 0; wp[argc]; argc++)
1241		;
1242	if (user_opt.optind > argc ||
1243	    (user_opt.p != 0 &&
1244	    user_opt.p > strlen(wp[user_opt.optind - 1]))) {
1245		bi_errorf("arguments changed since last call");
1246		return (1);
1247	}
1248
1249	user_opt.optarg = NULL;
1250	optc = ksh_getopt(wp, &user_opt, opts);
1251
1252	if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
1253		buf[0] = '+';
1254		buf[1] = optc;
1255		buf[2] = '\0';
1256	} else {
1257		/*
1258		 * POSIX says var is set to ? at end-of-options, AT&T ksh
1259		 * sets it to null - we go with POSIX...
1260		 */
1261		buf[0] = optc < 0 ? '?' : optc;
1262		buf[1] = '\0';
1263	}
1264
1265	/* AT&T ksh93 in fact does change OPTIND for unknown options too */
1266	user_opt.uoptind = user_opt.optind;
1267
1268	voptarg = global("OPTARG");
1269	/* AT&T ksh clears ro and int */
1270	voptarg->flag &= ~RDONLY;
1271	/* Paranoia: ensure no bizarre results. */
1272	if (voptarg->flag & INTEGER)
1273	    typeset("OPTARG", 0, INTEGER, 0, 0);
1274	if (user_opt.optarg == NULL)
1275		unset(voptarg, 1);
1276	else
1277		/* this can't fail (haing cleared readonly/integer) */
1278		setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
1279
1280	rv = 0;
1281
1282	vq = global(var);
1283	/* Error message already printed (integer, readonly) */
1284	if (!setstr(vq, buf, KSH_RETURN_ERROR))
1285		rv = 2;
1286	if (Flag(FEXPORT))
1287		typeset(var, EXPORT, 0, 0, 0);
1288
1289	return (optc < 0 ? 1 : rv);
1290}
1291
1292#ifndef MKSH_NO_CMDLINE_EDITING
1293int
1294c_bind(const char **wp)
1295{
1296	int optc, rv = 0;
1297#ifndef MKSH_SMALL
1298	bool macro = false;
1299#endif
1300	bool list = false;
1301	const char *cp;
1302	char *up;
1303
1304	while ((optc = ksh_getopt(wp, &builtin_opt,
1305#ifndef MKSH_SMALL
1306	    "lm"
1307#else
1308	    "l"
1309#endif
1310	    )) != -1)
1311		switch (optc) {
1312		case 'l':
1313			list = true;
1314			break;
1315#ifndef MKSH_SMALL
1316		case 'm':
1317			macro = true;
1318			break;
1319#endif
1320		case '?':
1321			return (1);
1322		}
1323	wp += builtin_opt.optind;
1324
1325	if (*wp == NULL)
1326		/* list all */
1327		rv = x_bind(NULL, NULL,
1328#ifndef MKSH_SMALL
1329		    false,
1330#endif
1331		    list);
1332
1333	for (; *wp != NULL; wp++) {
1334		if ((cp = cstrchr(*wp, '=')) == NULL)
1335			up = NULL;
1336		else {
1337			strdupx(up, *wp, ATEMP);
1338			up[cp++ - *wp] = '\0';
1339		}
1340		if (x_bind(up ? up : *wp, cp,
1341#ifndef MKSH_SMALL
1342		    macro,
1343#endif
1344		    false))
1345			rv = 1;
1346		afree(up, ATEMP);
1347	}
1348
1349	return (rv);
1350}
1351#endif
1352
1353int
1354c_shift(const char **wp)
1355{
1356	struct block *l = e->loc;
1357	int n;
1358	mksh_ari_t val;
1359	const char *arg;
1360
1361	if (ksh_getopt(wp, &builtin_opt, null) == '?')
1362		return (1);
1363	arg = wp[builtin_opt.optind];
1364
1365	if (!arg)
1366		n = 1;
1367	else if (!evaluate(arg, &val, KSH_RETURN_ERROR, false)) {
1368		/* error already printed */
1369		bi_errorfz();
1370		return (1);
1371	} else if (!(n = val)) {
1372		/* nothing to do */
1373		return (0);
1374	} else if (n < 0) {
1375		bi_errorf(Tf_sD_s, Tbadnum, arg);
1376		return (1);
1377	}
1378	if (l->argc < n) {
1379		bi_errorf("nothing to shift");
1380		return (1);
1381	}
1382	l->argv[n] = l->argv[0];
1383	l->argv += n;
1384	l->argc -= n;
1385	return (0);
1386}
1387
1388int
1389c_umask(const char **wp)
1390{
1391	int i, optc;
1392	const char *cp;
1393	bool symbolic = false;
1394	mode_t old_umask;
1395
1396	while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
1397		switch (optc) {
1398		case 'S':
1399			symbolic = true;
1400			break;
1401		case '?':
1402			return (1);
1403		}
1404	cp = wp[builtin_opt.optind];
1405	if (cp == NULL) {
1406		old_umask = umask((mode_t)0);
1407		umask(old_umask);
1408		if (symbolic) {
1409			char buf[18], *p;
1410			int j;
1411
1412			old_umask = ~old_umask;
1413			p = buf;
1414			for (i = 0; i < 3; i++) {
1415				*p++ = Tugo[i];
1416				*p++ = '=';
1417				for (j = 0; j < 3; j++)
1418					if (old_umask & (1 << (8 - (3*i + j))))
1419						*p++ = "rwx"[j];
1420				*p++ = ',';
1421			}
1422			p[-1] = '\0';
1423			shprintf(Tf_sN, buf);
1424		} else
1425			shprintf("%#3.3o\n", (unsigned int)old_umask);
1426	} else {
1427		mode_t new_umask;
1428
1429		if (ctype(*cp, C_DIGIT)) {
1430			new_umask = 0;
1431			while (ctype(*cp, C_OCTAL)) {
1432				new_umask = new_umask * 8 + ksh_numdig(*cp);
1433				++cp;
1434			}
1435			if (*cp) {
1436				bi_errorf(Tbadnum);
1437				return (1);
1438			}
1439		} else {
1440			/* symbolic format */
1441			int positions, new_val;
1442			char op;
1443
1444			old_umask = umask((mode_t)0);
1445			/* in case of error */
1446			umask(old_umask);
1447			old_umask = ~old_umask;
1448			new_umask = old_umask;
1449			positions = 0;
1450			while (*cp) {
1451				while (*cp && vstrchr(Taugo, *cp))
1452					switch (*cp++) {
1453					case 'a':
1454						positions |= 0111;
1455						break;
1456					case 'u':
1457						positions |= 0100;
1458						break;
1459					case 'g':
1460						positions |= 0010;
1461						break;
1462					case 'o':
1463						positions |= 0001;
1464						break;
1465					}
1466				if (!positions)
1467					/* default is a */
1468					positions = 0111;
1469				if (!ctype((op = *cp), C_EQUAL | C_MINUS | C_PLUS))
1470					break;
1471				cp++;
1472				new_val = 0;
1473				while (*cp && vstrchr("rwxugoXs", *cp))
1474					switch (*cp++) {
1475					case 'r': new_val |= 04; break;
1476					case 'w': new_val |= 02; break;
1477					case 'x': new_val |= 01; break;
1478					case 'u':
1479						new_val |= old_umask >> 6;
1480						break;
1481					case 'g':
1482						new_val |= old_umask >> 3;
1483						break;
1484					case 'o':
1485						new_val |= old_umask >> 0;
1486						break;
1487					case 'X':
1488						if (old_umask & 0111)
1489							new_val |= 01;
1490						break;
1491					case 's':
1492						/* ignored */
1493						break;
1494					}
1495				new_val = (new_val & 07) * positions;
1496				switch (op) {
1497				case '-':
1498					new_umask &= ~new_val;
1499					break;
1500				case '=':
1501					new_umask = new_val |
1502					    (new_umask & ~(positions * 07));
1503					break;
1504				case '+':
1505					new_umask |= new_val;
1506				}
1507				if (*cp == ',') {
1508					positions = 0;
1509					cp++;
1510				} else if (!ctype(*cp, C_EQUAL | C_MINUS | C_PLUS))
1511					break;
1512			}
1513			if (*cp) {
1514				bi_errorf("bad mask");
1515				return (1);
1516			}
1517			new_umask = ~new_umask;
1518		}
1519		umask(new_umask);
1520	}
1521	return (0);
1522}
1523
1524int
1525c_dot(const char **wp)
1526{
1527	const char *file, *cp, **argv;
1528	int argc, rv, errcode;
1529
1530	if (ksh_getopt(wp, &builtin_opt, null) == '?')
1531		return (1);
1532
1533	if ((cp = wp[builtin_opt.optind]) == NULL) {
1534		bi_errorf(Tno_args);
1535		return (1);
1536	}
1537	file = search_path(cp, path, R_OK, &errcode);
1538	if (!file && errcode == ENOENT && wp[0][0] == 's' &&
1539	    search_access(cp, R_OK) == 0)
1540		file = cp;
1541	if (!file) {
1542		bi_errorf(Tf_sD_s, cp, cstrerror(errcode));
1543		return (1);
1544	}
1545
1546	/* Set positional parameters? */
1547	if (wp[builtin_opt.optind + 1]) {
1548		argv = wp + builtin_opt.optind;
1549		/* preserve $0 */
1550		argv[0] = e->loc->argv[0];
1551		for (argc = 0; argv[argc + 1]; argc++)
1552			;
1553	} else {
1554		argc = 0;
1555		argv = NULL;
1556	}
1557	/* SUSv4: OR with a high value never written otherwise */
1558	exstat |= 0x4000;
1559	if ((rv = include(file, argc, argv, false)) < 0) {
1560		/* should not happen */
1561		bi_errorf(Tf_sD_s, cp, cstrerror(errno));
1562		return (1);
1563	}
1564	if (exstat & 0x4000)
1565		/* detect old exstat, use 0 in that case */
1566		rv = 0;
1567	return (rv);
1568}
1569
1570int
1571c_wait(const char **wp)
1572{
1573	int rv = 0, sig;
1574
1575	if (ksh_getopt(wp, &builtin_opt, null) == '?')
1576		return (1);
1577	wp += builtin_opt.optind;
1578	if (*wp == NULL) {
1579		while (waitfor(NULL, &sig) >= 0)
1580			;
1581		rv = sig;
1582	} else {
1583		for (; *wp; wp++)
1584			rv = waitfor(*wp, &sig);
1585		if (rv < 0)
1586			/* magic exit code: bad job-id */
1587			rv = sig ? sig : 127;
1588	}
1589	return (rv);
1590}
1591
1592static const char REPLY[] = "REPLY";
1593int
1594c_read(const char **wp)
1595{
1596#define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
1597	int c, fd = 0, rv = 0;
1598	bool savehist = false, intoarray = false, aschars = false;
1599	bool rawmode = false, expanding = false;
1600	bool lastparmmode = false, lastparmused = false;
1601	enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
1602	char delim = '\n';
1603	size_t bytesleft = 128, bytesread;
1604	struct tbl *vp /* FU gcc */ = NULL, *vq = NULL;
1605	char *cp, *allocd = NULL, *xp;
1606	const char *ccp;
1607	XString xs;
1608	size_t xsave = 0;
1609	mksh_ttyst tios;
1610	bool restore_tios = false;
1611	/* to catch read -aN2 foo[i] */
1612	bool subarray = false;
1613#if HAVE_SELECT
1614	bool hastimeout = false;
1615	struct timeval tv, tvlim;
1616#define c_read_opts "Aad:N:n:prst:u,"
1617#else
1618#define c_read_opts "Aad:N:n:prsu,"
1619#endif
1620#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1621	int saved_mode;
1622	int saved_errno;
1623#endif
1624
1625	while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
1626	switch (c) {
1627	case 'a':
1628		aschars = true;
1629		/* FALLTHROUGH */
1630	case 'A':
1631		intoarray = true;
1632		break;
1633	case 'd':
1634		delim = builtin_opt.optarg[0];
1635		break;
1636	case 'N':
1637	case 'n':
1638		readmode = c == 'N' ? BYTES : UPTO;
1639		if (!bi_getn(builtin_opt.optarg, &c))
1640			return (2);
1641		if (c == -1) {
1642			readmode = readmode == BYTES ? READALL : UPTO;
1643			bytesleft = 1024;
1644		} else
1645			bytesleft = (unsigned int)c;
1646		break;
1647	case 'p':
1648		if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
1649			bi_errorf(Tf_coproc, ccp);
1650			return (2);
1651		}
1652		break;
1653	case 'r':
1654		rawmode = true;
1655		break;
1656	case 's':
1657		savehist = true;
1658		break;
1659#if HAVE_SELECT
1660	case 't':
1661		if (parse_usec(builtin_opt.optarg, &tv)) {
1662			bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno),
1663			    builtin_opt.optarg);
1664			return (2);
1665		}
1666		hastimeout = true;
1667		break;
1668#endif
1669	case 'u':
1670		if (!builtin_opt.optarg[0])
1671			fd = 0;
1672		else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
1673			bi_errorf(Tf_sD_sD_s, "-u", builtin_opt.optarg, ccp);
1674			return (2);
1675		}
1676		break;
1677	case '?':
1678		return (2);
1679	}
1680	wp += builtin_opt.optind;
1681	if (*wp == NULL)
1682		*--wp = REPLY;
1683
1684	if (intoarray && wp[1] != NULL) {
1685		bi_errorf(Ttoo_many_args);
1686		return (2);
1687	}
1688
1689	if ((ccp = cstrchr(*wp, '?')) != NULL) {
1690		strdupx(allocd, *wp, ATEMP);
1691		allocd[ccp - *wp] = '\0';
1692		*wp = allocd;
1693		if (isatty(fd)) {
1694			/*
1695			 * AT&T ksh says it prints prompt on fd if it's open
1696			 * for writing and is a tty, but it doesn't do it
1697			 * (it also doesn't check the interactive flag,
1698			 * as is indicated in the Korn Shell book).
1699			 */
1700			shf_puts(ccp + 1, shl_out);
1701			shf_flush(shl_out);
1702		}
1703	}
1704
1705	Xinit(xs, xp, bytesleft, ATEMP);
1706
1707	if (readmode == LINES)
1708		bytesleft = 1;
1709	else if (isatty(fd)) {
1710		x_mkraw(fd, &tios, true);
1711		restore_tios = true;
1712	}
1713
1714#if HAVE_SELECT
1715	if (hastimeout) {
1716		mksh_TIME(tvlim);
1717		timeradd(&tvlim, &tv, &tvlim);
1718	}
1719#endif
1720
1721 c_read_readloop:
1722#if HAVE_SELECT
1723	if (hastimeout) {
1724		fd_set fdset;
1725
1726		FD_ZERO(&fdset);
1727		FD_SET((unsigned int)fd, &fdset);
1728		mksh_TIME(tv);
1729		timersub(&tvlim, &tv, &tv);
1730		if (tv.tv_sec < 0) {
1731			/* timeout expired globally */
1732			rv = 3;
1733			goto c_read_out;
1734		}
1735
1736		switch (select(fd + 1, &fdset, NULL, NULL, &tv)) {
1737		case 1:
1738			break;
1739		case 0:
1740			/* timeout expired for this call */
1741			bytesread = 0;
1742			rv = 3;
1743			goto c_read_readdone;
1744		default:
1745			bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
1746			rv = 2;
1747			goto c_read_out;
1748		}
1749	}
1750#endif
1751
1752#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1753	saved_mode = setmode(fd, O_TEXT);
1754#endif
1755	if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
1756#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1757		saved_errno = errno;
1758		setmode(fd, saved_mode);
1759		errno = saved_errno;
1760#endif
1761		if (errno == EINTR) {
1762			/* check whether the signal would normally kill */
1763			if (!fatal_trap_check()) {
1764				/* no, just ignore the signal */
1765				goto c_read_readloop;
1766			}
1767			/* pretend the read was killed */
1768		} else {
1769			/* unexpected error */
1770			bi_errorf(Tf_s, cstrerror(errno));
1771		}
1772		rv = 2;
1773		goto c_read_out;
1774	}
1775#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1776	setmode(fd, saved_mode);
1777#endif
1778
1779	switch (readmode) {
1780	case READALL:
1781		if (bytesread == 0) {
1782			/* end of file reached */
1783			rv = 1;
1784			goto c_read_readdone;
1785		}
1786		xp += bytesread;
1787		XcheckN(xs, xp, bytesleft);
1788		break;
1789
1790	case UPTO:
1791		if (bytesread == 0)
1792			/* end of file reached */
1793			rv = 1;
1794		xp += bytesread;
1795		goto c_read_readdone;
1796
1797	case BYTES:
1798		if (bytesread == 0) {
1799			/* end of file reached */
1800			rv = 1;
1801			/* may be partial read: $? = 1, but content */
1802			goto c_read_readdone;
1803		}
1804		xp += bytesread;
1805		if ((bytesleft -= bytesread) == 0)
1806			goto c_read_readdone;
1807		break;
1808	case LINES:
1809		if (bytesread == 0) {
1810			/* end of file reached */
1811			rv = 1;
1812			goto c_read_readdone;
1813		}
1814		if ((c = *xp) == '\0' && !aschars && delim != '\0') {
1815			/* skip any read NULs unless delimiter */
1816			break;
1817		}
1818		if (expanding) {
1819			expanding = false;
1820			if (c == delim) {
1821				if (Flag(FTALKING_I) && isatty(fd)) {
1822					/*
1823					 * set prompt in case this is
1824					 * called from .profile or $ENV
1825					 */
1826					set_prompt(PS2, NULL);
1827					pprompt(prompt, 0);
1828				}
1829				/* drop the backslash */
1830				--xp;
1831				/* and the delimiter */
1832				break;
1833			}
1834		} else if (c == delim) {
1835			goto c_read_readdone;
1836		} else if (!rawmode && c == '\\') {
1837			expanding = true;
1838		}
1839		Xcheck(xs, xp);
1840		++xp;
1841		break;
1842	}
1843	goto c_read_readloop;
1844
1845 c_read_readdone:
1846	bytesread = Xlength(xs, xp);
1847	Xput(xs, xp, '\0');
1848
1849	/*-
1850	 * state: we finished reading the input and NUL terminated it
1851	 * Xstring(xs, xp) -> xp-1 = input string without trailing delim
1852	 * rv = 3 if timeout, 1 if EOF, 0 otherwise (errors handled already)
1853	 */
1854
1855	if (rv) {
1856		/* clean up coprocess if needed, on EOF/error/timeout */
1857		coproc_read_close(fd);
1858		if (readmode == READALL && (rv == 1 || (rv == 3 && bytesread)))
1859			/* EOF is no error here */
1860			rv = 0;
1861	}
1862
1863	if (savehist)
1864		histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
1865
1866	ccp = cp = Xclose(xs, xp);
1867	expanding = false;
1868	XinitN(xs, 128, ATEMP);
1869	if (intoarray) {
1870		vp = global(*wp);
1871		subarray = last_lookup_was_array;
1872		if (vp->flag & RDONLY) {
1873 c_read_splitro:
1874			bi_errorf(Tf_ro, *wp);
1875 c_read_spliterr:
1876			rv = 2;
1877			afree(cp, ATEMP);
1878			goto c_read_out;
1879		}
1880		/* counter for array index */
1881		c = subarray ? arrayindex(vp) : 0;
1882		/* exporting an array is currently pointless */
1883		unset(vp, subarray ? 0 : 1);
1884	}
1885	if (!aschars) {
1886		/* skip initial IFS whitespace */
1887		while (bytesread && is_ifsws(*ccp)) {
1888			++ccp;
1889			--bytesread;
1890		}
1891		/* trim trailing IFS whitespace */
1892		while (bytesread && is_ifsws(ccp[bytesread - 1])) {
1893			--bytesread;
1894		}
1895	}
1896 c_read_splitloop:
1897	xp = Xstring(xs, xp);
1898	/* generate next word */
1899	if (!bytesread) {
1900		/* no more input */
1901		if (intoarray)
1902			goto c_read_splitdone;
1903		/* zero out next parameters */
1904		goto c_read_gotword;
1905	}
1906	if (aschars) {
1907		Xput(xs, xp, '1');
1908		Xput(xs, xp, '#');
1909		bytesleft = utf_ptradj(ccp);
1910		while (bytesleft && bytesread) {
1911			*xp++ = *ccp++;
1912			--bytesleft;
1913			--bytesread;
1914		}
1915		if (xp[-1] == '\0') {
1916			xp[-1] = '0';
1917			xp[-3] = '2';
1918		}
1919		goto c_read_gotword;
1920	}
1921
1922	if (!intoarray && wp[1] == NULL)
1923		lastparmmode = true;
1924
1925 c_read_splitlast:
1926	/* copy until IFS character */
1927	while (bytesread) {
1928		char ch;
1929
1930		ch = *ccp;
1931		if (expanding) {
1932			expanding = false;
1933			goto c_read_splitcopy;
1934		} else if (ctype(ch, C_IFS)) {
1935			break;
1936		} else if (!rawmode && ch == '\\') {
1937			expanding = true;
1938		} else {
1939 c_read_splitcopy:
1940			Xcheck(xs, xp);
1941			Xput(xs, xp, ch);
1942		}
1943		++ccp;
1944		--bytesread;
1945	}
1946	xsave = Xsavepos(xs, xp);
1947	/* copy word delimiter: IFSWS+IFS,IFSWS */
1948	expanding = false;
1949	while (bytesread) {
1950		char ch;
1951
1952		ch = *ccp;
1953		if (!ctype(ch, C_IFS))
1954			break;
1955		if (lastparmmode && !expanding && !rawmode && ch == '\\') {
1956			expanding = true;
1957		} else {
1958			Xcheck(xs, xp);
1959			Xput(xs, xp, ch);
1960		}
1961		++ccp;
1962		--bytesread;
1963		if (expanding)
1964			continue;
1965		if (!ctype(ch, C_IFSWS))
1966			break;
1967	}
1968	while (bytesread && is_ifsws(*ccp)) {
1969		Xcheck(xs, xp);
1970		Xput(xs, xp, *ccp);
1971		++ccp;
1972		--bytesread;
1973	}
1974	/* if no more parameters, rinse and repeat */
1975	if (lastparmmode && bytesread) {
1976		lastparmused = true;
1977		goto c_read_splitlast;
1978	}
1979	/* get rid of the delimiter unless we pack the rest */
1980	if (!lastparmused)
1981		xp = Xrestpos(xs, xp, xsave);
1982 c_read_gotword:
1983	Xput(xs, xp, '\0');
1984	if (intoarray) {
1985		if (subarray) {
1986			/* array element passed, accept first read */
1987			if (vq) {
1988				bi_errorf("nested arrays not yet supported");
1989				goto c_read_spliterr;
1990			}
1991			vq = vp;
1992			if (c)
1993				/* [0] doesn't */
1994				vq->flag |= AINDEX;
1995		} else
1996			vq = arraysearch(vp, c++);
1997	} else {
1998		vq = global(*wp);
1999		/* must be checked before exporting */
2000		if (vq->flag & RDONLY)
2001			goto c_read_splitro;
2002		if (Flag(FEXPORT))
2003			typeset(*wp, EXPORT, 0, 0, 0);
2004	}
2005	if (!setstr(vq, Xstring(xs, xp), KSH_RETURN_ERROR))
2006		goto c_read_spliterr;
2007	if (aschars) {
2008		setint_v(vq, vq, false);
2009		/* protect from UTFMODE changes */
2010		vq->type = 0;
2011	}
2012	if (intoarray || *++wp != NULL)
2013		goto c_read_splitloop;
2014
2015 c_read_splitdone:
2016	/* free up */
2017	afree(cp, ATEMP);
2018
2019 c_read_out:
2020	afree(allocd, ATEMP);
2021	Xfree(xs, xp);
2022	if (restore_tios)
2023		mksh_tcset(fd, &tios);
2024	return (rv == 3 ? ksh_sigmask(SIGALRM) : rv);
2025#undef is_ifsws
2026}
2027
2028int
2029c_eval(const char **wp)
2030{
2031	struct source *s, *saves = source;
2032	unsigned char savef;
2033	int rv;
2034
2035	if (ksh_getopt(wp, &builtin_opt, null) == '?')
2036		return (1);
2037	s = pushs(SWORDS, ATEMP);
2038	s->u.strv = wp + builtin_opt.optind;
2039	s->line = current_lineno;
2040
2041	/*-
2042	 * The following code handles the case where the command is
2043	 * empty due to failed command substitution, for example by
2044	 *	eval "$(false)"
2045	 * This has historically returned 1 by AT&T ksh88. In this
2046	 * case, shell() will not set or change exstat because the
2047	 * compiled tree is empty, so it will use the value we pass
2048	 * from subst_exstat, which is cleared in execute(), so it
2049	 * should have been 0 if there were no substitutions.
2050	 *
2051	 * POSIX however says we don't do this, even though it is
2052	 * traditionally done. AT&T ksh93 agrees with POSIX, so we
2053	 * do. The following is an excerpt from SUSv4 [1003.2-2008]:
2054	 *
2055	 * 2.9.1: Simple Commands
2056	 *	... If there is a command name, execution shall
2057	 *	continue as described in 2.9.1.1 [Command Search
2058	 *	and Execution]. If there is no command name, but
2059	 *	the command contained a command substitution, the
2060	 *	command shall complete with the exit status of the
2061	 *	last command substitution performed.
2062	 * 2.9.1.1: Command Search and Execution
2063	 *	(1) a. If the command name matches the name of a
2064	 *	special built-in utility, that special built-in
2065	 *	utility shall be invoked.
2066	 * 2.14.5: eval
2067	 *	If there are no arguments, or only null arguments,
2068	 *	eval shall return a zero exit status; ...
2069	 */
2070	/* AT&T ksh88: use subst_exstat */
2071	/* exstat = subst_exstat; */
2072	/* SUSv4: OR with a high value never written otherwise */
2073	exstat |= 0x4000;
2074
2075	savef = Flag(FERREXIT);
2076	Flag(FERREXIT) |= 0x80;
2077	rv = shell(s, 2);
2078	Flag(FERREXIT) = savef;
2079	source = saves;
2080	afree(s, ATEMP);
2081	if (exstat & 0x4000)
2082		/* detect old exstat, use 0 in that case */
2083		rv = 0;
2084	return (rv);
2085}
2086
2087int
2088c_trap(const char **wp)
2089{
2090	Trap *p = sigtraps;
2091	int i = ksh_NSIG;
2092	const char *s;
2093
2094	if (ksh_getopt(wp, &builtin_opt, null) == '?')
2095		return (1);
2096	wp += builtin_opt.optind;
2097
2098	if (*wp == NULL) {
2099		do {
2100			if (p->trap) {
2101				shf_puts("trap -- ", shl_stdout);
2102				print_value_quoted(shl_stdout, p->trap);
2103				shprintf(Tf__sN, p->name);
2104			}
2105			++p;
2106		} while (i--);
2107		return (0);
2108	}
2109
2110	if (getn(*wp, &i)) {
2111		/* first argument is a signal number, reset them all */
2112		s = NULL;
2113	} else {
2114		/* first argument must be a command, then */
2115		s = *wp++;
2116		/* reset traps? */
2117		if (ksh_isdash(s))
2118			s = NULL;
2119	}
2120
2121	/* set/clear the traps */
2122	i = 0;
2123	while (*wp)
2124		if (!(p = gettrap(*wp++, true, true))) {
2125			warningf(true, Tbad_sig_ss, builtin_argv0, wp[-1]);
2126			i = 1;
2127		} else
2128			settrap(p, s);
2129	return (i);
2130}
2131
2132int
2133c_exitreturn(const char **wp)
2134{
2135	int n, how = LEXIT;
2136
2137	if (wp[1]) {
2138		if (wp[2])
2139			goto c_exitreturn_err;
2140		exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1;
2141	} else if (trap_exstat != -1)
2142		exstat = trap_exstat;
2143
2144	if (wp[0][0] == 'r') {
2145		/* return */
2146		struct env *ep;
2147
2148		/*
2149		 * need to tell if this is exit or return so trap exit will
2150		 * work right (POSIX)
2151		 */
2152		for (ep = e; ep; ep = ep->oenv)
2153			if (STOP_RETURN(ep->type)) {
2154				how = LRETURN;
2155				break;
2156			}
2157	}
2158
2159	if (how == LEXIT && !really_exit && j_stopped_running()) {
2160		really_exit = true;
2161		how = LSHELL;
2162	}
2163
2164	/* get rid of any I/O redirections */
2165	quitenv(NULL);
2166	unwind(how);
2167	/* NOTREACHED */
2168
2169 c_exitreturn_err:
2170	bi_errorf(Ttoo_many_args);
2171	return (1);
2172}
2173
2174int
2175c_brkcont(const char **wp)
2176{
2177	unsigned int quit;
2178	int n;
2179	struct env *ep, *last_ep = NULL;
2180	const char *arg;
2181
2182	if (ksh_getopt(wp, &builtin_opt, null) == '?')
2183		goto c_brkcont_err;
2184	arg = wp[builtin_opt.optind];
2185
2186	if (!arg)
2187		n = 1;
2188	else if (!bi_getn(arg, &n))
2189		goto c_brkcont_err;
2190	if (n <= 0) {
2191		/* AT&T ksh does this for non-interactive shells only - weird */
2192		bi_errorf("%s: bad value", arg);
2193		goto c_brkcont_err;
2194	}
2195	quit = (unsigned int)n;
2196
2197	/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
2198	for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
2199		if (ep->type == E_LOOP) {
2200			if (--quit == 0)
2201				break;
2202			ep->flags |= EF_BRKCONT_PASS;
2203			last_ep = ep;
2204		}
2205
2206	if (quit) {
2207		/*
2208		 * AT&T ksh doesn't print a message - just does what it
2209		 * can. We print a message 'cause it helps in debugging
2210		 * scripts, but don't generate an error (ie, keep going).
2211		 */
2212		if ((unsigned int)n == quit) {
2213			warningf(true, Tf_cant_s, wp[0], wp[0]);
2214			return (0);
2215		}
2216		/*
2217		 * POSIX says if n is too big, the last enclosing loop
2218		 * shall be used. Doesn't say to print an error but we
2219		 * do anyway 'cause the user messed up.
2220		 */
2221		if (last_ep)
2222			last_ep->flags &= ~EF_BRKCONT_PASS;
2223		warningf(true, "%s: can only %s %u level(s)",
2224		    wp[0], wp[0], (unsigned int)n - quit);
2225	}
2226
2227	unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
2228	/* NOTREACHED */
2229
2230 c_brkcont_err:
2231	return (1);
2232}
2233
2234int
2235c_set(const char **wp)
2236{
2237	int argi;
2238	bool setargs;
2239	struct block *l = e->loc;
2240	const char **owp;
2241
2242	if (wp[1] == NULL) {
2243		static const char *args[] = { Tset, "-", NULL };
2244		return (c_typeset(args));
2245	}
2246
2247	if ((argi = parse_args(wp, OF_SET, &setargs)) < 0)
2248		return (2);
2249	/* set $# and $* */
2250	if (setargs) {
2251		wp += argi - 1;
2252		owp = wp;
2253		/* save $0 */
2254		wp[0] = l->argv[0];
2255		while (*++wp != NULL)
2256			strdupx(*wp, *wp, &l->area);
2257		l->argc = wp - owp - 1;
2258		l->argv = alloc2(l->argc + 2, sizeof(char *), &l->area);
2259		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
2260			;
2261	}
2262	/*-
2263	 * POSIX says set exit status is 0, but old scripts that use
2264	 * getopt(1) use the construct
2265	 *	set -- $(getopt ab:c "$@")
2266	 * which assumes the exit value set will be that of the $()
2267	 * (subst_exstat is cleared in execute() so that it will be 0
2268	 * if there are no command substitutions).
2269	 */
2270#ifdef MKSH_LEGACY_MODE
2271	/* traditional behaviour, unless set -o posix */
2272	return (Flag(FPOSIX) ? 0 : subst_exstat);
2273#else
2274	/* conformant behaviour, unless set -o sh +o posix */
2275	return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
2276#endif
2277}
2278
2279int
2280c_unset(const char **wp)
2281{
2282	const char *id;
2283	int optc, rv = 0;
2284	bool unset_var = true;
2285
2286	while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
2287		switch (optc) {
2288		case 'f':
2289			unset_var = false;
2290			break;
2291		case 'v':
2292			unset_var = true;
2293			break;
2294		case '?':
2295			/*XXX not reached due to GF_ERROR */
2296			return (2);
2297		}
2298	wp += builtin_opt.optind;
2299	for (; (id = *wp) != NULL; wp++)
2300		if (unset_var) {
2301			/* unset variable */
2302			struct tbl *vp;
2303			char *cp = NULL;
2304			size_t n;
2305
2306			n = strlen(id);
2307			if (n > 3 && ord(id[n - 3]) == ORD('[') &&
2308			    ord(id[n - 2]) == ORD('*') &&
2309			    ord(id[n - 1]) == ORD(']')) {
2310				strndupx(cp, id, n - 3, ATEMP);
2311				id = cp;
2312				optc = 3;
2313			} else
2314				optc = vstrchr(id, '[') ? 0 : 1;
2315
2316			vp = global(id);
2317			afree(cp, ATEMP);
2318
2319			if ((vp->flag&RDONLY)) {
2320				warningf(true, Tf_ro, vp->name);
2321				rv = 1;
2322			} else
2323				unset(vp, optc);
2324		} else
2325			/* unset function */
2326			define(id, NULL);
2327	return (rv);
2328}
2329
2330static void
2331p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width,
2332    const char *prefix, const char *suffix)
2333{
2334	tv_usec /= 10000;
2335	if (posix)
2336		shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width,
2337		    tv_sec, tv_usec, suffix);
2338	else
2339		shf_fprintf(shf, "%s%*ldm%02d.%02ds%s", prefix, width,
2340		    tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix);
2341}
2342
2343int
2344c_times(const char **wp MKSH_A_UNUSED)
2345{
2346	struct rusage usage;
2347
2348	getrusage(RUSAGE_SELF, &usage);
2349	p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2350	    usage.ru_utime.tv_usec, 0, null, T1space);
2351	p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2352	    usage.ru_stime.tv_usec, 0, null, "\n");
2353
2354	getrusage(RUSAGE_CHILDREN, &usage);
2355	p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2356	    usage.ru_utime.tv_usec, 0, null, T1space);
2357	p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2358	    usage.ru_stime.tv_usec, 0, null, "\n");
2359
2360	return (0);
2361}
2362
2363/*
2364 * time pipeline (really a statement, not a built-in command)
2365 */
2366int
2367timex(struct op *t, int f, volatile int *xerrok)
2368{
2369#define TF_NOARGS	BIT(0)
2370#define TF_NOREAL	BIT(1)		/* don't report real time */
2371#define TF_POSIX	BIT(2)		/* report in POSIX format */
2372	int rv = 0, tf = 0;
2373	struct rusage ru0, ru1, cru0, cru1;
2374	struct timeval usrtime, systime, tv0, tv1;
2375
2376	mksh_TIME(tv0);
2377	getrusage(RUSAGE_SELF, &ru0);
2378	getrusage(RUSAGE_CHILDREN, &cru0);
2379	if (t->left) {
2380		/*
2381		 * Two ways of getting cpu usage of a command: just use t0
2382		 * and t1 (which will get cpu usage from other jobs that
2383		 * finish while we are executing t->left), or get the
2384		 * cpu usage of t->left. AT&T ksh does the former, while
2385		 * pdksh tries to do the later (the j_usrtime hack doesn't
2386		 * really work as it only counts the last job).
2387		 */
2388		timerclear(&j_usrtime);
2389		timerclear(&j_systime);
2390		rv = execute(t->left, f | XTIME, xerrok);
2391		if (t->left->type == TCOM)
2392			tf |= t->left->str[0];
2393		mksh_TIME(tv1);
2394		getrusage(RUSAGE_SELF, &ru1);
2395		getrusage(RUSAGE_CHILDREN, &cru1);
2396	} else
2397		tf = TF_NOARGS;
2398
2399	if (tf & TF_NOARGS) {
2400		/* ksh93 - report shell times (shell+kids) */
2401		tf |= TF_NOREAL;
2402		timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime);
2403		timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime);
2404	} else {
2405		timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime);
2406		timeradd(&usrtime, &j_usrtime, &usrtime);
2407		timersub(&ru1.ru_stime, &ru0.ru_stime, &systime);
2408		timeradd(&systime, &j_systime, &systime);
2409	}
2410
2411	if (!(tf & TF_NOREAL)) {
2412		timersub(&tv1, &tv0, &tv1);
2413		if (tf & TF_POSIX)
2414			p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec,
2415			    5, Treal_sp1, "\n");
2416		else
2417			p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec,
2418			    5, null, Treal_sp2);
2419	}
2420	if (tf & TF_POSIX)
2421		p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec,
2422		    5, Tuser_sp1, "\n");
2423	else
2424		p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec,
2425		    5, null, Tuser_sp2);
2426	if (tf & TF_POSIX)
2427		p_time(shl_out, true, systime.tv_sec, systime.tv_usec,
2428		    5, "sys  ", "\n");
2429	else
2430		p_time(shl_out, false, systime.tv_sec, systime.tv_usec,
2431		    5, null, " system\n");
2432	shf_flush(shl_out);
2433
2434	return (rv);
2435}
2436
2437void
2438timex_hook(struct op *t, char **volatile *app)
2439{
2440	char **wp = *app;
2441	int optc, i, j;
2442	Getopt opt;
2443
2444	ksh_getopt_reset(&opt, 0);
2445	/* start at the start */
2446	opt.optind = 0;
2447	while ((optc = ksh_getopt((const char **)wp, &opt, ":p")) != -1)
2448		switch (optc) {
2449		case 'p':
2450			t->str[0] |= TF_POSIX;
2451			break;
2452		case '?':
2453			errorf(Tf_optfoo, Ttime, Tcolsp,
2454			    opt.optarg[0], Tunknown_option);
2455		case ':':
2456			errorf(Tf_optfoo, Ttime, Tcolsp,
2457			    opt.optarg[0], Treq_arg);
2458		}
2459	/* Copy command words down over options. */
2460	if (opt.optind != 0) {
2461		for (i = 0; i < opt.optind; i++)
2462			afree(wp[i], ATEMP);
2463		for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
2464			;
2465	}
2466	if (!wp[0])
2467		t->str[0] |= TF_NOARGS;
2468	*app = wp;
2469}
2470
2471/* exec with no args - args case is taken care of in comexec() */
2472int
2473c_exec(const char **wp MKSH_A_UNUSED)
2474{
2475	int i;
2476
2477	/* make sure redirects stay in place */
2478	if (e->savefd != NULL) {
2479		for (i = 0; i < NUFILE; i++) {
2480			if (e->savefd[i] > 0)
2481				close(e->savefd[i]);
2482			/*
2483			 * keep all file descriptors > 2 private for ksh,
2484			 * but not for POSIX or legacy/kludge sh
2485			 */
2486			if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
2487			    e->savefd[i])
2488				fcntl(i, F_SETFD, FD_CLOEXEC);
2489		}
2490		e->savefd = NULL;
2491	}
2492	return (0);
2493}
2494
2495#if HAVE_MKNOD && !defined(__OS2__)
2496int
2497c_mknod(const char **wp)
2498{
2499	int argc, optc, rv = 0;
2500	bool ismkfifo = false;
2501	const char **argv;
2502	void *set = NULL;
2503	mode_t mode = 0, oldmode = 0;
2504
2505	while ((optc = ksh_getopt(wp, &builtin_opt, "m:")) != -1) {
2506		switch (optc) {
2507		case 'm':
2508			set = setmode(builtin_opt.optarg);
2509			if (set == NULL) {
2510				bi_errorf("invalid file mode");
2511				return (1);
2512			}
2513			mode = getmode(set, (mode_t)(DEFFILEMODE));
2514			free_ossetmode(set);
2515			break;
2516		default:
2517			goto c_mknod_usage;
2518		}
2519	}
2520	argv = &wp[builtin_opt.optind];
2521	if (argv[0] == NULL)
2522		goto c_mknod_usage;
2523	for (argc = 0; argv[argc]; argc++)
2524		;
2525	if (argc == 2 && argv[1][0] == 'p')
2526		ismkfifo = true;
2527	else if (argc != 4 || (argv[1][0] != 'b' && argv[1][0] != 'c'))
2528		goto c_mknod_usage;
2529
2530	if (set != NULL)
2531		oldmode = umask((mode_t)0);
2532	else
2533		mode = DEFFILEMODE;
2534
2535	mode |= (argv[1][0] == 'b') ? S_IFBLK :
2536	    (argv[1][0] == 'c') ? S_IFCHR : 0;
2537
2538	if (!ismkfifo) {
2539		unsigned long majnum, minnum;
2540		dev_t dv;
2541		char *c;
2542
2543		majnum = strtoul(argv[2], &c, 0);
2544		if ((c == argv[2]) || (*c != '\0')) {
2545			bi_errorf(Tf_nonnum, "device", "major", argv[2]);
2546			goto c_mknod_err;
2547		}
2548		minnum = strtoul(argv[3], &c, 0);
2549		if ((c == argv[3]) || (*c != '\0')) {
2550			bi_errorf(Tf_nonnum, "device", "minor", argv[3]);
2551			goto c_mknod_err;
2552		}
2553		dv = makedev(majnum, minnum);
2554		if ((unsigned long)(major(dv)) != majnum) {
2555			bi_errorf(Tf_toolarge, "device", "major", majnum);
2556			goto c_mknod_err;
2557		}
2558		if ((unsigned long)(minor(dv)) != minnum) {
2559			bi_errorf(Tf_toolarge, "device", "minor", minnum);
2560			goto c_mknod_err;
2561		}
2562		if (mknod(argv[0], mode, dv))
2563			goto c_mknod_failed;
2564	} else if (mkfifo(argv[0], mode)) {
2565 c_mknod_failed:
2566		bi_errorf(Tf_sD_s, argv[0], cstrerror(errno));
2567 c_mknod_err:
2568		rv = 1;
2569	}
2570
2571	if (set)
2572		umask(oldmode);
2573	return (rv);
2574 c_mknod_usage:
2575	bi_errorf("usage: mknod [-m mode] name %s", "b|c major minor");
2576	bi_errorf("usage: mknod [-m mode] name %s", "p");
2577	return (1);
2578}
2579#endif
2580
2581/*-
2582   test(1) roughly accepts the following grammar:
2583	oexpr	::= aexpr | aexpr "-o" oexpr ;
2584	aexpr	::= nexpr | nexpr "-a" aexpr ;
2585	nexpr	::= primary | "!" nexpr ;
2586	primary	::= unary-operator operand
2587		| operand binary-operator operand
2588		| operand
2589		| "(" oexpr ")"
2590		;
2591
2592	unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
2593			   "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
2594			   "-u"|"-v"|"-w"|"-x"|"-z";
2595
2596	binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
2597			    "-lt"|"-le"|"-ef"|"-nt"|"-ot";
2598
2599	operand ::= <anything>
2600*/
2601
2602/* POSIX says > 1 for errors */
2603#define T_ERR_EXIT 2
2604
2605int
2606c_test(const char **wp)
2607{
2608	int argc, rv, invert = 0;
2609	Test_env te;
2610	Test_op op;
2611	Test_meta tm;
2612	const char *lhs, **swp;
2613
2614	te.flags = 0;
2615	te.isa = ptest_isa;
2616	te.getopnd = ptest_getopnd;
2617	te.eval = test_eval;
2618	te.error = ptest_error;
2619
2620	for (argc = 0; wp[argc]; argc++)
2621		;
2622
2623	if (strcmp(wp[0], Tbracket) == 0) {
2624		if (strcmp(wp[--argc], "]") != 0) {
2625			bi_errorf("missing ]");
2626			return (T_ERR_EXIT);
2627		}
2628	}
2629
2630	te.pos.wp = wp + 1;
2631	te.wp_end = wp + argc;
2632
2633	/*
2634	 * Attempt to conform to POSIX special cases. This is pretty
2635	 * dumb code straight-forward from the 2008 spec, but unlike
2636	 * the old pdksh code doesn't live from so many assumptions.
2637	 * It does, though, inline some calls to '(*te.funcname)()'.
2638	 */
2639	switch (argc - 1) {
2640	case 0:
2641		return (1);
2642	case 1:
2643 ptest_one:
2644		op = TO_STNZE;
2645		goto ptest_unary;
2646	case 2:
2647 ptest_two:
2648		if (ptest_isa(&te, TM_NOT)) {
2649			++invert;
2650			goto ptest_one;
2651		}
2652		if ((op = ptest_isa(&te, TM_UNOP))) {
2653 ptest_unary:
2654			rv = test_eval(&te, op, *te.pos.wp++, NULL, true);
2655 ptest_out:
2656			if (te.flags & TEF_ERROR)
2657				return (T_ERR_EXIT);
2658			return ((invert & 1) ? rv : !rv);
2659		}
2660		/* let the parser deal with anything else */
2661		break;
2662	case 3:
2663 ptest_three:
2664		swp = te.pos.wp;
2665		/* use inside knowledge of ptest_getopnd inlined below */
2666		lhs = *te.pos.wp++;
2667		if ((op = ptest_isa(&te, TM_BINOP))) {
2668			/* test lhs op rhs */
2669			rv = test_eval(&te, op, lhs, *te.pos.wp++, true);
2670			goto ptest_out;
2671		}
2672		if (ptest_isa(&te, tm = TM_AND) || ptest_isa(&te, tm = TM_OR)) {
2673			/* XSI */
2674			argc = test_eval(&te, TO_STNZE, lhs, NULL, true);
2675			rv = test_eval(&te, TO_STNZE, *te.pos.wp++, NULL, true);
2676			if (tm == TM_AND)
2677				rv = argc && rv;
2678			else
2679				rv = argc || rv;
2680			goto ptest_out;
2681		}
2682		/* back up to lhs */
2683		te.pos.wp = swp;
2684		if (ptest_isa(&te, TM_NOT)) {
2685			++invert;
2686			goto ptest_two;
2687		}
2688		if (ptest_isa(&te, TM_OPAREN)) {
2689			swp = te.pos.wp;
2690			/* skip operand, without evaluation */
2691			te.pos.wp++;
2692			/* check for closing parenthesis */
2693			op = ptest_isa(&te, TM_CPAREN);
2694			/* back up to operand */
2695			te.pos.wp = swp;
2696			/* if there was a closing paren, handle it */
2697			if (op)
2698				goto ptest_one;
2699			/* backing up is done before calling the parser */
2700		}
2701		/* let the parser deal with it */
2702		break;
2703	case 4:
2704		if (ptest_isa(&te, TM_NOT)) {
2705			++invert;
2706			goto ptest_three;
2707		}
2708		if (ptest_isa(&te, TM_OPAREN)) {
2709			swp = te.pos.wp;
2710			/* skip two operands, without evaluation */
2711			te.pos.wp++;
2712			te.pos.wp++;
2713			/* check for closing parenthesis */
2714			op = ptest_isa(&te, TM_CPAREN);
2715			/* back up to first operand */
2716			te.pos.wp = swp;
2717			/* if there was a closing paren, handle it */
2718			if (op)
2719				goto ptest_two;
2720			/* backing up is done before calling the parser */
2721		}
2722		/* defer this to the parser */
2723		break;
2724	}
2725
2726	/* "The results are unspecified." */
2727	te.pos.wp = wp + 1;
2728	return (test_parse(&te));
2729}
2730
2731/*
2732 * Generic test routines.
2733 */
2734
2735Test_op
2736test_isop(Test_meta meta, const char *s)
2737{
2738	char sc1;
2739	const struct t_op *tbl;
2740
2741	tbl = meta == TM_UNOP ? u_ops : b_ops;
2742	if (*s) {
2743		sc1 = s[1];
2744		for (; tbl->op_text[0]; tbl++)
2745			if (sc1 == tbl->op_text[1] && !strcmp(s, tbl->op_text))
2746				return (tbl->op_num);
2747	}
2748	return (TO_NONOP);
2749}
2750
2751#ifdef __OS2__
2752#define test_access(name, mode) access_ex(access, (name), (mode))
2753#define test_stat(name, buffer) stat_ex((name), (buffer))
2754#else
2755#define test_access(name, mode) access((name), (mode))
2756#define test_stat(name, buffer) stat((name), (buffer))
2757#endif
2758
2759int
2760test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
2761    bool do_eval)
2762{
2763	int i, s;
2764	size_t k;
2765	struct stat b1, b2;
2766	mksh_ari_t v1, v2;
2767	struct tbl *vp;
2768
2769	if (!do_eval)
2770		return (0);
2771
2772#ifdef DEBUG
2773	switch (op) {
2774	/* Binary operators */
2775	case TO_STEQL:
2776	case TO_STNEQ:
2777	case TO_STLT:
2778	case TO_STGT:
2779	case TO_INTEQ:
2780	case TO_INTNE:
2781	case TO_INTGT:
2782	case TO_INTGE:
2783	case TO_INTLT:
2784	case TO_INTLE:
2785	case TO_FILEQ:
2786	case TO_FILNT:
2787	case TO_FILOT:
2788		/* consistency check, but does not happen in practice */
2789		if (!opnd2) {
2790			te->flags |= TEF_ERROR;
2791			return (1);
2792		}
2793		break;
2794	default:
2795		/* for completeness of switch */
2796		break;
2797	}
2798#endif
2799
2800	switch (op) {
2801
2802	/*
2803	 * Unary Operators
2804	 */
2805
2806	/* -n */
2807	case TO_STNZE:
2808		return (*opnd1 != '\0');
2809
2810	/* -z */
2811	case TO_STZER:
2812		return (*opnd1 == '\0');
2813
2814	/* -v */
2815	case TO_ISSET:
2816		return ((vp = isglobal(opnd1, false)) && (vp->flag & ISSET));
2817
2818	/* -o */
2819	case TO_OPTION:
2820		if ((i = *opnd1) == '!' || i == '?')
2821			opnd1++;
2822		if ((k = option(opnd1)) == (size_t)-1)
2823			return (0);
2824		return (i == '?' ? 1 : i == '!' ? !Flag(k) : Flag(k));
2825
2826	/* -r */
2827	case TO_FILRD:
2828		/* LINTED use of access */
2829		return (test_access(opnd1, R_OK) == 0);
2830
2831	/* -w */
2832	case TO_FILWR:
2833		/* LINTED use of access */
2834		return (test_access(opnd1, W_OK) == 0);
2835
2836	/* -x */
2837	case TO_FILEX:
2838		return (ksh_access(opnd1, X_OK) == 0);
2839
2840	/* -a */
2841	case TO_FILAXST:
2842	/* -e */
2843	case TO_FILEXST:
2844		return (test_stat(opnd1, &b1) == 0);
2845
2846	/* -f */
2847	case TO_FILREG:
2848		return (test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
2849
2850	/* -d */
2851	case TO_FILID:
2852		return (stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode));
2853
2854	/* -c */
2855	case TO_FILCDEV:
2856		return (stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode));
2857
2858	/* -b */
2859	case TO_FILBDEV:
2860		return (stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode));
2861
2862	/* -p */
2863	case TO_FILFIFO:
2864		return (stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode));
2865
2866	/* -h or -L */
2867	case TO_FILSYM:
2868#ifdef MKSH__NO_SYMLINK
2869		return (0);
2870#else
2871		return (lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode));
2872#endif
2873
2874	/* -S */
2875	case TO_FILSOCK:
2876		return (stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode));
2877
2878	/* -H => HP context dependent files (directories) */
2879	case TO_FILCDF:
2880#ifdef S_ISCDF
2881	{
2882		char *nv;
2883
2884		/*
2885		 * Append a + to filename and check to see if result is
2886		 * a setuid directory. CDF stuff in general is hookey,
2887		 * since it breaks for, e.g., the following sequence:
2888		 * echo hi >foo+; mkdir foo; echo bye >foo/default;
2889		 * chmod u+s foo (foo+ refers to the file with hi in it,
2890		 * there is no way to get at the file with bye in it;
2891		 * please correct me if I'm wrong about this).
2892		 */
2893
2894		nv = shf_smprintf("%s+", opnd1);
2895		i = (stat(nv, &b1) == 0 && S_ISCDF(b1.st_mode));
2896		afree(nv, ATEMP);
2897		return (i);
2898	}
2899#else
2900		return (0);
2901#endif
2902
2903	/* -u */
2904	case TO_FILSETU:
2905		return (stat(opnd1, &b1) == 0 &&
2906		    (b1.st_mode & S_ISUID) == S_ISUID);
2907
2908	/* -g */
2909	case TO_FILSETG:
2910		return (stat(opnd1, &b1) == 0 &&
2911		    (b1.st_mode & S_ISGID) == S_ISGID);
2912
2913	/* -k */
2914	case TO_FILSTCK:
2915#ifdef S_ISVTX
2916		return (stat(opnd1, &b1) == 0 &&
2917		    (b1.st_mode & S_ISVTX) == S_ISVTX);
2918#else
2919		return (0);
2920#endif
2921
2922	/* -s */
2923	case TO_FILGZ:
2924		return (stat(opnd1, &b1) == 0 && (off_t)b1.st_size > (off_t)0);
2925
2926	/* -t */
2927	case TO_FILTT:
2928		if (opnd1 && !bi_getn(opnd1, &i)) {
2929			te->flags |= TEF_ERROR;
2930			i = 0;
2931		} else
2932			i = isatty(opnd1 ? i : 0);
2933		return (i);
2934
2935	/* -O */
2936	case TO_FILUID:
2937		return (stat(opnd1, &b1) == 0 && (uid_t)b1.st_uid == ksheuid);
2938
2939	/* -G */
2940	case TO_FILGID:
2941		return (stat(opnd1, &b1) == 0 && (gid_t)b1.st_gid == getegid());
2942
2943	/*
2944	 * Binary Operators
2945	 */
2946
2947	/* =, == */
2948	case TO_STEQL:
2949		if (te->flags & TEF_DBRACKET) {
2950			if ((i = gmatchx(opnd1, opnd2, false)))
2951				record_match(opnd1);
2952			return (i);
2953		}
2954		return (strcmp(opnd1, opnd2) == 0);
2955
2956	/* != */
2957	case TO_STNEQ:
2958		if (te->flags & TEF_DBRACKET) {
2959			if ((i = gmatchx(opnd1, opnd2, false)))
2960				record_match(opnd1);
2961			return (!i);
2962		}
2963		return (strcmp(opnd1, opnd2) != 0);
2964
2965	/* < */
2966	case TO_STLT:
2967		return (strcmp(opnd1, opnd2) < 0);
2968
2969	/* > */
2970	case TO_STGT:
2971		return (strcmp(opnd1, opnd2) > 0);
2972
2973	/* -eq */
2974	case TO_INTEQ:
2975	/* -ne */
2976	case TO_INTNE:
2977	/* -ge */
2978	case TO_INTGE:
2979	/* -gt */
2980	case TO_INTGT:
2981	/* -le */
2982	case TO_INTLE:
2983	/* -lt */
2984	case TO_INTLT:
2985		if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) ||
2986		    !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) {
2987			/* error already printed.. */
2988			te->flags |= TEF_ERROR;
2989			return (1);
2990		}
2991		switch (op) {
2992		case TO_INTEQ:
2993			return (v1 == v2);
2994		case TO_INTNE:
2995			return (v1 != v2);
2996		case TO_INTGE:
2997			return (v1 >= v2);
2998		case TO_INTGT:
2999			return (v1 > v2);
3000		case TO_INTLE:
3001			return (v1 <= v2);
3002		case TO_INTLT:
3003			return (v1 < v2);
3004		default:
3005			/* NOTREACHED */
3006			break;
3007		}
3008		/* NOTREACHED */
3009
3010	/* -nt */
3011	case TO_FILNT:
3012		/*
3013		 * ksh88/ksh93 succeed if file2 can't be stated
3014		 * (subtly different from 'does not exist').
3015		 */
3016		return (stat(opnd1, &b1) == 0 &&
3017		    (((s = stat(opnd2, &b2)) == 0 &&
3018		    b1.st_mtime > b2.st_mtime) || s < 0));
3019
3020	/* -ot */
3021	case TO_FILOT:
3022		/*
3023		 * ksh88/ksh93 succeed if file1 can't be stated
3024		 * (subtly different from 'does not exist').
3025		 */
3026		return (stat(opnd2, &b2) == 0 &&
3027		    (((s = stat(opnd1, &b1)) == 0 &&
3028		    b1.st_mtime < b2.st_mtime) || s < 0));
3029
3030	/* -ef */
3031	case TO_FILEQ:
3032		return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
3033		    b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
3034
3035	/* all other cases */
3036	case TO_NONOP:
3037	case TO_NONNULL:
3038		/* throw the error */
3039		break;
3040	}
3041	(*te->error)(te, 0, "internal error: unknown op");
3042	return (1);
3043}
3044
3045int
3046test_parse(Test_env *te)
3047{
3048	int rv;
3049
3050	rv = test_oexpr(te, 1);
3051
3052	if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
3053		(*te->error)(te, 0, "unexpected operator/operand");
3054
3055	return ((te->flags & TEF_ERROR) ? T_ERR_EXIT : !rv);
3056}
3057
3058static int
3059test_oexpr(Test_env *te, bool do_eval)
3060{
3061	int rv;
3062
3063	if ((rv = test_aexpr(te, do_eval)))
3064		do_eval = false;
3065	if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
3066		return (test_oexpr(te, do_eval) || rv);
3067	return (rv);
3068}
3069
3070static int
3071test_aexpr(Test_env *te, bool do_eval)
3072{
3073	int rv;
3074
3075	if (!(rv = test_nexpr(te, do_eval)))
3076		do_eval = false;
3077	if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
3078		return (test_aexpr(te, do_eval) && rv);
3079	return (rv);
3080}
3081
3082static int
3083test_nexpr(Test_env *te, bool do_eval)
3084{
3085	if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
3086		return (!test_nexpr(te, do_eval));
3087	return (test_primary(te, do_eval));
3088}
3089
3090static int
3091test_primary(Test_env *te, bool do_eval)
3092{
3093	const char *opnd1, *opnd2;
3094	int rv;
3095	Test_op op;
3096
3097	if (te->flags & TEF_ERROR)
3098		return (0);
3099	if ((*te->isa)(te, TM_OPAREN)) {
3100		rv = test_oexpr(te, do_eval);
3101		if (te->flags & TEF_ERROR)
3102			return (0);
3103		if (!(*te->isa)(te, TM_CPAREN)) {
3104			(*te->error)(te, 0, "missing )");
3105			return (0);
3106		}
3107		return (rv);
3108	}
3109	/*
3110	 * Binary should have precedence over unary in this case
3111	 * so that something like test \( -f = -f \) is accepted
3112	 */
3113	if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end &&
3114	    !test_isop(TM_BINOP, te->pos.wp[1]))) {
3115		if ((op = (*te->isa)(te, TM_UNOP))) {
3116			/* unary expression */
3117			opnd1 = (*te->getopnd)(te, op, do_eval);
3118			if (!opnd1) {
3119				(*te->error)(te, -1, Tno_args);
3120				return (0);
3121			}
3122
3123			return ((*te->eval)(te, op, opnd1, NULL, do_eval));
3124		}
3125	}
3126	opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
3127	if (!opnd1) {
3128		(*te->error)(te, 0, "expression expected");
3129		return (0);
3130	}
3131	if ((op = (*te->isa)(te, TM_BINOP))) {
3132		/* binary expression */
3133		opnd2 = (*te->getopnd)(te, op, do_eval);
3134		if (!opnd2) {
3135			(*te->error)(te, -1, "missing second argument");
3136			return (0);
3137		}
3138
3139		return ((*te->eval)(te, op, opnd1, opnd2, do_eval));
3140	}
3141	return ((*te->eval)(te, TO_STNZE, opnd1, NULL, do_eval));
3142}
3143
3144/*
3145 * Plain test (test and [ .. ]) specific routines.
3146 */
3147
3148/*
3149 * Test if the current token is a whatever. Accepts the current token if
3150 * it is. Returns 0 if it is not, non-zero if it is (in the case of
3151 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
3152 */
3153static Test_op
3154ptest_isa(Test_env *te, Test_meta meta)
3155{
3156	/* Order important - indexed by Test_meta values */
3157	static const char * const tokens[] = {
3158		"-o", "-a", "!", "(", ")"
3159	};
3160	Test_op rv;
3161
3162	if (te->pos.wp >= te->wp_end)
3163		return (meta == TM_END ? TO_NONNULL : TO_NONOP);
3164
3165	if (meta == TM_UNOP || meta == TM_BINOP)
3166		rv = test_isop(meta, *te->pos.wp);
3167	else if (meta == TM_END)
3168		rv = TO_NONOP;
3169	else
3170		rv = !strcmp(*te->pos.wp, tokens[(int)meta]) ?
3171		    TO_NONNULL : TO_NONOP;
3172
3173	/* Accept the token? */
3174	if (rv != TO_NONOP)
3175		te->pos.wp++;
3176
3177	return (rv);
3178}
3179
3180static const char *
3181ptest_getopnd(Test_env *te, Test_op op, bool do_eval MKSH_A_UNUSED)
3182{
3183	if (te->pos.wp >= te->wp_end)
3184		return (op == TO_FILTT ? "1" : NULL);
3185	return (*te->pos.wp++);
3186}
3187
3188static void
3189ptest_error(Test_env *te, int ofs, const char *msg)
3190{
3191	const char *op;
3192
3193	te->flags |= TEF_ERROR;
3194	if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs]))
3195		bi_errorf(Tf_sD_s, op, msg);
3196	else
3197		bi_errorf(Tf_s, msg);
3198}
3199
3200#ifndef MKSH_NO_LIMITS
3201#define SOFT	0x1
3202#define HARD	0x2
3203
3204/* Magic to divine the 'm' and 'v' limits */
3205
3206#ifdef RLIMIT_AS
3207#if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
3208    !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
3209#define ULIMIT_V_IS_AS
3210#elif defined(RLIMIT_VMEM)
3211#if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
3212#define ULIMIT_V_IS_AS
3213#else
3214#define ULIMIT_V_IS_VMEM
3215#endif
3216#endif
3217#endif
3218
3219#ifdef RLIMIT_RSS
3220#ifdef ULIMIT_V_IS_VMEM
3221#define ULIMIT_M_IS_RSS
3222#elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
3223#define ULIMIT_M_IS_VMEM
3224#else
3225#define ULIMIT_M_IS_RSS
3226#endif
3227#if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)
3228#undef ULIMIT_M_IS_RSS
3229#endif
3230#endif
3231
3232#if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
3233#define ULIMIT_V_IS_VMEM
3234#endif
3235
3236#if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
3237    (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
3238#define ULIMIT_M_IS_VMEM
3239#endif
3240
3241#if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
3242    (RLIMIT_VMEM == RLIMIT_AS)
3243#undef ULIMIT_M_IS_VMEM
3244#endif
3245
3246#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
3247# error nonsensical m ulimit
3248#endif
3249
3250#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
3251# error nonsensical v ulimit
3252#endif
3253
3254struct limits {
3255	/* limit resource */
3256	int resource;
3257	/* multiply by to get rlim_{cur,max} values */
3258	unsigned int factor;
3259	/* getopts char */
3260	char optchar;
3261	/* limit name */
3262	char name[1];
3263};
3264
3265#define RLIMITS_DEFNS
3266#define FN(lname,lid,lfac,lopt)				\
3267	static const struct {				\
3268		int resource;				\
3269		unsigned int factor;			\
3270		char optchar;				\
3271		char name[sizeof(lname)];		\
3272	} rlimits_ ## lid = {				\
3273		lid, lfac, lopt, lname			\
3274	};
3275#include "rlimits.gen"
3276
3277static void print_ulimit(const struct limits *, int);
3278static int set_ulimit(const struct limits *, const char *, int);
3279
3280static const struct limits * const rlimits[] = {
3281#define RLIMITS_ITEMS
3282#include "rlimits.gen"
3283};
3284
3285static const char rlimits_opts[] =
3286#define RLIMITS_OPTCS
3287#include "rlimits.gen"
3288    ;
3289
3290int
3291c_ulimit(const char **wp)
3292{
3293	size_t i = 0;
3294	int how = SOFT | HARD, optc, what = 'f';
3295	bool all = false;
3296
3297	while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
3298		switch (optc) {
3299		case 'H':
3300			how = HARD;
3301			break;
3302		case 'S':
3303			how = SOFT;
3304			break;
3305		case 'a':
3306			all = true;
3307			break;
3308		case '?':
3309			bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
3310			return (1);
3311		default:
3312			what = optc;
3313		}
3314
3315	while (i < NELEM(rlimits)) {
3316		if (rlimits[i]->optchar == what)
3317			goto found;
3318		++i;
3319	}
3320	internal_warningf("ulimit: %c", what);
3321	return (1);
3322 found:
3323	if (wp[builtin_opt.optind]) {
3324		if (all || wp[builtin_opt.optind + 1]) {
3325			bi_errorf(Ttoo_many_args);
3326			return (1);
3327		}
3328		return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
3329	}
3330	if (!all)
3331		print_ulimit(rlimits[i], how);
3332	else for (i = 0; i < NELEM(rlimits); ++i) {
3333		shprintf("-%c: %-20s  ", rlimits[i]->optchar, rlimits[i]->name);
3334		print_ulimit(rlimits[i], how);
3335	}
3336	return (0);
3337}
3338
3339static int
3340set_ulimit(const struct limits *l, const char *v, int how)
3341{
3342	rlim_t val = (rlim_t)0;
3343	struct rlimit limit;
3344
3345	if (strcmp(v, "unlimited") == 0)
3346		val = (rlim_t)RLIM_INFINITY;
3347	else {
3348		mksh_uari_t rval;
3349
3350		if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
3351			return (1);
3352		/*
3353		 * Avoid problems caused by typos that evaluate misses due
3354		 * to evaluating unset parameters to 0...
3355		 * If this causes problems, will have to add parameter to
3356		 * evaluate() to control if unset params are 0 or an error.
3357		 */
3358		if (!rval && !ctype(v[0], C_DIGIT)) {
3359			bi_errorf("invalid %s limit: %s", l->name, v);
3360			return (1);
3361		}
3362		val = (rlim_t)((rlim_t)rval * l->factor);
3363	}
3364
3365	if (getrlimit(l->resource, &limit) < 0) {
3366#ifndef MKSH_SMALL
3367		bi_errorf("limit %s could not be read, contact the mksh developers: %s",
3368		    l->name, cstrerror(errno));
3369#endif
3370		/* some can't be read */
3371		limit.rlim_cur = RLIM_INFINITY;
3372		limit.rlim_max = RLIM_INFINITY;
3373	}
3374	if (how & SOFT)
3375		limit.rlim_cur = val;
3376	if (how & HARD)
3377		limit.rlim_max = val;
3378	if (!setrlimit(l->resource, &limit))
3379		return (0);
3380	if (errno == EPERM)
3381		bi_errorf("%s exceeds allowable %s limit", v, l->name);
3382	else
3383		bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
3384	return (1);
3385}
3386
3387static void
3388print_ulimit(const struct limits *l, int how)
3389{
3390	rlim_t val = (rlim_t)0;
3391	struct rlimit limit;
3392
3393	if (getrlimit(l->resource, &limit)) {
3394		shf_puts("unknown\n", shl_stdout);
3395		return;
3396	}
3397	if (how & SOFT)
3398		val = limit.rlim_cur;
3399	else if (how & HARD)
3400		val = limit.rlim_max;
3401	if (val == (rlim_t)RLIM_INFINITY)
3402		shf_puts("unlimited\n", shl_stdout);
3403	else
3404		shprintf("%lu\n", (unsigned long)(val / l->factor));
3405}
3406#endif
3407
3408int
3409c_rename(const char **wp)
3410{
3411	int rv = 1;
3412
3413	/* skip argv[0] */
3414	++wp;
3415	if (wp[0] && !strcmp(wp[0], "--"))
3416		/* skip "--" (options separator) */
3417		++wp;
3418
3419	/* check for exactly two arguments */
3420	if (wp[0] == NULL	/* first argument */ ||
3421	    wp[1] == NULL	/* second argument */ ||
3422	    wp[2] != NULL	/* no further args please */)
3423		bi_errorf(Tsynerr);
3424	else if ((rv = rename(wp[0], wp[1])) != 0) {
3425		rv = errno;
3426		bi_errorf(Tf_sD_s, "failed", cstrerror(rv));
3427	}
3428
3429	return (rv);
3430}
3431
3432int
3433c_realpath(const char **wp)
3434{
3435	int rv = 1;
3436	char *buf;
3437
3438	/* skip argv[0] */
3439	++wp;
3440	if (wp[0] && !strcmp(wp[0], "--"))
3441		/* skip "--" (options separator) */
3442		++wp;
3443
3444	/* check for exactly one argument */
3445	if (wp[0] == NULL || wp[1] != NULL)
3446		bi_errorf(Tsynerr);
3447	else if ((buf = do_realpath(wp[0])) == NULL) {
3448		rv = errno;
3449		bi_errorf(Tf_sD_s, wp[0], cstrerror(rv));
3450		if ((unsigned int)rv > 255)
3451			rv = 255;
3452	} else {
3453		shprintf(Tf_sN, buf);
3454		afree(buf, ATEMP);
3455		rv = 0;
3456	}
3457
3458	return (rv);
3459}
3460
3461int
3462c_cat(const char **wp)
3463{
3464	int fd = STDIN_FILENO, rv;
3465	ssize_t n, w;
3466	const char *fn = "<stdin>";
3467	char *buf, *cp;
3468	bool opipe;
3469#define MKSH_CAT_BUFSIZ 4096
3470
3471	/* parse options: POSIX demands we support "-u" as no-op */
3472	while ((rv = ksh_getopt(wp, &builtin_opt, "u")) != -1) {
3473		switch (rv) {
3474		case 'u':
3475			/* we already operate unbuffered */
3476			break;
3477		default:
3478			bi_errorf(Tsynerr);
3479			return (1);
3480		}
3481	}
3482	wp += builtin_opt.optind;
3483	rv = 0;
3484
3485	if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
3486		bi_errorf(Toomem, (size_t)MKSH_CAT_BUFSIZ);
3487		return (1);
3488	}
3489
3490	/* catch SIGPIPE */
3491	opipe = block_pipe();
3492
3493	do {
3494		if (*wp) {
3495			fn = *wp++;
3496			if (ksh_isdash(fn))
3497				fd = STDIN_FILENO;
3498			else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
3499				bi_errorf(Tf_sD_s, fn, cstrerror(errno));
3500				rv = 1;
3501				continue;
3502			}
3503		}
3504		while (/* CONSTCOND */ 1) {
3505			if ((n = blocking_read(fd, (cp = buf),
3506			    MKSH_CAT_BUFSIZ)) == -1) {
3507				if (errno == EINTR) {
3508					if (opipe)
3509						restore_pipe();
3510					/* give the user a chance to ^C out */
3511					intrcheck();
3512					/* interrupted, try again */
3513					opipe = block_pipe();
3514					continue;
3515				}
3516				/* an error occured during reading */
3517				bi_errorf(Tf_sD_s, fn, cstrerror(errno));
3518				rv = 1;
3519				break;
3520			} else if (n == 0)
3521				/* end of file reached */
3522				break;
3523			while (n) {
3524				if (intrsig)
3525					goto has_intrsig;
3526				if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
3527					n -= w;
3528					cp += w;
3529					continue;
3530				}
3531				if (errno == EINTR) {
3532 has_intrsig:
3533					if (opipe)
3534						restore_pipe();
3535					/* give the user a chance to ^C out */
3536					intrcheck();
3537					/* interrupted, try again */
3538					opipe = block_pipe();
3539					continue;
3540				}
3541				if (errno == EPIPE) {
3542					/* fake receiving signal */
3543					rv = ksh_sigmask(SIGPIPE);
3544				} else {
3545					/* an error occured during writing */
3546					bi_errorf(Tf_sD_s, "<stdout>",
3547					    cstrerror(errno));
3548					rv = 1;
3549				}
3550				if (fd != STDIN_FILENO)
3551					close(fd);
3552				goto out;
3553			}
3554		}
3555		if (fd != STDIN_FILENO)
3556			close(fd);
3557	} while (*wp);
3558
3559 out:
3560	if (opipe)
3561		restore_pipe();
3562	free_osfunc(buf);
3563	return (rv);
3564}
3565
3566#if HAVE_SELECT
3567int
3568c_sleep(const char **wp)
3569{
3570	struct timeval tv;
3571	int rv = 1;
3572
3573	/* skip argv[0] */
3574	++wp;
3575	if (wp[0] && !strcmp(wp[0], "--"))
3576		/* skip "--" (options separator) */
3577		++wp;
3578
3579	if (!wp[0] || wp[1])
3580		bi_errorf(Tsynerr);
3581	else if (parse_usec(wp[0], &tv))
3582		bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno), wp[0]);
3583	else {
3584#ifndef MKSH_NOPROSPECTOFWORK
3585		sigset_t omask, bmask;
3586
3587		/* block a number of signals from interrupting us, though */
3588		(void)sigemptyset(&bmask);
3589		(void)sigaddset(&bmask, SIGPIPE);
3590		(void)sigaddset(&bmask, SIGCHLD);
3591#ifdef SIGWINCH
3592		(void)sigaddset(&bmask, SIGWINCH);
3593#endif
3594#ifdef SIGINFO
3595		(void)sigaddset(&bmask, SIGINFO);
3596#endif
3597#ifdef SIGUSR1
3598		(void)sigaddset(&bmask, SIGUSR1);
3599#endif
3600#ifdef SIGUSR2
3601		(void)sigaddset(&bmask, SIGUSR2);
3602#endif
3603		sigprocmask(SIG_BLOCK, &bmask, &omask);
3604#endif
3605		if (select(1, NULL, NULL, NULL, &tv) == 0 || errno == EINTR)
3606			/*
3607			 * strictly speaking only for SIGALRM, but the
3608			 * execution may be interrupted by other signals
3609			 */
3610			rv = 0;
3611		else
3612			bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
3613#ifndef MKSH_NOPROSPECTOFWORK
3614		/* this will re-schedule signal delivery */
3615		sigprocmask(SIG_SETMASK, &omask, NULL);
3616#endif
3617	}
3618	return (rv);
3619}
3620#endif
3621
3622#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
3623static int
3624c_suspend(const char **wp)
3625{
3626	if (wp[1] != NULL) {
3627		bi_errorf(Ttoo_many_args);
3628		return (1);
3629	}
3630	if (Flag(FLOGIN)) {
3631		/* Can't suspend an orphaned process group. */
3632		if (getpgid(kshppid) == getpgid(0) ||
3633		    getsid(kshppid) != getsid(0)) {
3634			bi_errorf("can't suspend a login shell");
3635			return (1);
3636		}
3637	}
3638	j_suspend();
3639	return (0);
3640}
3641#endif
3642