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