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