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