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