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 (at) mirbsd.org> 8 * 9 * Provided that these terms and disclaimer and all copyright notices 10 * are retained or reproduced in an accompanying document, permission 11 * is granted to deal in this work without restriction, including un- 12 * limited rights to use, publicly perform, distribute, sell, modify, 13 * merge, give away, or sublicence. 14 * 15 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 16 * the utmost extent permitted by applicable law, neither express nor 17 * implied; without malicious intent or gross negligence. In no event 18 * may a licensor, author or contributor be held liable for indirect, 19 * direct, other damage, loss, or other issues arising in any way out 20 * of dealing in the work, even if advised of the possibility of such 21 * damage or existence of a defect, except proven that it results out 22 * of said person's immediate fault when using the work as intended. 23 */ 24 25 #include "sh.h" 26 #if !HAVE_GETRUSAGE 27 #include <sys/times.h> 28 #endif 29 #if HAVE_GRP_H 30 #include <grp.h> 31 #endif 32 33 __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.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 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 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 * 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 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 * 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 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 * 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 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 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 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 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 * 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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