1/*	$OpenBSD: misc.c,v 1.41 2015/09/10 22:48:58 nicm Exp $	*/
2/*	$OpenBSD: path.c,v 1.13 2015/09/05 09:47:08 jsg Exp $	*/
3
4/*-
5 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6 *		 2011, 2012, 2013, 2014, 2015
7 *	mirabilos <m@mirbsd.org>
8 *
9 * Provided that these terms and disclaimer and all copyright notices
10 * are retained or reproduced in an accompanying document, permission
11 * is granted to deal in this work without restriction, including un-
12 * limited rights to use, publicly perform, distribute, sell, modify,
13 * merge, give away, or sublicence.
14 *
15 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
16 * the utmost extent permitted by applicable law, neither express nor
17 * implied; without malicious intent or gross negligence. In no event
18 * may a licensor, author or contributor be held liable for indirect,
19 * direct, other damage, loss, or other issues arising in any way out
20 * of dealing in the work, even if advised of the possibility of such
21 * damage or existence of a defect, except proven that it results out
22 * of said person's immediate fault when using the work as intended.
23 */
24
25#include "sh.h"
26#if !HAVE_GETRUSAGE
27#include <sys/times.h>
28#endif
29#if HAVE_GRP_H
30#include <grp.h>
31#endif
32
33__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.240 2015/10/09 16:11:17 tg Exp $");
34
35#define KSH_CHVT_FLAG
36#ifdef MKSH_SMALL
37#undef KSH_CHVT_FLAG
38#endif
39#ifdef TIOCSCTTY
40#define KSH_CHVT_CODE
41#define KSH_CHVT_FLAG
42#endif
43#ifdef MKSH_LEGACY_MODE
44#undef KSH_CHVT_CODE
45#undef KSH_CHVT_FLAG
46#endif
47
48/* type bits for unsigned char */
49unsigned char chtypes[UCHAR_MAX + 1];
50
51static const unsigned char *pat_scan(const unsigned char *,
52    const unsigned char *, bool) MKSH_A_PURE;
53static int do_gmatch(const unsigned char *, const unsigned char *,
54    const unsigned char *, const unsigned char *) MKSH_A_PURE;
55static const unsigned char *gmatch_cclass(const unsigned char *, unsigned char)
56    MKSH_A_PURE;
57#ifdef KSH_CHVT_CODE
58static void chvt(const Getopt *);
59#endif
60
61/*XXX this should go away */
62static int make_path(const char *, const char *, char **, XString *, int *);
63
64#ifdef SETUID_CAN_FAIL_WITH_EAGAIN
65/* we don't need to check for other codes, EPERM won't happen */
66#define DO_SETUID(func, argvec) do {					\
67	if ((func argvec) && errno == EAGAIN)				\
68		errorf("%s failed with EAGAIN, probably due to a"	\
69		    " too low process limit; aborting", #func);		\
70} while (/* CONSTCOND */ 0)
71#else
72#define DO_SETUID(func, argvec) func argvec
73#endif
74
75/*
76 * Fast character classes
77 */
78void
79setctypes(const char *s, int t)
80{
81	unsigned int i;
82
83	if (t & C_IFS) {
84		for (i = 0; i < UCHAR_MAX + 1; i++)
85			chtypes[i] &= ~C_IFS;
86		/* include \0 in C_IFS */
87		chtypes[0] |= C_IFS;
88	}
89	while (*s != 0)
90		chtypes[(unsigned char)*s++] |= t;
91}
92
93void
94initctypes(void)
95{
96	setctypes(letters_uc, C_ALPHA);
97	setctypes(letters_lc, C_ALPHA);
98	chtypes['_'] |= C_ALPHA;
99	setctypes("0123456789", C_DIGIT);
100	/* \0 added automatically */
101	setctypes(TC_LEX1, C_LEX1);
102	setctypes("*@#!$-?", C_VAR1);
103	setctypes(TC_IFSWS, C_IFSWS);
104	setctypes("=-+?", C_SUBOP1);
105	setctypes("\t\n \"#$&'()*;<=>?[\\]`|", C_QUOTE);
106}
107
108/* called from XcheckN() to grow buffer */
109char *
110Xcheck_grow(XString *xsp, const char *xp, size_t more)
111{
112	const char *old_beg = xsp->beg;
113
114	if (more < xsp->len)
115		more = xsp->len;
116	/* (xsp->len + X_EXTRA) never overflows */
117	checkoktoadd(more, xsp->len + X_EXTRA);
118	xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap);
119	xsp->end = xsp->beg + xsp->len;
120	return (xsp->beg + (xp - old_beg));
121}
122
123
124#define SHFLAGS_DEFNS
125#define FN(sname,cname,flags,ochar)		\
126	static const struct {			\
127		/* character flag (if any) */	\
128		char c;				\
129		/* OF_* */			\
130		unsigned char optflags;		\
131		/* long name of option */	\
132		char name[sizeof(sname)];	\
133	} shoptione_ ## cname = {		\
134		ochar, flags, sname		\
135	};
136#include "sh_flags.gen"
137
138#define OFC(i) (options[i][-2])
139#define OFF(i) (((const unsigned char *)options[i])[-1])
140#define OFN(i) (options[i])
141
142const char * const options[] = {
143#define SHFLAGS_ITEMS
144#include "sh_flags.gen"
145};
146
147/*
148 * translate -o option into F* constant (also used for test -o option)
149 */
150size_t
151option(const char *n)
152{
153	size_t i = 0;
154
155	if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2])
156		while (i < NELEM(options)) {
157			if (OFC(i) == n[1])
158				return (i);
159			++i;
160		}
161	else
162		while (i < NELEM(options)) {
163			if (!strcmp(OFN(i), n))
164				return (i);
165			++i;
166		}
167
168	return ((size_t)-1);
169}
170
171struct options_info {
172	int opt_width;
173	int opts[NELEM(options)];
174};
175
176static void options_fmt_entry(char *, size_t, unsigned int, const void *);
177static void printoptions(bool);
178
179/* format a single select menu item */
180static void
181options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
182{
183	const struct options_info *oi = (const struct options_info *)arg;
184
185	shf_snprintf(buf, buflen, "%-*s %s",
186	    oi->opt_width, OFN(oi->opts[i]),
187	    Flag(oi->opts[i]) ? "on" : "off");
188}
189
190static void
191printoptions(bool verbose)
192{
193	size_t i = 0;
194
195	if (verbose) {
196		size_t n = 0, len, octs = 0;
197		struct options_info oi;
198
199		/* verbose version */
200		shf_puts("Current option settings\n", shl_stdout);
201
202		oi.opt_width = 0;
203		while (i < NELEM(options)) {
204			if ((len = strlen(OFN(i)))) {
205				oi.opts[n++] = i;
206				if (len > octs)
207					octs = len;
208				len = utf_mbswidth(OFN(i));
209				if ((int)len > oi.opt_width)
210					oi.opt_width = (int)len;
211			}
212			++i;
213		}
214		print_columns(shl_stdout, n, options_fmt_entry, &oi,
215		    octs + 4, oi.opt_width + 4, true);
216	} else {
217		/* short version like AT&T ksh93 */
218		shf_puts(Tset, shl_stdout);
219		while (i < NELEM(options)) {
220			if (Flag(i) && OFN(i)[0])
221				shprintf(" -o %s", OFN(i));
222			++i;
223		}
224		shf_putc('\n', shl_stdout);
225	}
226}
227
228char *
229getoptions(void)
230{
231	size_t i = 0;
232	char c, m[(int)FNFLAGS + 1];
233	char *cp = m;
234
235	while (i < NELEM(options)) {
236		if ((c = OFC(i)) && Flag(i))
237			*cp++ = c;
238		++i;
239	}
240	strndupx(cp, m, cp - m, ATEMP);
241	return (cp);
242}
243
244/* change a Flag(*) value; takes care of special actions */
245void
246change_flag(enum sh_flag f, int what, bool newset)
247{
248	unsigned char oldval;
249	unsigned char newval = (newset ? 1 : 0);
250
251	if (f == FXTRACE) {
252		change_xtrace(newval, true);
253		return;
254	}
255	oldval = Flag(f);
256	Flag(f) = newval = (newset ? 1 : 0);
257#ifndef MKSH_UNEMPLOYED
258	if (f == FMONITOR) {
259		if (what != OF_CMDLINE && newval != oldval)
260			j_change();
261	} else
262#endif
263#ifndef MKSH_NO_CMDLINE_EDITING
264	  if ((
265#if !MKSH_S_NOVI
266	    f == FVI ||
267#endif
268	    f == FEMACS || f == FGMACS) && newval) {
269#if !MKSH_S_NOVI
270		Flag(FVI) =
271#endif
272		    Flag(FEMACS) = Flag(FGMACS) = 0;
273		Flag(f) = newval;
274	} else
275#endif
276	  if (f == FPRIVILEGED && oldval && !newval) {
277		/* Turning off -p? */
278
279		/*XXX this can probably be optimised */
280		kshegid = kshgid = getgid();
281		ksheuid = kshuid = getuid();
282#if HAVE_SETRESUGID
283		DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
284#if HAVE_SETGROUPS
285		/* setgroups doesn't EAGAIN on Linux */
286		setgroups(1, &kshegid);
287#endif
288		DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid));
289#else /* !HAVE_SETRESUGID */
290		/* setgid, setegid, seteuid don't EAGAIN on Linux */
291		setgid(kshegid);
292#ifndef MKSH__NO_SETEUGID
293		setegid(kshegid);
294#endif
295		DO_SETUID(setuid, (ksheuid));
296#ifndef MKSH__NO_SETEUGID
297		seteuid(ksheuid);
298#endif
299#endif /* !HAVE_SETRESUGID */
300	} else if ((f == FPOSIX || f == FSH) && newval) {
301		/* Turning on -o posix or -o sh? */
302		Flag(FBRACEEXPAND) = 0;
303	} else if (f == FTALKING) {
304		/* Changing interactive flag? */
305		if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
306			Flag(FTALKING_I) = newval;
307	}
308}
309
310void
311change_xtrace(unsigned char newval, bool dosnapshot)
312{
313	static bool in_xtrace;
314
315	if (in_xtrace)
316		return;
317
318	if (!dosnapshot && newval == Flag(FXTRACE))
319		return;
320
321	if (Flag(FXTRACE) == 2) {
322		shf_putc('\n', shl_xtrace);
323		Flag(FXTRACE) = 1;
324		shf_flush(shl_xtrace);
325	}
326
327	if (!dosnapshot && Flag(FXTRACE) == 1)
328		switch (newval) {
329		case 1:
330			return;
331		case 2:
332			goto changed_xtrace;
333		}
334
335	shf_flush(shl_xtrace);
336	if (shl_xtrace->fd != 2)
337		close(shl_xtrace->fd);
338	if (!newval || (shl_xtrace->fd = savefd(2)) == -1)
339		shl_xtrace->fd = 2;
340
341 changed_xtrace:
342	if ((Flag(FXTRACE) = newval) == 2) {
343		in_xtrace = true;
344		Flag(FXTRACE) = 0;
345		shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace);
346		Flag(FXTRACE) = 2;
347		in_xtrace = false;
348	}
349}
350
351/*
352 * Parse command line and set command arguments. Returns the index of
353 * non-option arguments, -1 if there is an error.
354 */
355int
356parse_args(const char **argv,
357    /* OF_CMDLINE or OF_SET */
358    int what,
359    bool *setargsp)
360{
361	static const char cmd_opts[] =
362#define SHFLAGS_NOT_SET
363#define SHFLAGS_OPTCS
364#include "sh_flags.gen"
365#undef SHFLAGS_NOT_SET
366	    ;
367	static const char set_opts[] =
368#define SHFLAGS_NOT_CMD
369#define SHFLAGS_OPTCS
370#include "sh_flags.gen"
371#undef SHFLAGS_NOT_CMD
372	    ;
373	bool set;
374	const char *opts;
375	const char *array = NULL;
376	Getopt go;
377	size_t i;
378	int optc, arrayset = 0;
379	bool sortargs = false;
380	bool fcompatseen = false;
381
382	if (what == OF_CMDLINE) {
383		const char *p = argv[0], *q;
384		/*
385		 * Set FLOGIN before parsing options so user can clear
386		 * flag using +l.
387		 */
388		if (*p != '-')
389			for (q = p; *q; )
390				if (*q++ == '/')
391					p = q;
392		Flag(FLOGIN) = (*p == '-');
393		opts = cmd_opts;
394	} else if (what == OF_FIRSTTIME) {
395		opts = cmd_opts;
396	} else
397		opts = set_opts;
398	ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT);
399	while ((optc = ksh_getopt(argv, &go, opts)) != -1) {
400		set = tobool(!(go.info & GI_PLUS));
401		switch (optc) {
402		case 'A':
403			if (what == OF_FIRSTTIME)
404				break;
405			arrayset = set ? 1 : -1;
406			array = go.optarg;
407			break;
408
409		case 'o':
410			if (what == OF_FIRSTTIME)
411				break;
412			if (go.optarg == NULL) {
413				/*
414				 * lone -o: print options
415				 *
416				 * Note that on the command line, -o requires
417				 * an option (ie, can't get here if what is
418				 * OF_CMDLINE).
419				 */
420				printoptions(set);
421				break;
422			}
423			i = option(go.optarg);
424			if ((i == FPOSIX || i == FSH) && set && !fcompatseen) {
425				/*
426				 * If running 'set -o posix' or
427				 * 'set -o sh', turn off the other;
428				 * if running 'set -o posix -o sh'
429				 * allow both to be set though.
430				 */
431				Flag(FPOSIX) = 0;
432				Flag(FSH) = 0;
433				fcompatseen = true;
434			}
435			if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i))
436				/*
437				 * Don't check the context if the flag
438				 * isn't changing - makes "set -o interactive"
439				 * work if you're already interactive. Needed
440				 * if the output of "set +o" is to be used.
441				 */
442				;
443			else if ((i != (size_t)-1) && (OFF(i) & what))
444				change_flag((enum sh_flag)i, what, set);
445			else {
446				bi_errorf("%s: %s", go.optarg, "bad option");
447				return (-1);
448			}
449			break;
450
451#ifdef KSH_CHVT_FLAG
452		case 'T':
453			if (what != OF_FIRSTTIME)
454				break;
455#ifndef KSH_CHVT_CODE
456			errorf("no TIOCSCTTY ioctl");
457#else
458			change_flag(FTALKING, OF_CMDLINE, true);
459			chvt(&go);
460			break;
461#endif
462#endif
463
464		case '?':
465			return (-1);
466
467		default:
468			if (what == OF_FIRSTTIME)
469				break;
470			/* -s: sort positional params (AT&T ksh stupidity) */
471			if (what == OF_SET && optc == 's') {
472				sortargs = true;
473				break;
474			}
475			for (i = 0; i < NELEM(options); i++)
476				if (optc == OFC(i) &&
477				    (what & OFF(i))) {
478					change_flag((enum sh_flag)i, what, set);
479					break;
480				}
481			if (i == NELEM(options))
482				internal_errorf("parse_args: '%c'", optc);
483		}
484	}
485	if (!(go.info & GI_MINUSMINUS) && argv[go.optind] &&
486	    (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
487	    argv[go.optind][1] == '\0') {
488		/* lone - clears -v and -x flags */
489		if (argv[go.optind][0] == '-') {
490			Flag(FVERBOSE) = 0;
491			change_xtrace(0, false);
492		}
493		/* set skips lone - or + option */
494		go.optind++;
495	}
496	if (setargsp)
497		/* -- means set $#/$* even if there are no arguments */
498		*setargsp = !arrayset && ((go.info & GI_MINUSMINUS) ||
499		    argv[go.optind]);
500
501	if (arrayset) {
502		const char *ccp = NULL;
503
504		if (*array)
505			ccp = skip_varname(array, false);
506		if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
507			bi_errorf("%s: %s", array, "is not an identifier");
508			return (-1);
509		}
510	}
511	if (sortargs) {
512		for (i = go.optind; argv[i]; i++)
513			;
514		qsort(&argv[go.optind], i - go.optind, sizeof(void *),
515		    xstrcmp);
516	}
517	if (arrayset)
518		go.optind += set_array(array, tobool(arrayset > 0),
519		    argv + go.optind);
520
521	return (go.optind);
522}
523
524/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */
525int
526getn(const char *s, int *ai)
527{
528	char c;
529	mksh_ari_u num;
530	bool neg = false;
531
532	num.u = 0;
533
534	do {
535		c = *s++;
536	} while (ksh_isspace(c));
537
538	switch (c) {
539	case '-':
540		neg = true;
541		/* FALLTHROUGH */
542	case '+':
543		c = *s++;
544		break;
545	}
546
547	do {
548		if (!ksh_isdigit(c))
549			/* not numeric */
550			return (0);
551		if (num.u > 214748364U)
552			/* overflow on multiplication */
553			return (0);
554		num.u = num.u * 10U + (unsigned int)ksh_numdig(c);
555		/* now: num.u <= 2147483649U */
556	} while ((c = *s++));
557
558	if (num.u > (neg ? 2147483648U : 2147483647U))
559		/* overflow for signed 32-bit int */
560		return (0);
561
562	if (neg)
563		num.u = -num.u;
564	*ai = num.i;
565	return (1);
566}
567
568/**
569 * pattern simplifications:
570 * - @(x) -> x (not @(x|y) though)
571 * - ** -> *
572 */
573static void *
574simplify_gmatch_pattern(const unsigned char *sp)
575{
576	uint8_t c;
577	unsigned char *cp, *dp;
578	const unsigned char *ps, *se;
579
580	cp = alloc(strlen((const void *)sp) + 1, ATEMP);
581	goto simplify_gmatch_pat1a;
582
583	/* foo@(b@(a)r)b@(a|a)z -> foobarb@(a|a)z */
584 simplify_gmatch_pat1:
585	sp = cp;
586 simplify_gmatch_pat1a:
587	dp = cp;
588	se = sp + strlen((const void *)sp);
589	while ((c = *sp++)) {
590		if (!ISMAGIC(c)) {
591			*dp++ = c;
592			continue;
593		}
594		switch ((c = *sp++)) {
595		case 0x80|'@':
596		/* simile for @ */
597		case 0x80|' ':
598			/* check whether it has only one clause */
599			ps = pat_scan(sp, se, true);
600			if (!ps || ps[-1] != /*(*/ ')')
601				/* nope */
602				break;
603			/* copy inner clause until matching close */
604			ps -= 2;
605			while ((const unsigned char *)sp < ps)
606				*dp++ = *sp++;
607			/* skip MAGIC and closing parenthesis */
608			sp += 2;
609			/* copy the rest of the pattern */
610			memmove(dp, sp, strlen((const void *)sp) + 1);
611			/* redo from start */
612			goto simplify_gmatch_pat1;
613		}
614		*dp++ = MAGIC;
615		*dp++ = c;
616	}
617	*dp = '\0';
618
619	/* collapse adjacent asterisk wildcards */
620	sp = dp = cp;
621	while ((c = *sp++)) {
622		if (!ISMAGIC(c)) {
623			*dp++ = c;
624			continue;
625		}
626		switch ((c = *sp++)) {
627		case '*':
628			while (ISMAGIC(sp[0]) && sp[1] == c)
629				sp += 2;
630			break;
631		}
632		*dp++ = MAGIC;
633		*dp++ = c;
634	}
635	*dp = '\0';
636
637	/* return the result, allocated from ATEMP */
638	return (cp);
639}
640
641/* -------- gmatch.c -------- */
642
643/*
644 * int gmatch(string, pattern)
645 * char *string, *pattern;
646 *
647 * Match a pattern as in sh(1).
648 * pattern character are prefixed with MAGIC by expand.
649 */
650int
651gmatchx(const char *s, const char *p, bool isfile)
652{
653	const char *se, *pe;
654	char *pnew;
655	int rv;
656
657	if (s == NULL || p == NULL)
658		return (0);
659
660	se = s + strlen(s);
661	pe = p + strlen(p);
662	/*
663	 * isfile is false iff no syntax check has been done on
664	 * the pattern. If check fails, just to a strcmp().
665	 */
666	if (!isfile && !has_globbing(p, pe)) {
667		size_t len = pe - p + 1;
668		char tbuf[64];
669		char *t = len <= sizeof(tbuf) ? tbuf : alloc(len, ATEMP);
670		debunk(t, p, len);
671		return (!strcmp(t, s));
672	}
673
674	/*
675	 * since the do_gmatch() engine sucks so much, we must do some
676	 * pattern simplifications
677	 */
678	pnew = simplify_gmatch_pattern((const unsigned char *)p);
679	pe = pnew + strlen(pnew);
680
681	rv = do_gmatch((const unsigned char *)s, (const unsigned char *)se,
682	    (const unsigned char *)pnew, (const unsigned char *)pe);
683	afree(pnew, ATEMP);
684	return (rv);
685}
686
687/**
688 * Returns if p is a syntacticly correct globbing pattern, false
689 * if it contains no pattern characters or if there is a syntax error.
690 * Syntax errors are:
691 *	- [ with no closing ]
692 *	- imbalanced $(...) expression
693 *	- [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d))
694 */
695/*XXX
696 * - if no magic,
697 *	if dest given, copy to dst
698 *	return ?
699 * - if magic && (no globbing || syntax error)
700 *	debunk to dst
701 *	return ?
702 * - return ?
703 */
704int
705has_globbing(const char *xp, const char *xpe)
706{
707	const unsigned char *p = (const unsigned char *) xp;
708	const unsigned char *pe = (const unsigned char *) xpe;
709	int c;
710	int nest = 0, bnest = 0;
711	bool saw_glob = false;
712	/* inside [...] */
713	bool in_bracket = false;
714
715	for (; p < pe; p++) {
716		if (!ISMAGIC(*p))
717			continue;
718		if ((c = *++p) == '*' || c == '?')
719			saw_glob = true;
720		else if (c == '[') {
721			if (!in_bracket) {
722				saw_glob = true;
723				in_bracket = true;
724				if (ISMAGIC(p[1]) && p[2] == '!')
725					p += 2;
726				if (ISMAGIC(p[1]) && p[2] == ']')
727					p += 2;
728			}
729			/*XXX Do we need to check ranges here? POSIX Q */
730		} else if (c == ']') {
731			if (in_bracket) {
732				if (bnest)
733					/* [a*(b]) */
734					return (0);
735				in_bracket = false;
736			}
737		} else if ((c & 0x80) && vstrchr("*+?@! ", c & 0x7f)) {
738			saw_glob = true;
739			if (in_bracket)
740				bnest++;
741			else
742				nest++;
743		} else if (c == '|') {
744			if (in_bracket && !bnest)
745				/* *(a[foo|bar]) */
746				return (0);
747		} else if (c == /*(*/ ')') {
748			if (in_bracket) {
749				if (!bnest--)
750					/* *(a[b)c] */
751					return (0);
752			} else if (nest)
753				nest--;
754		}
755		/*
756		 * else must be a MAGIC-MAGIC, or MAGIC-!,
757		 * MAGIC--, MAGIC-], MAGIC-{, MAGIC-, MAGIC-}
758		 */
759	}
760	return (saw_glob && !in_bracket && !nest);
761}
762
763/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */
764static int
765do_gmatch(const unsigned char *s, const unsigned char *se,
766    const unsigned char *p, const unsigned char *pe)
767{
768	unsigned char sc, pc;
769	const unsigned char *prest, *psub, *pnext;
770	const unsigned char *srest;
771
772	if (s == NULL || p == NULL)
773		return (0);
774	while (p < pe) {
775		pc = *p++;
776		sc = s < se ? *s : '\0';
777		s++;
778		if (!ISMAGIC(pc)) {
779			if (sc != pc)
780				return (0);
781			continue;
782		}
783		switch (*p++) {
784		case '[':
785			if (sc == 0 || (p = gmatch_cclass(p, sc)) == NULL)
786				return (0);
787			break;
788
789		case '?':
790			if (sc == 0)
791				return (0);
792			if (UTFMODE) {
793				--s;
794				s += utf_ptradj((const void *)s);
795			}
796			break;
797
798		case '*':
799			if (p == pe)
800				return (1);
801			s--;
802			do {
803				if (do_gmatch(s, se, p, pe))
804					return (1);
805			} while (s++ < se);
806			return (0);
807
808		/**
809		 * [*+?@!](pattern|pattern|..)
810		 * This is also needed for ${..%..}, etc.
811		 */
812
813		/* matches one or more times */
814		case 0x80|'+':
815		/* matches zero or more times */
816		case 0x80|'*':
817			if (!(prest = pat_scan(p, pe, false)))
818				return (0);
819			s--;
820			/* take care of zero matches */
821			if (p[-1] == (0x80 | '*') &&
822			    do_gmatch(s, se, prest, pe))
823				return (1);
824			for (psub = p; ; psub = pnext) {
825				pnext = pat_scan(psub, pe, true);
826				for (srest = s; srest <= se; srest++) {
827					if (do_gmatch(s, srest, psub, pnext - 2) &&
828					    (do_gmatch(srest, se, prest, pe) ||
829					    (s != srest && do_gmatch(srest,
830					    se, p - 2, pe))))
831						return (1);
832				}
833				if (pnext == prest)
834					break;
835			}
836			return (0);
837
838		/* matches zero or once */
839		case 0x80|'?':
840		/* matches one of the patterns */
841		case 0x80|'@':
842		/* simile for @ */
843		case 0x80|' ':
844			if (!(prest = pat_scan(p, pe, false)))
845				return (0);
846			s--;
847			/* Take care of zero matches */
848			if (p[-1] == (0x80 | '?') &&
849			    do_gmatch(s, se, prest, pe))
850				return (1);
851			for (psub = p; ; psub = pnext) {
852				pnext = pat_scan(psub, pe, true);
853				srest = prest == pe ? se : s;
854				for (; srest <= se; srest++) {
855					if (do_gmatch(s, srest, psub, pnext - 2) &&
856					    do_gmatch(srest, se, prest, pe))
857						return (1);
858				}
859				if (pnext == prest)
860					break;
861			}
862			return (0);
863
864		/* matches none of the patterns */
865		case 0x80|'!':
866			if (!(prest = pat_scan(p, pe, false)))
867				return (0);
868			s--;
869			for (srest = s; srest <= se; srest++) {
870				int matched = 0;
871
872				for (psub = p; ; psub = pnext) {
873					pnext = pat_scan(psub, pe, true);
874					if (do_gmatch(s, srest, psub,
875					    pnext - 2)) {
876						matched = 1;
877						break;
878					}
879					if (pnext == prest)
880						break;
881				}
882				if (!matched &&
883				    do_gmatch(srest, se, prest, pe))
884					return (1);
885			}
886			return (0);
887
888		default:
889			if (sc != p[-1])
890				return (0);
891			break;
892		}
893	}
894	return (s == se);
895}
896
897static const unsigned char *
898gmatch_cclass(const unsigned char *p, unsigned char sub)
899{
900	unsigned char c, d;
901	bool notp, found = false;
902	const unsigned char *orig_p = p;
903
904	if ((notp = tobool(ISMAGIC(*p) && *++p == '!')))
905		p++;
906	do {
907		c = *p++;
908		if (ISMAGIC(c)) {
909			c = *p++;
910			if ((c & 0x80) && !ISMAGIC(c)) {
911				/* extended pattern matching: *+?@! */
912				c &= 0x7F;
913				/* XXX the ( char isn't handled as part of [] */
914				if (c == ' ')
915					/* simile for @: plain (..) */
916					c = '(' /*)*/;
917			}
918		}
919		if (c == '\0')
920			/* No closing ] - act as if the opening [ was quoted */
921			return (sub == '[' ? orig_p : NULL);
922		if (ISMAGIC(p[0]) && p[1] == '-' &&
923		    (!ISMAGIC(p[2]) || p[3] != ']')) {
924			/* MAGIC- */
925			p += 2;
926			d = *p++;
927			if (ISMAGIC(d)) {
928				d = *p++;
929				if ((d & 0x80) && !ISMAGIC(d))
930					d &= 0x7f;
931			}
932			/* POSIX says this is an invalid expression */
933			if (c > d)
934				return (NULL);
935		} else
936			d = c;
937		if (c == sub || (c <= sub && sub <= d))
938			found = true;
939	} while (!(ISMAGIC(p[0]) && p[1] == ']'));
940
941	return ((found != notp) ? p+2 : NULL);
942}
943
944/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
945static const unsigned char *
946pat_scan(const unsigned char *p, const unsigned char *pe, bool match_sep)
947{
948	int nest = 0;
949
950	for (; p < pe; p++) {
951		if (!ISMAGIC(*p))
952			continue;
953		if ((*++p == /*(*/ ')' && nest-- == 0) ||
954		    (*p == '|' && match_sep && nest == 0))
955			return (p + 1);
956		if ((*p & 0x80) && vstrchr("*+?@! ", *p & 0x7f))
957			nest++;
958	}
959	return (NULL);
960}
961
962int
963xstrcmp(const void *p1, const void *p2)
964{
965	return (strcmp(*(const char * const *)p1, *(const char * const *)p2));
966}
967
968/* Initialise a Getopt structure */
969void
970ksh_getopt_reset(Getopt *go, int flags)
971{
972	go->optind = 1;
973	go->optarg = NULL;
974	go->p = 0;
975	go->flags = flags;
976	go->info = 0;
977	go->buf[1] = '\0';
978}
979
980
981/**
982 * getopt() used for shell built-in commands, the getopts command, and
983 * command line options.
984 * A leading ':' in options means don't print errors, instead return '?'
985 * or ':' and set go->optarg to the offending option character.
986 * If GF_ERROR is set (and option doesn't start with :), errors result in
987 * a call to bi_errorf().
988 *
989 * Non-standard features:
990 *	- ';' is like ':' in options, except the argument is optional
991 *	  (if it isn't present, optarg is set to 0).
992 *	  Used for 'set -o'.
993 *	- ',' is like ':' in options, except the argument always immediately
994 *	  follows the option character (optarg is set to the null string if
995 *	  the option is missing).
996 *	  Used for 'read -u2', 'print -u2' and fc -40.
997 *	- '#' is like ':' in options, expect that the argument is optional
998 *	  and must start with a digit. If the argument doesn't start with a
999 *	  digit, it is assumed to be missing and normal option processing
1000 *	  continues (optarg is set to 0 if the option is missing).
1001 *	  Used for 'typeset -LZ4'.
1002 *	- accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
1003 *	  option starting with + is accepted, the GI_PLUS flag will be set
1004 *	  in go->info.
1005 */
1006int
1007ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
1008{
1009	char c;
1010	const char *o;
1011
1012	if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') {
1013		const char *arg = argv[go->optind], flag = arg ? *arg : '\0';
1014
1015		go->p = 1;
1016		if (flag == '-' && ksh_isdash(arg + 1)) {
1017			go->optind++;
1018			go->p = 0;
1019			go->info |= GI_MINUSMINUS;
1020			return (-1);
1021		}
1022		if (arg == NULL ||
1023		    ((flag != '-' ) &&
1024		    /* neither a - nor a + (if + allowed) */
1025		    (!(go->flags & GF_PLUSOPT) || flag != '+')) ||
1026		    (c = arg[1]) == '\0') {
1027			go->p = 0;
1028			return (-1);
1029		}
1030		go->optind++;
1031		go->info &= ~(GI_MINUS|GI_PLUS);
1032		go->info |= flag == '-' ? GI_MINUS : GI_PLUS;
1033	}
1034	go->p++;
1035	if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#' ||
1036	    !(o = cstrchr(optionsp, c))) {
1037		if (optionsp[0] == ':') {
1038			go->buf[0] = c;
1039			go->optarg = go->buf;
1040		} else {
1041			warningf(true, "%s%s-%c: %s",
1042			    (go->flags & GF_NONAME) ? "" : argv[0],
1043			    (go->flags & GF_NONAME) ? "" : ": ", c,
1044			    "unknown option");
1045			if (go->flags & GF_ERROR)
1046				bi_errorfz();
1047		}
1048		return ('?');
1049	}
1050	/**
1051	 * : means argument must be present, may be part of option argument
1052	 *   or the next argument
1053	 * ; same as : but argument may be missing
1054	 * , means argument is part of option argument, and may be null.
1055	 */
1056	if (*++o == ':' || *o == ';') {
1057		if (argv[go->optind - 1][go->p])
1058			go->optarg = argv[go->optind - 1] + go->p;
1059		else if (argv[go->optind])
1060			go->optarg = argv[go->optind++];
1061		else if (*o == ';')
1062			go->optarg = NULL;
1063		else {
1064			if (optionsp[0] == ':') {
1065				go->buf[0] = c;
1066				go->optarg = go->buf;
1067				return (':');
1068			}
1069			warningf(true, "%s%s-%c: %s",
1070			    (go->flags & GF_NONAME) ? "" : argv[0],
1071			    (go->flags & GF_NONAME) ? "" : ": ", c,
1072			    "requires an argument");
1073			if (go->flags & GF_ERROR)
1074				bi_errorfz();
1075			return ('?');
1076		}
1077		go->p = 0;
1078	} else if (*o == ',') {
1079		/* argument is attached to option character, even if null */
1080		go->optarg = argv[go->optind - 1] + go->p;
1081		go->p = 0;
1082	} else if (*o == '#') {
1083		/*
1084		 * argument is optional and may be attached or unattached
1085		 * but must start with a digit. optarg is set to 0 if the
1086		 * argument is missing.
1087		 */
1088		if (argv[go->optind - 1][go->p]) {
1089			if (ksh_isdigit(argv[go->optind - 1][go->p])) {
1090				go->optarg = argv[go->optind - 1] + go->p;
1091				go->p = 0;
1092			} else
1093				go->optarg = NULL;
1094		} else {
1095			if (argv[go->optind] && ksh_isdigit(argv[go->optind][0])) {
1096				go->optarg = argv[go->optind++];
1097				go->p = 0;
1098			} else
1099				go->optarg = NULL;
1100		}
1101	}
1102	return (c);
1103}
1104
1105/*
1106 * print variable/alias value using necessary quotes
1107 * (POSIX says they should be suitable for re-entry...)
1108 * No trailing newline is printed.
1109 */
1110void
1111print_value_quoted(struct shf *shf, const char *s)
1112{
1113	unsigned char c;
1114	const unsigned char *p = (const unsigned char *)s;
1115	bool inquote = true;
1116
1117	/* first, check whether any quotes are needed */
1118	while ((c = *p++) >= 32)
1119		if (ctype(c, C_QUOTE))
1120			inquote = false;
1121
1122	p = (const unsigned char *)s;
1123	if (c == 0) {
1124		if (inquote) {
1125			/* nope, use the shortcut */
1126			shf_puts(s, shf);
1127			return;
1128		}
1129
1130		/* otherwise, quote nicely via state machine */
1131		while ((c = *p++) != 0) {
1132			if (c == '\'') {
1133				/*
1134				 * multiple single quotes or any of them
1135				 * at the beginning of a string look nicer
1136				 * this way than when simply substituting
1137				 */
1138				if (inquote) {
1139					shf_putc('\'', shf);
1140					inquote = false;
1141				}
1142				shf_putc('\\', shf);
1143			} else if (!inquote) {
1144				shf_putc('\'', shf);
1145				inquote = true;
1146			}
1147			shf_putc(c, shf);
1148		}
1149	} else {
1150		unsigned int wc;
1151		size_t n;
1152
1153		/* use $'...' quote format */
1154		shf_putc('$', shf);
1155		shf_putc('\'', shf);
1156		while ((c = *p) != 0) {
1157			if (c >= 0xC2) {
1158				n = utf_mbtowc(&wc, (const char *)p);
1159				if (n != (size_t)-1) {
1160					p += n;
1161					shf_fprintf(shf, "\\u%04X", wc);
1162					continue;
1163				}
1164			}
1165			++p;
1166			switch (c) {
1167			/* see unbksl() in this file for comments */
1168			case 7:
1169				c = 'a';
1170				if (0)
1171					/* FALLTHROUGH */
1172			case '\b':
1173				  c = 'b';
1174				if (0)
1175					/* FALLTHROUGH */
1176			case '\f':
1177				  c = 'f';
1178				if (0)
1179					/* FALLTHROUGH */
1180			case '\n':
1181				  c = 'n';
1182				if (0)
1183					/* FALLTHROUGH */
1184			case '\r':
1185				  c = 'r';
1186				if (0)
1187					/* FALLTHROUGH */
1188			case '\t':
1189				  c = 't';
1190				if (0)
1191					/* FALLTHROUGH */
1192			case 11:
1193				  c = 'v';
1194				if (0)
1195					/* FALLTHROUGH */
1196			case '\033':
1197				/* take E not e because \e is \ in *roff */
1198				  c = 'E';
1199				/* FALLTHROUGH */
1200			case '\\':
1201				shf_putc('\\', shf);
1202
1203				if (0)
1204					/* FALLTHROUGH */
1205			default:
1206				  if (c < 32 || c > 0x7E) {
1207					/* FALLTHROUGH */
1208			case '\'':
1209					shf_fprintf(shf, "\\%03o", c);
1210					break;
1211				}
1212
1213				shf_putc(c, shf);
1214				break;
1215			}
1216		}
1217		inquote = true;
1218	}
1219	if (inquote)
1220		shf_putc('\'', shf);
1221}
1222
1223/*
1224 * Print things in columns and rows - func() is called to format
1225 * the i-th element
1226 */
1227void
1228print_columns(struct shf *shf, unsigned int n,
1229    void (*func)(char *, size_t, unsigned int, const void *),
1230    const void *arg, size_t max_oct, size_t max_colz, bool prefcol)
1231{
1232	unsigned int i, r, c, rows, cols, nspace, max_col;
1233	char *str;
1234
1235	if (!n)
1236		return;
1237
1238	if (max_colz > 2147483646) {
1239#ifndef MKSH_SMALL
1240		internal_warningf("print_columns called with %s=%zu >= INT_MAX",
1241		    "max_col", max_colz);
1242#endif
1243		return;
1244	}
1245	max_col = (unsigned int)max_colz;
1246
1247	if (max_oct > 2147483646) {
1248#ifndef MKSH_SMALL
1249		internal_warningf("print_columns called with %s=%zu >= INT_MAX",
1250		    "max_oct", max_oct);
1251#endif
1252		return;
1253	}
1254	++max_oct;
1255	str = alloc(max_oct, ATEMP);
1256
1257	/*
1258	 * We use (max_col + 2) to consider the separator space.
1259	 * Note that no spaces are printed after the last column
1260	 * to avoid problems with terminals that have auto-wrap,
1261	 * but we need to also take this into account in x_cols.
1262	 */
1263	cols = (x_cols + 1) / (max_col + 2);
1264
1265	/* if we can only print one column anyway, skip the goo */
1266	if (cols < 2) {
1267		for (i = 0; i < n; ++i) {
1268			(*func)(str, max_oct, i, arg);
1269			shf_puts(str, shf);
1270			shf_putc('\n', shf);
1271		}
1272		goto out;
1273	}
1274
1275	rows = (n + cols - 1) / cols;
1276	if (prefcol && cols > rows) {
1277		cols = rows;
1278		rows = (n + cols - 1) / cols;
1279	}
1280
1281	nspace = (x_cols - max_col * cols) / cols;
1282	if (nspace < 2)
1283		nspace = 2;
1284	max_col = -max_col;
1285	for (r = 0; r < rows; r++) {
1286		for (c = 0; c < cols; c++) {
1287			if ((i = c * rows + r) >= n)
1288				break;
1289			(*func)(str, max_oct, i, arg);
1290			if (i + rows >= n)
1291				shf_puts(str, shf);
1292			else
1293				shf_fprintf(shf, "%*s%*s",
1294				    max_col, str, nspace, null);
1295		}
1296		shf_putchar('\n', shf);
1297	}
1298 out:
1299	afree(str, ATEMP);
1300}
1301
1302/* strip all NUL bytes from buf; output is NUL-terminated if stripped */
1303void
1304strip_nuls(char *buf, size_t len)
1305{
1306	char *cp, *dp, *ep;
1307
1308	if (!len || !(dp = memchr(buf, '\0', len)))
1309		return;
1310
1311	ep = buf + len;
1312	cp = dp;
1313
1314 cp_has_nul_byte:
1315	while (cp++ < ep && *cp == '\0')
1316		;	/* nothing */
1317	while (cp < ep && *cp != '\0')
1318		*dp++ = *cp++;
1319	if (cp < ep)
1320		goto cp_has_nul_byte;
1321
1322	*dp = '\0';
1323}
1324
1325/*
1326 * Like read(2), but if read fails due to non-blocking flag,
1327 * resets flag and restarts read.
1328 */
1329ssize_t
1330blocking_read(int fd, char *buf, size_t nbytes)
1331{
1332	ssize_t ret;
1333	bool tried_reset = false;
1334
1335	while ((ret = read(fd, buf, nbytes)) < 0) {
1336		if (!tried_reset && errno == EAGAIN) {
1337			if (reset_nonblock(fd) > 0) {
1338				tried_reset = true;
1339				continue;
1340			}
1341			errno = EAGAIN;
1342		}
1343		break;
1344	}
1345	return (ret);
1346}
1347
1348/*
1349 * Reset the non-blocking flag on the specified file descriptor.
1350 * Returns -1 if there was an error, 0 if non-blocking wasn't set,
1351 * 1 if it was.
1352 */
1353int
1354reset_nonblock(int fd)
1355{
1356	int flags;
1357
1358	if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1359		return (-1);
1360	if (!(flags & O_NONBLOCK))
1361		return (0);
1362	flags &= ~O_NONBLOCK;
1363	if (fcntl(fd, F_SETFL, flags) < 0)
1364		return (-1);
1365	return (1);
1366}
1367
1368/* getcwd(3) equivalent, allocates from ATEMP but doesn't resize */
1369char *
1370ksh_get_wd(void)
1371{
1372#ifdef MKSH__NO_PATH_MAX
1373	char *rv, *cp;
1374
1375	if ((cp = get_current_dir_name())) {
1376		strdupx(rv, cp, ATEMP);
1377		free_gnu_gcdn(cp);
1378	} else
1379		rv = NULL;
1380#else
1381	char *rv;
1382
1383	if (!getcwd((rv = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)) {
1384		afree(rv, ATEMP);
1385		rv = NULL;
1386	}
1387#endif
1388
1389	return (rv);
1390}
1391
1392#ifndef ELOOP
1393#define ELOOP		E2BIG
1394#endif
1395
1396char *
1397do_realpath(const char *upath)
1398{
1399	char *xp, *ip, *tp, *ipath, *ldest = NULL;
1400	XString xs;
1401	size_t pos, len;
1402	int llen;
1403	struct stat sb;
1404#ifdef MKSH__NO_PATH_MAX
1405	size_t ldestlen = 0;
1406#define pathlen sb.st_size
1407#define pathcnd (ldestlen < (pathlen + 1))
1408#else
1409#define pathlen PATH_MAX
1410#define pathcnd (!ldest)
1411#endif
1412	/* max. recursion depth */
1413	int symlinks = 32;
1414
1415	if (mksh_abspath(upath)) {
1416		/* upath is an absolute pathname */
1417		strdupx(ipath, upath, ATEMP);
1418	} else {
1419		/* upath is a relative pathname, prepend cwd */
1420		if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
1421			return (NULL);
1422		ipath = shf_smprintf("%s%s%s", tp, "/", upath);
1423		afree(tp, ATEMP);
1424	}
1425
1426	/* ipath and upath are in memory at the same time -> unchecked */
1427	Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
1428
1429	/* now jump into the deep of the loop */
1430	goto beginning_of_a_pathname;
1431
1432	while (*ip) {
1433		/* skip slashes in input */
1434		while (*ip == '/')
1435			++ip;
1436		if (!*ip)
1437			break;
1438
1439		/* get next pathname component from input */
1440		tp = ip;
1441		while (*ip && *ip != '/')
1442			++ip;
1443		len = ip - tp;
1444
1445		/* check input for "." and ".." */
1446		if (tp[0] == '.') {
1447			if (len == 1)
1448				/* just continue with the next one */
1449				continue;
1450			else if (len == 2 && tp[1] == '.') {
1451				/* strip off last pathname component */
1452				while (xp > Xstring(xs, xp))
1453					if (*--xp == '/')
1454						break;
1455				/* then continue with the next one */
1456				continue;
1457			}
1458		}
1459
1460		/* store output position away, then append slash to output */
1461		pos = Xsavepos(xs, xp);
1462		/* 1 for the '/' and len + 1 for tp and the NUL from below */
1463		XcheckN(xs, xp, 1 + len + 1);
1464		Xput(xs, xp, '/');
1465
1466		/* append next pathname component to output */
1467		memcpy(xp, tp, len);
1468		xp += len;
1469		*xp = '\0';
1470
1471		/* lstat the current output, see if it's a symlink */
1472		if (mksh_lstat(Xstring(xs, xp), &sb)) {
1473			/* lstat failed */
1474			if (errno == ENOENT) {
1475				/* because the pathname does not exist */
1476				while (*ip == '/')
1477					/* skip any trailing slashes */
1478					++ip;
1479				/* no more components left? */
1480				if (!*ip)
1481					/* we can still return successfully */
1482					break;
1483				/* more components left? fall through */
1484			}
1485			/* not ENOENT or not at the end of ipath */
1486			goto notfound;
1487		}
1488
1489		/* check if we encountered a symlink? */
1490		if (S_ISLNK(sb.st_mode)) {
1491#ifndef MKSH__NO_SYMLINK
1492			/* reached maximum recursion depth? */
1493			if (!symlinks--) {
1494				/* yep, prevent infinite loops */
1495				errno = ELOOP;
1496				goto notfound;
1497			}
1498
1499			/* get symlink(7) target */
1500			if (pathcnd) {
1501#ifdef MKSH__NO_PATH_MAX
1502				if (notoktoadd(pathlen, 1)) {
1503					errno = ENAMETOOLONG;
1504					goto notfound;
1505				}
1506#endif
1507				ldest = aresize(ldest, pathlen + 1, ATEMP);
1508			}
1509			llen = readlink(Xstring(xs, xp), ldest, pathlen);
1510			if (llen < 0)
1511				/* oops... */
1512				goto notfound;
1513			ldest[llen] = '\0';
1514
1515			/*
1516			 * restart if symlink target is an absolute path,
1517			 * otherwise continue with currently resolved prefix
1518			 */
1519			/* append rest of current input path to link target */
1520			tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
1521			afree(ipath, ATEMP);
1522			ip = ipath = tp;
1523			if (!mksh_abspath(ldest)) {
1524				/* symlink target is a relative path */
1525				xp = Xrestpos(xs, xp, pos);
1526			} else
1527#endif
1528			  {
1529				/* symlink target is an absolute path */
1530				xp = Xstring(xs, xp);
1531 beginning_of_a_pathname:
1532				/* assert: (ip == ipath)[0] == '/' */
1533				/* assert: xp == xs.beg => start of path */
1534
1535				/* exactly two leading slashes? (SUSv4 3.266) */
1536				if (ip[1] == '/' && ip[2] != '/') {
1537					/* keep them, e.g. for UNC pathnames */
1538					Xput(xs, xp, '/');
1539				}
1540			}
1541		}
1542		/* otherwise (no symlink) merely go on */
1543	}
1544
1545	/*
1546	 * either found the target and successfully resolved it,
1547	 * or found its parent directory and may create it
1548	 */
1549	if (Xlength(xs, xp) == 0)
1550		/*
1551		 * if the resolved pathname is "", make it "/",
1552		 * otherwise do not add a trailing slash
1553		 */
1554		Xput(xs, xp, '/');
1555	Xput(xs, xp, '\0');
1556
1557	/*
1558	 * if source path had a trailing slash, check if target path
1559	 * is not a non-directory existing file
1560	 */
1561	if (ip > ipath && ip[-1] == '/') {
1562		if (stat(Xstring(xs, xp), &sb)) {
1563			if (errno != ENOENT)
1564				goto notfound;
1565		} else if (!S_ISDIR(sb.st_mode)) {
1566			errno = ENOTDIR;
1567			goto notfound;
1568		}
1569		/* target now either does not exist or is a directory */
1570	}
1571
1572	/* return target path */
1573	afree(ldest, ATEMP);
1574	afree(ipath, ATEMP);
1575	return (Xclose(xs, xp));
1576
1577 notfound:
1578	/* save; freeing memory might trash it */
1579	llen = errno;
1580	afree(ldest, ATEMP);
1581	afree(ipath, ATEMP);
1582	Xfree(xs, xp);
1583	errno = llen;
1584	return (NULL);
1585
1586#undef pathlen
1587#undef pathcnd
1588}
1589
1590/**
1591 *	Makes a filename into result using the following algorithm.
1592 *	- make result NULL
1593 *	- if file starts with '/', append file to result & set cdpathp to NULL
1594 *	- if file starts with ./ or ../ append cwd and file to result
1595 *	  and set cdpathp to NULL
1596 *	- if the first element of cdpathp doesnt start with a '/' xx or '.' xx
1597 *	  then cwd is appended to result.
1598 *	- the first element of cdpathp is appended to result
1599 *	- file is appended to result
1600 *	- cdpathp is set to the start of the next element in cdpathp (or NULL
1601 *	  if there are no more elements.
1602 *	The return value indicates whether a non-null element from cdpathp
1603 *	was appended to result.
1604 */
1605static int
1606make_path(const char *cwd, const char *file,
1607    /* pointer to colon-separated list */
1608    char **cdpathp,
1609    XString *xsp,
1610    int *phys_pathp)
1611{
1612	int rval = 0;
1613	bool use_cdpath = true;
1614	char *plist;
1615	size_t len, plen = 0;
1616	char *xp = Xstring(*xsp, xp);
1617
1618	if (!file)
1619		file = null;
1620
1621	if (mksh_abspath(file)) {
1622		*phys_pathp = 0;
1623		use_cdpath = false;
1624	} else {
1625		if (file[0] == '.') {
1626			char c = file[1];
1627
1628			if (c == '.')
1629				c = file[2];
1630			if (c == '/' || c == '\0')
1631				use_cdpath = false;
1632		}
1633
1634		plist = *cdpathp;
1635		if (!plist)
1636			use_cdpath = false;
1637		else if (use_cdpath) {
1638			char *pend = plist;
1639
1640			while (*pend && *pend != MKSH_PATHSEPC)
1641				++pend;
1642			plen = pend - plist;
1643			*cdpathp = *pend ? pend + 1 : NULL;
1644		}
1645
1646		if ((!use_cdpath || !plen || !mksh_abspath(plist)) &&
1647		    (cwd && *cwd)) {
1648			len = strlen(cwd);
1649			XcheckN(*xsp, xp, len);
1650			memcpy(xp, cwd, len);
1651			xp += len;
1652			if (cwd[len - 1] != '/')
1653				Xput(*xsp, xp, '/');
1654		}
1655		*phys_pathp = Xlength(*xsp, xp);
1656		if (use_cdpath && plen) {
1657			XcheckN(*xsp, xp, plen);
1658			memcpy(xp, plist, plen);
1659			xp += plen;
1660			if (plist[plen - 1] != '/')
1661				Xput(*xsp, xp, '/');
1662			rval = 1;
1663		}
1664	}
1665
1666	len = strlen(file) + 1;
1667	XcheckN(*xsp, xp, len);
1668	memcpy(xp, file, len);
1669
1670	if (!use_cdpath)
1671		*cdpathp = NULL;
1672
1673	return (rval);
1674}
1675
1676/*-
1677 * Simplify pathnames containing "." and ".." entries.
1678 *
1679 * simplify_path(this)			= that
1680 * /a/b/c/./../d/..			/a/b
1681 * //./C/foo/bar/../baz			//C/foo/baz
1682 * /foo/				/foo
1683 * /foo/../../bar			/bar
1684 * /foo/./blah/..			/foo
1685 * .					.
1686 * ..					..
1687 * ./foo				foo
1688 * foo/../../../bar			../../bar
1689 */
1690void
1691simplify_path(char *p)
1692{
1693	char *dp, *ip, *sp, *tp;
1694	size_t len;
1695	bool needslash;
1696
1697	switch (*p) {
1698	case 0:
1699		return;
1700	case '/':
1701		/* exactly two leading slashes? (SUSv4 3.266) */
1702		if (p[1] == '/' && p[2] != '/')
1703			/* keep them, e.g. for UNC pathnames */
1704			++p;
1705		needslash = true;
1706		break;
1707	default:
1708		needslash = false;
1709	}
1710	dp = ip = sp = p;
1711
1712	while (*ip) {
1713		/* skip slashes in input */
1714		while (*ip == '/')
1715			++ip;
1716		if (!*ip)
1717			break;
1718
1719		/* get next pathname component from input */
1720		tp = ip;
1721		while (*ip && *ip != '/')
1722			++ip;
1723		len = ip - tp;
1724
1725		/* check input for "." and ".." */
1726		if (tp[0] == '.') {
1727			if (len == 1)
1728				/* just continue with the next one */
1729				continue;
1730			else if (len == 2 && tp[1] == '.') {
1731				/* parent level, but how? */
1732				if (mksh_abspath(p))
1733					/* absolute path, only one way */
1734					goto strip_last_component;
1735				else if (dp > sp) {
1736					/* relative path, with subpaths */
1737					needslash = false;
1738 strip_last_component:
1739					/* strip off last pathname component */
1740					while (dp > sp)
1741						if (*--dp == '/')
1742							break;
1743				} else {
1744					/* relative path, at its beginning */
1745					if (needslash)
1746						/* or already dotdot-slash'd */
1747						*dp++ = '/';
1748					/* keep dotdot-slash if not absolute */
1749					*dp++ = '.';
1750					*dp++ = '.';
1751					needslash = true;
1752					sp = dp;
1753				}
1754				/* then continue with the next one */
1755				continue;
1756			}
1757		}
1758
1759		if (needslash)
1760			*dp++ = '/';
1761
1762		/* append next pathname component to output */
1763		memmove(dp, tp, len);
1764		dp += len;
1765
1766		/* append slash if we continue */
1767		needslash = true;
1768		/* try next component */
1769	}
1770	if (dp == p)
1771		/* empty path -> dot */
1772		*dp++ = needslash ? '/' : '.';
1773	*dp = '\0';
1774}
1775
1776void
1777set_current_wd(const char *nwd)
1778{
1779	char *allocd = NULL;
1780
1781	if (nwd == NULL) {
1782		allocd = ksh_get_wd();
1783		nwd = allocd ? allocd : null;
1784	}
1785
1786	afree(current_wd, APERM);
1787	strdupx(current_wd, nwd, APERM);
1788
1789	afree(allocd, ATEMP);
1790}
1791
1792int
1793c_cd(const char **wp)
1794{
1795	int optc, rv, phys_path;
1796	bool physical = tobool(Flag(FPHYSICAL));
1797	/* was a node from cdpath added in? */
1798	int cdnode;
1799	/* show where we went?, error for $PWD */
1800	bool printpath = false, eflag = false;
1801	struct tbl *pwd_s, *oldpwd_s;
1802	XString xs;
1803	char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
1804
1805	while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1)
1806		switch (optc) {
1807		case 'e':
1808			eflag = true;
1809			break;
1810		case 'L':
1811			physical = false;
1812			break;
1813		case 'P':
1814			physical = true;
1815			break;
1816		case '?':
1817			return (2);
1818		}
1819	wp += builtin_opt.optind;
1820
1821	if (Flag(FRESTRICTED)) {
1822		bi_errorf("restricted shell - can't cd");
1823		return (2);
1824	}
1825
1826	pwd_s = global("PWD");
1827	oldpwd_s = global("OLDPWD");
1828
1829	if (!wp[0]) {
1830		/* No arguments - go home */
1831		if ((dir = str_val(global("HOME"))) == null) {
1832			bi_errorf("no home directory (HOME not set)");
1833			return (2);
1834		}
1835	} else if (!wp[1]) {
1836		/* One argument: - or dir */
1837		strdupx(allocd, wp[0], ATEMP);
1838		if (ksh_isdash((dir = allocd))) {
1839			afree(allocd, ATEMP);
1840			allocd = NULL;
1841			dir = str_val(oldpwd_s);
1842			if (dir == null) {
1843				bi_errorf("no OLDPWD");
1844				return (2);
1845			}
1846			printpath = true;
1847		}
1848	} else if (!wp[2]) {
1849		/* Two arguments - substitute arg1 in PWD for arg2 */
1850		size_t ilen, olen, nlen, elen;
1851		char *cp;
1852
1853		if (!current_wd[0]) {
1854			bi_errorf("can't determine current directory");
1855			return (2);
1856		}
1857		/*
1858		 * substitute arg1 for arg2 in current path.
1859		 * if the first substitution fails because the cd fails
1860		 * we could try to find another substitution. For now
1861		 * we don't
1862		 */
1863		if ((cp = strstr(current_wd, wp[0])) == NULL) {
1864			bi_errorf("bad substitution");
1865			return (2);
1866		}
1867		/*-
1868		 * ilen = part of current_wd before wp[0]
1869		 * elen = part of current_wd after wp[0]
1870		 * because current_wd and wp[1] need to be in memory at the
1871		 * same time beforehand the addition can stay unchecked
1872		 */
1873		ilen = cp - current_wd;
1874		olen = strlen(wp[0]);
1875		nlen = strlen(wp[1]);
1876		elen = strlen(current_wd + ilen + olen) + 1;
1877		dir = allocd = alloc(ilen + nlen + elen, ATEMP);
1878		memcpy(dir, current_wd, ilen);
1879		memcpy(dir + ilen, wp[1], nlen);
1880		memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
1881		printpath = true;
1882	} else {
1883		bi_errorf("too many arguments");
1884		return (2);
1885	}
1886
1887#ifdef MKSH__NO_PATH_MAX
1888	/* only a first guess; make_path will enlarge xs if necessary */
1889	XinitN(xs, 1024, ATEMP);
1890#else
1891	XinitN(xs, PATH_MAX, ATEMP);
1892#endif
1893
1894	cdpath = str_val(global("CDPATH"));
1895	do {
1896		cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
1897		if (physical)
1898			rv = chdir(tryp = Xstring(xs, xp) + phys_path);
1899		else {
1900			simplify_path(Xstring(xs, xp));
1901			rv = chdir(tryp = Xstring(xs, xp));
1902		}
1903	} while (rv < 0 && cdpath != NULL);
1904
1905	if (rv < 0) {
1906		if (cdnode)
1907			bi_errorf("%s: %s", dir, "bad directory");
1908		else
1909			bi_errorf("%s: %s", tryp, cstrerror(errno));
1910		afree(allocd, ATEMP);
1911		Xfree(xs, xp);
1912		return (2);
1913	}
1914
1915	rv = 0;
1916
1917	/* allocd (above) => dir, which is no longer used */
1918	afree(allocd, ATEMP);
1919	allocd = NULL;
1920
1921	/* Clear out tracked aliases with relative paths */
1922	flushcom(false);
1923
1924	/*
1925	 * Set OLDPWD (note: unsetting OLDPWD does not disable this
1926	 * setting in AT&T ksh)
1927	 */
1928	if (current_wd[0])
1929		/* Ignore failure (happens if readonly or integer) */
1930		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
1931
1932	if (!mksh_abspath(Xstring(xs, xp))) {
1933		pwd = NULL;
1934	} else if (!physical) {
1935		goto norealpath_PWD;
1936	} else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) {
1937		if (eflag)
1938			rv = 1;
1939 norealpath_PWD:
1940		pwd = Xstring(xs, xp);
1941	}
1942
1943	/* Set PWD */
1944	if (pwd) {
1945		char *ptmp = pwd;
1946
1947		set_current_wd(ptmp);
1948		/* Ignore failure (happens if readonly or integer) */
1949		setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
1950	} else {
1951		set_current_wd(null);
1952		pwd = Xstring(xs, xp);
1953		/* XXX unset $PWD? */
1954		if (eflag)
1955			rv = 1;
1956	}
1957	if (printpath || cdnode)
1958		shprintf("%s\n", pwd);
1959
1960	afree(allocd, ATEMP);
1961	Xfree(xs, xp);
1962	return (rv);
1963}
1964
1965
1966#ifdef KSH_CHVT_CODE
1967extern void chvt_reinit(void);
1968
1969static void
1970chvt(const Getopt *go)
1971{
1972	const char *dv = go->optarg;
1973	char *cp = NULL;
1974	int fd;
1975
1976	switch (*dv) {
1977	case '-':
1978		dv = "/dev/null";
1979		break;
1980	case '!':
1981		++dv;
1982		/* FALLTHROUGH */
1983	default: {
1984		struct stat sb;
1985
1986		if (stat(dv, &sb)) {
1987			cp = shf_smprintf("/dev/ttyC%s", dv);
1988			dv = cp;
1989			if (stat(dv, &sb)) {
1990				memmove(cp + 1, cp, /* /dev/tty */ 8);
1991				dv = cp + 1;
1992				if (stat(dv, &sb)) {
1993					errorf("%s: %s: %s", "chvt",
1994					    "can't find tty", go->optarg);
1995				}
1996			}
1997		}
1998		if (!(sb.st_mode & S_IFCHR))
1999			errorf("%s: %s: %s", "chvt", "not a char device", dv);
2000#ifndef MKSH_DISABLE_REVOKE_WARNING
2001#if HAVE_REVOKE
2002		if (revoke(dv))
2003#endif
2004			warningf(false, "%s: %s %s", "chvt",
2005			    "new shell is potentially insecure, can't revoke",
2006			    dv);
2007#endif
2008	    }
2009	}
2010	if ((fd = binopen2(dv, O_RDWR)) < 0) {
2011		sleep(1);
2012		if ((fd = binopen2(dv, O_RDWR)) < 0) {
2013			errorf("%s: %s %s", "chvt", "can't open", dv);
2014		}
2015	}
2016	if (go->optarg[0] != '!') {
2017		switch (fork()) {
2018		case -1:
2019			errorf("%s: %s %s", "chvt", "fork", "failed");
2020		case 0:
2021			break;
2022		default:
2023			exit(0);
2024		}
2025	}
2026	if (setsid() == -1)
2027		errorf("%s: %s %s", "chvt", "setsid", "failed");
2028	if (go->optarg[0] != '-') {
2029		if (ioctl(fd, TIOCSCTTY, NULL) == -1)
2030			errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
2031		if (tcflush(fd, TCIOFLUSH))
2032			errorf("%s: %s %s", "chvt", "TCIOFLUSH", "failed");
2033	}
2034	ksh_dup2(fd, 0, false);
2035	ksh_dup2(fd, 1, false);
2036	ksh_dup2(fd, 2, false);
2037	if (fd > 2)
2038		close(fd);
2039	rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt)));
2040	chvt_reinit();
2041}
2042#endif
2043
2044#ifdef DEBUG
2045char *
2046strchr(char *p, int ch)
2047{
2048	for (;; ++p) {
2049		if (*p == ch)
2050			return (p);
2051		if (!*p)
2052			return (NULL);
2053	}
2054	/* NOTREACHED */
2055}
2056
2057char *
2058strstr(char *b, const char *l)
2059{
2060	char first, c;
2061	size_t n;
2062
2063	if ((first = *l++) == '\0')
2064		return (b);
2065	n = strlen(l);
2066 strstr_look:
2067	while ((c = *b++) != first)
2068		if (c == '\0')
2069			return (NULL);
2070	if (strncmp(b, l, n))
2071		goto strstr_look;
2072	return (b - 1);
2073}
2074#endif
2075
2076#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
2077char *
2078strndup_i(const char *src, size_t len, Area *ap)
2079{
2080	char *dst = NULL;
2081
2082	if (src != NULL) {
2083		dst = alloc(len + 1, ap);
2084		memcpy(dst, src, len);
2085		dst[len] = '\0';
2086	}
2087	return (dst);
2088}
2089
2090char *
2091strdup_i(const char *src, Area *ap)
2092{
2093	return (src == NULL ? NULL : strndup_i(src, strlen(src), ap));
2094}
2095#endif
2096
2097#if !HAVE_GETRUSAGE
2098#define INVTCK(r,t)	do {						\
2099	r.tv_usec = ((t) % (1000000 / CLK_TCK)) * (1000000 / CLK_TCK);	\
2100	r.tv_sec = (t) / CLK_TCK;					\
2101} while (/* CONSTCOND */ 0)
2102
2103int
2104getrusage(int what, struct rusage *ru)
2105{
2106	struct tms tms;
2107	clock_t u, s;
2108
2109	if (/* ru == NULL || */ times(&tms) == (clock_t)-1)
2110		return (-1);
2111
2112	switch (what) {
2113	case RUSAGE_SELF:
2114		u = tms.tms_utime;
2115		s = tms.tms_stime;
2116		break;
2117	case RUSAGE_CHILDREN:
2118		u = tms.tms_cutime;
2119		s = tms.tms_cstime;
2120		break;
2121	default:
2122		errno = EINVAL;
2123		return (-1);
2124	}
2125	INVTCK(ru->ru_utime, u);
2126	INVTCK(ru->ru_stime, s);
2127	return (0);
2128}
2129#endif
2130
2131/*
2132 * process the string available via fg (get a char)
2133 * and fp (put back a char) for backslash escapes,
2134 * assuming the first call to *fg gets the char di-
2135 * rectly after the backslash; return the character
2136 * (0..0xFF), Unicode (wc + 0x100), or -1 if no known
2137 * escape sequence was found
2138 */
2139int
2140unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
2141{
2142	int wc, i, c, fc;
2143
2144	fc = (*fg)();
2145	switch (fc) {
2146	case 'a':
2147		/*
2148		 * according to the comments in pdksh, \007 seems
2149		 * to be more portable than \a (due to HP-UX cc,
2150		 * Ultrix cc, old pcc, etc.) so we avoid the escape
2151		 * sequence altogether in mksh and assume ASCII
2152		 */
2153		wc = 7;
2154		break;
2155	case 'b':
2156		wc = '\b';
2157		break;
2158	case 'c':
2159		if (!cstyle)
2160			goto unknown_escape;
2161		c = (*fg)();
2162		wc = CTRL(c);
2163		break;
2164	case 'E':
2165	case 'e':
2166		wc = 033;
2167		break;
2168	case 'f':
2169		wc = '\f';
2170		break;
2171	case 'n':
2172		wc = '\n';
2173		break;
2174	case 'r':
2175		wc = '\r';
2176		break;
2177	case 't':
2178		wc = '\t';
2179		break;
2180	case 'v':
2181		/* assume ASCII here as well */
2182		wc = 11;
2183		break;
2184	case '1':
2185	case '2':
2186	case '3':
2187	case '4':
2188	case '5':
2189	case '6':
2190	case '7':
2191		if (!cstyle)
2192			goto unknown_escape;
2193		/* FALLTHROUGH */
2194	case '0':
2195		if (cstyle)
2196			(*fp)(fc);
2197		/*
2198		 * look for an octal number with up to three
2199		 * digits, not counting the leading zero;
2200		 * convert it to a raw octet
2201		 */
2202		wc = 0;
2203		i = 3;
2204		while (i--)
2205			if ((c = (*fg)()) >= ord('0') && c <= ord('7'))
2206				wc = (wc << 3) + ksh_numdig(c);
2207			else {
2208				(*fp)(c);
2209				break;
2210			}
2211		break;
2212	case 'U':
2213		i = 8;
2214		if (/* CONSTCOND */ 0)
2215			/* FALLTHROUGH */
2216	case 'u':
2217		  i = 4;
2218		if (/* CONSTCOND */ 0)
2219			/* FALLTHROUGH */
2220	case 'x':
2221		  i = cstyle ? -1 : 2;
2222		/**
2223		 * x:	look for a hexadecimal number with up to
2224		 *	two (C style: arbitrary) digits; convert
2225		 *	to raw octet (C style: Unicode if >0xFF)
2226		 * u/U:	look for a hexadecimal number with up to
2227		 *	four (U: eight) digits; convert to Unicode
2228		 */
2229		wc = 0;
2230		while (i--) {
2231			wc <<= 4;
2232			if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
2233				wc += ksh_numdig(c);
2234			else if (c >= ord('A') && c <= ord('F'))
2235				wc += ksh_numuc(c) + 10;
2236			else if (c >= ord('a') && c <= ord('f'))
2237				wc += ksh_numlc(c) + 10;
2238			else {
2239				wc >>= 4;
2240				(*fp)(c);
2241				break;
2242			}
2243		}
2244		if ((cstyle && wc > 0xFF) || fc != 'x')
2245			/* Unicode marker */
2246			wc += 0x100;
2247		break;
2248	case '\'':
2249		if (!cstyle)
2250			goto unknown_escape;
2251		wc = '\'';
2252		break;
2253	case '\\':
2254		wc = '\\';
2255		break;
2256	default:
2257 unknown_escape:
2258		(*fp)(fc);
2259		return (-1);
2260	}
2261
2262	return (wc);
2263}
2264