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