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