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