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