1 /* $OpenBSD: c_ksh.c,v 1.62 2019/06/28 13:34:59 deraadt Exp $ */ 2 3 /* 4 * built-in Korn commands: c_* 5 */ 6 7 #include <sys/stat.h> 8 9 #include <ctype.h> 10 #include <errno.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include "sh.h" 15 16 int 17 c_cd(char **wp) 18 { 19 int optc; 20 int physical = Flag(FPHYSICAL); 21 int cdnode; /* was a node from cdpath added in? */ 22 int printpath = 0; /* print where we cd'd? */ 23 int rval; 24 struct tbl *pwd_s, *oldpwd_s; 25 XString xs; 26 char *xp; 27 char *dir, *try, *pwd; 28 int phys_path; 29 char *cdpath; 30 char *fdir = NULL; 31 32 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) 33 switch (optc) { 34 case 'L': 35 physical = 0; 36 break; 37 case 'P': 38 physical = 1; 39 break; 40 case '?': 41 return 1; 42 } 43 wp += builtin_opt.optind; 44 45 if (Flag(FRESTRICTED)) { 46 bi_errorf("restricted shell - can't cd"); 47 return 1; 48 } 49 50 pwd_s = global("PWD"); 51 oldpwd_s = global("OLDPWD"); 52 53 if (!wp[0]) { 54 /* No arguments - go home */ 55 if ((dir = str_val(global("HOME"))) == null) { 56 bi_errorf("no home directory (HOME not set)"); 57 return 1; 58 } 59 } else if (!wp[1]) { 60 /* One argument: - or dir */ 61 dir = wp[0]; 62 if (strcmp(dir, "-") == 0) { 63 dir = str_val(oldpwd_s); 64 if (dir == null) { 65 bi_errorf("no OLDPWD"); 66 return 1; 67 } 68 printpath++; 69 } 70 } else if (!wp[2]) { 71 /* Two arguments - substitute arg1 in PWD for arg2 */ 72 int ilen, olen, nlen, elen; 73 char *cp; 74 75 if (!current_wd[0]) { 76 bi_errorf("don't know current directory"); 77 return 1; 78 } 79 /* substitute arg1 for arg2 in current path. 80 * if the first substitution fails because the cd fails 81 * we could try to find another substitution. For now 82 * we don't 83 */ 84 if ((cp = strstr(current_wd, wp[0])) == NULL) { 85 bi_errorf("bad substitution"); 86 return 1; 87 } 88 ilen = cp - current_wd; 89 olen = strlen(wp[0]); 90 nlen = strlen(wp[1]); 91 elen = strlen(current_wd + ilen + olen) + 1; 92 fdir = dir = alloc(ilen + nlen + elen, ATEMP); 93 memcpy(dir, current_wd, ilen); 94 memcpy(dir + ilen, wp[1], nlen); 95 memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); 96 printpath++; 97 } else { 98 bi_errorf("too many arguments"); 99 return 1; 100 } 101 102 Xinit(xs, xp, PATH_MAX, ATEMP); 103 /* xp will have a bogus value after make_path() - set it to 0 104 * so that if it's used, it will cause a dump 105 */ 106 xp = NULL; 107 108 cdpath = str_val(global("CDPATH")); 109 do { 110 cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); 111 if (physical) 112 rval = chdir(try = Xstring(xs, xp) + phys_path); 113 else { 114 simplify_path(Xstring(xs, xp)); 115 rval = chdir(try = Xstring(xs, xp)); 116 } 117 } while (rval == -1 && cdpath != NULL); 118 119 if (rval == -1) { 120 if (cdnode) 121 bi_errorf("%s: bad directory", dir); 122 else 123 bi_errorf("%s - %s", try, strerror(errno)); 124 afree(fdir, ATEMP); 125 return 1; 126 } 127 128 /* Clear out tracked aliases with relative paths */ 129 flushcom(0); 130 131 /* Set OLDPWD (note: unsetting OLDPWD does not disable this 132 * setting in at&t ksh) 133 */ 134 if (current_wd[0]) 135 /* Ignore failure (happens if readonly or integer) */ 136 setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); 137 138 if (Xstring(xs, xp)[0] != '/') { 139 pwd = NULL; 140 } else 141 if (!physical || !(pwd = get_phys_path(Xstring(xs, xp)))) 142 pwd = Xstring(xs, xp); 143 144 /* Set PWD */ 145 if (pwd) { 146 char *ptmp = pwd; 147 set_current_wd(ptmp); 148 /* Ignore failure (happens if readonly or integer) */ 149 setstr(pwd_s, ptmp, KSH_RETURN_ERROR); 150 } else { 151 set_current_wd(null); 152 pwd = Xstring(xs, xp); 153 /* XXX unset $PWD? */ 154 } 155 if (printpath || cdnode) 156 shprintf("%s\n", pwd); 157 158 afree(fdir, ATEMP); 159 160 return 0; 161 } 162 163 int 164 c_pwd(char **wp) 165 { 166 int optc; 167 int physical = Flag(FPHYSICAL); 168 char *p, *freep = NULL; 169 170 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) 171 switch (optc) { 172 case 'L': 173 physical = 0; 174 break; 175 case 'P': 176 physical = 1; 177 break; 178 case '?': 179 return 1; 180 } 181 wp += builtin_opt.optind; 182 183 if (wp[0]) { 184 bi_errorf("too many arguments"); 185 return 1; 186 } 187 p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) : 188 NULL; 189 if (p && access(p, R_OK) == -1) 190 p = NULL; 191 if (!p) { 192 freep = p = ksh_get_wd(NULL, 0); 193 if (!p) { 194 bi_errorf("can't get current directory - %s", 195 strerror(errno)); 196 return 1; 197 } 198 } 199 shprintf("%s\n", p); 200 afree(freep, ATEMP); 201 return 0; 202 } 203 204 int 205 c_print(char **wp) 206 { 207 #define PO_NL BIT(0) /* print newline */ 208 #define PO_EXPAND BIT(1) /* expand backslash sequences */ 209 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */ 210 #define PO_HIST BIT(3) /* print to history instead of stdout */ 211 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ 212 int fd = 1; 213 int flags = PO_EXPAND|PO_NL; 214 char *s; 215 const char *emsg; 216 XString xs; 217 char *xp; 218 219 if (wp[0][0] == 'e') { /* echo command */ 220 int nflags = flags; 221 222 /* A compromise between sysV and BSD echo commands: 223 * escape sequences are enabled by default, and 224 * -n, -e and -E are recognized if they appear 225 * in arguments with no illegal options (ie, echo -nq 226 * will print -nq). 227 * Different from sysV echo since options are recognized, 228 * different from BSD echo since escape sequences are enabled 229 * by default. 230 */ 231 wp += 1; 232 if (Flag(FPOSIX)) { 233 if (*wp && strcmp(*wp, "-n") == 0) { 234 flags &= ~PO_NL; 235 wp++; 236 } 237 } else { 238 while ((s = *wp) && *s == '-' && s[1]) { 239 while (*++s) 240 if (*s == 'n') 241 nflags &= ~PO_NL; 242 else if (*s == 'e') 243 nflags |= PO_EXPAND; 244 else if (*s == 'E') 245 nflags &= ~PO_EXPAND; 246 else 247 /* bad option: don't use 248 * nflags, print argument 249 */ 250 break; 251 if (*s) 252 break; 253 wp++; 254 flags = nflags; 255 } 256 } 257 } else { 258 int optc; 259 const char *options = "Rnprsu,"; 260 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) 261 switch (optc) { 262 case 'R': /* fake BSD echo command */ 263 flags |= PO_PMINUSMINUS; 264 flags &= ~PO_EXPAND; 265 options = "ne"; 266 break; 267 case 'e': 268 flags |= PO_EXPAND; 269 break; 270 case 'n': 271 flags &= ~PO_NL; 272 break; 273 case 'p': 274 if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { 275 bi_errorf("-p: %s", emsg); 276 return 1; 277 } 278 break; 279 case 'r': 280 flags &= ~PO_EXPAND; 281 break; 282 case 's': 283 flags |= PO_HIST; 284 break; 285 case 'u': 286 if (!*(s = builtin_opt.optarg)) 287 fd = 0; 288 else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { 289 bi_errorf("-u: %s: %s", s, emsg); 290 return 1; 291 } 292 break; 293 case '?': 294 return 1; 295 } 296 if (!(builtin_opt.info & GI_MINUSMINUS)) { 297 /* treat a lone - like -- */ 298 if (wp[builtin_opt.optind] && 299 strcmp(wp[builtin_opt.optind], "-") == 0) 300 builtin_opt.optind++; 301 } else if (flags & PO_PMINUSMINUS) 302 builtin_opt.optind--; 303 wp += builtin_opt.optind; 304 } 305 306 Xinit(xs, xp, 128, ATEMP); 307 308 while (*wp != NULL) { 309 int c; 310 s = *wp; 311 while ((c = *s++) != '\0') { 312 Xcheck(xs, xp); 313 if ((flags & PO_EXPAND) && c == '\\') { 314 int i; 315 316 switch ((c = *s++)) { 317 /* Oddly enough, \007 seems more portable than 318 * \a (due to HP-UX cc, Ultrix cc, old pcc's, 319 * etc.). 320 */ 321 case 'a': c = '\007'; break; 322 case 'b': c = '\b'; break; 323 case 'c': flags &= ~PO_NL; 324 continue; /* AT&T brain damage */ 325 case 'f': c = '\f'; break; 326 case 'n': c = '\n'; break; 327 case 'r': c = '\r'; break; 328 case 't': c = '\t'; break; 329 case 'v': c = 0x0B; break; 330 case '0': 331 /* Look for an octal number: can have 332 * three digits (not counting the 333 * leading 0). Truly burnt. 334 */ 335 c = 0; 336 for (i = 0; i < 3; i++) { 337 if (*s >= '0' && *s <= '7') 338 c = c*8 + *s++ - '0'; 339 else 340 break; 341 } 342 break; 343 case '\0': s--; c = '\\'; break; 344 case '\\': break; 345 default: 346 Xput(xs, xp, '\\'); 347 } 348 } 349 Xput(xs, xp, c); 350 } 351 if (*++wp != NULL) 352 Xput(xs, xp, ' '); 353 } 354 if (flags & PO_NL) 355 Xput(xs, xp, '\n'); 356 357 if (flags & PO_HIST) { 358 Xput(xs, xp, '\0'); 359 source->line++; 360 histsave(source->line, Xstring(xs, xp), 1); 361 Xfree(xs, xp); 362 } else { 363 int n, len = Xlength(xs, xp); 364 int opipe = 0; 365 366 /* Ensure we aren't killed by a SIGPIPE while writing to 367 * a coprocess. at&t ksh doesn't seem to do this (seems 368 * to just check that the co-process is alive, which is 369 * not enough). 370 */ 371 if (coproc.write >= 0 && coproc.write == fd) { 372 flags |= PO_COPROC; 373 opipe = block_pipe(); 374 } 375 for (s = Xstring(xs, xp); len > 0; ) { 376 n = write(fd, s, len); 377 if (n == -1) { 378 if (flags & PO_COPROC) 379 restore_pipe(opipe); 380 if (errno == EINTR) { 381 /* allow user to ^C out */ 382 intrcheck(); 383 if (flags & PO_COPROC) 384 opipe = block_pipe(); 385 continue; 386 } 387 /* This doesn't really make sense - could 388 * break scripts (print -p generates 389 * error message). 390 *if (errno == EPIPE) 391 * coproc_write_close(fd); 392 */ 393 return 1; 394 } 395 s += n; 396 len -= n; 397 } 398 if (flags & PO_COPROC) 399 restore_pipe(opipe); 400 } 401 402 return 0; 403 } 404 405 int 406 c_whence(char **wp) 407 { 408 struct tbl *tp; 409 char *id; 410 int pflag = 0, vflag = 0, Vflag = 0; 411 int ret = 0; 412 int optc; 413 int iam_whence; 414 int fcflags; 415 const char *options; 416 417 switch (wp[0][0]) { 418 case 'c': /* command */ 419 iam_whence = 0; 420 options = "pvV"; 421 break; 422 case 't': /* type */ 423 vflag = 1; 424 /* FALLTHROUGH */ 425 case 'w': /* whence */ 426 iam_whence = 1; 427 options = "pv"; 428 break; 429 default: 430 bi_errorf("builtin not handled by %s", __func__); 431 return 1; 432 } 433 434 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) 435 switch (optc) { 436 case 'p': 437 pflag = 1; 438 break; 439 case 'v': 440 vflag = 1; 441 break; 442 case 'V': 443 Vflag = 1; 444 break; 445 case '?': 446 return 1; 447 } 448 wp += builtin_opt.optind; 449 450 fcflags = FC_BI | FC_PATH | FC_FUNC; 451 if (!iam_whence) { 452 /* Note that -p on its own is dealt with in comexec() */ 453 if (pflag) 454 fcflags |= FC_DEFPATH; 455 /* Convert command options to whence options. Note that 456 * command -pV and command -pv use a different path search 457 * than whence -v or whence -pv. This should be considered 458 * a feature. 459 */ 460 vflag = Vflag; 461 } else if (pflag) 462 fcflags &= ~(FC_BI | FC_FUNC); 463 464 while ((vflag || ret == 0) && (id = *wp++) != NULL) { 465 tp = NULL; 466 if (!iam_whence || !pflag) 467 tp = ktsearch(&keywords, id, hash(id)); 468 if (!tp && (!iam_whence || !pflag)) { 469 tp = ktsearch(&aliases, id, hash(id)); 470 if (tp && !(tp->flag & ISSET)) 471 tp = NULL; 472 } 473 if (!tp) 474 tp = findcom(id, fcflags); 475 if (vflag || (tp->type != CALIAS && tp->type != CEXEC && 476 tp->type != CTALIAS)) 477 shprintf("%s", id); 478 switch (tp->type) { 479 case CKEYWD: 480 if (vflag) 481 shprintf(" is a reserved word"); 482 break; 483 case CALIAS: 484 if (vflag) 485 shprintf(" is an %salias for ", 486 (tp->flag & EXPORT) ? "exported " : ""); 487 if (!iam_whence && !vflag) 488 shprintf("alias %s=", id); 489 print_value_quoted(tp->val.s); 490 break; 491 case CFUNC: 492 if (vflag) { 493 shprintf(" is a"); 494 if (tp->flag & EXPORT) 495 shprintf("n exported"); 496 if (tp->flag & TRACE) 497 shprintf(" traced"); 498 if (!(tp->flag & ISSET)) { 499 shprintf(" undefined"); 500 if (tp->u.fpath) 501 shprintf(" (autoload from %s)", 502 tp->u.fpath); 503 } 504 shprintf(" function"); 505 } 506 break; 507 case CSHELL: 508 if (vflag) 509 shprintf(" is a%s shell builtin", 510 (tp->flag & SPEC_BI) ? " special" : ""); 511 break; 512 case CTALIAS: 513 case CEXEC: 514 if (tp->flag & ISSET) { 515 if (vflag) { 516 shprintf(" is "); 517 if (tp->type == CTALIAS) 518 shprintf("a tracked %salias for ", 519 (tp->flag & EXPORT) ? 520 "exported " : ""); 521 } 522 shprintf("%s", tp->val.s); 523 } else { 524 if (vflag) 525 shprintf(" not found"); 526 ret = 1; 527 } 528 break; 529 default: 530 shprintf("%s is *GOK*", id); 531 break; 532 } 533 if (vflag || !ret) 534 shprintf("\n"); 535 } 536 return ret; 537 } 538 539 /* Deal with command -vV - command -p dealt with in comexec() */ 540 int 541 c_command(char **wp) 542 { 543 /* Let c_whence do the work. Note that c_command() must be 544 * a distinct function from c_whence() (tested in comexec()). 545 */ 546 return c_whence(wp); 547 } 548 549 int 550 c_type(char **wp) 551 { 552 /* Let c_whence do the work. type = command -V = whence -v */ 553 return c_whence(wp); 554 } 555 556 /* typeset, export, and readonly */ 557 int 558 c_typeset(char **wp) 559 { 560 struct block *l; 561 struct tbl *vp, **p; 562 int fset = 0, fclr = 0, thing = 0, func = 0, local = 0, pflag = 0; 563 const char *options = "L#R#UZ#fi#lprtux"; /* see comment below */ 564 char *fieldstr, *basestr; 565 int field, base, optc, flag; 566 567 switch (**wp) { 568 case 'e': /* export */ 569 fset |= EXPORT; 570 options = "p"; 571 break; 572 case 'r': /* readonly */ 573 fset |= RDONLY; 574 options = "p"; 575 break; 576 case 's': /* set */ 577 /* called with 'typeset -' */ 578 break; 579 case 't': /* typeset */ 580 local = 1; 581 break; 582 } 583 584 fieldstr = basestr = NULL; 585 builtin_opt.flags |= GF_PLUSOPT; 586 /* at&t ksh seems to have 0-9 as options, which are multiplied 587 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 588 * sets right justify in a field of 12). This allows options 589 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and 590 * does not allow the number to be specified as a separate argument 591 * Here, the number must follow the RLZi option, but is optional 592 * (see the # kludge in ksh_getopt()). 593 */ 594 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) { 595 flag = 0; 596 switch (optc) { 597 case 'L': 598 flag = LJUST; 599 fieldstr = builtin_opt.optarg; 600 break; 601 case 'R': 602 flag = RJUST; 603 fieldstr = builtin_opt.optarg; 604 break; 605 case 'U': 606 /* at&t ksh uses u, but this conflicts with 607 * upper/lower case. If this option is changed, 608 * need to change the -U below as well 609 */ 610 flag = INT_U; 611 break; 612 case 'Z': 613 flag = ZEROFIL; 614 fieldstr = builtin_opt.optarg; 615 break; 616 case 'f': 617 func = 1; 618 break; 619 case 'i': 620 flag = INTEGER; 621 basestr = builtin_opt.optarg; 622 break; 623 case 'l': 624 flag = LCASEV; 625 break; 626 case 'p': 627 /* posix export/readonly -p flag. 628 * typeset -p is the same as typeset (in pdksh); 629 * here for compatibility with ksh93. 630 */ 631 pflag = 1; 632 break; 633 case 'r': 634 flag = RDONLY; 635 break; 636 case 't': 637 flag = TRACE; 638 break; 639 case 'u': 640 flag = UCASEV_AL; /* upper case / autoload */ 641 break; 642 case 'x': 643 flag = EXPORT; 644 break; 645 case '?': 646 return 1; 647 } 648 if (builtin_opt.info & GI_PLUS) { 649 fclr |= flag; 650 fset &= ~flag; 651 thing = '+'; 652 } else { 653 fset |= flag; 654 fclr &= ~flag; 655 thing = '-'; 656 } 657 } 658 659 field = 0; 660 if (fieldstr && !bi_getn(fieldstr, &field)) 661 return 1; 662 base = 0; 663 if (basestr && !bi_getn(basestr, &base)) 664 return 1; 665 666 if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && 667 (wp[builtin_opt.optind][0] == '-' || 668 wp[builtin_opt.optind][0] == '+') && 669 wp[builtin_opt.optind][1] == '\0') { 670 thing = wp[builtin_opt.optind][0]; 671 builtin_opt.optind++; 672 } 673 674 if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) { 675 bi_errorf("only -t, -u and -x options may be used with -f"); 676 return 1; 677 } 678 if (wp[builtin_opt.optind]) { 679 /* Take care of exclusions. 680 * At this point, flags in fset are cleared in fclr and vise 681 * versa. This property should be preserved. 682 */ 683 if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */ 684 fset &= ~UCASEV_AL; 685 if (fset & LJUST) /* LJUST has priority over RJUST */ 686 fset &= ~RJUST; 687 if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */ 688 fset |= RJUST; 689 fclr &= ~RJUST; 690 } 691 /* Setting these attributes clears the others, unless they 692 * are also set in this command 693 */ 694 if (fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | 695 INTEGER | INT_U | INT_L)) 696 fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | 697 LCASEV | INTEGER | INT_U | INT_L); 698 } 699 700 /* set variables and attributes */ 701 if (wp[builtin_opt.optind]) { 702 int i; 703 int rval = 0; 704 struct tbl *f; 705 706 if (local && !func) 707 fset |= LOCAL; 708 for (i = builtin_opt.optind; wp[i]; i++) { 709 if (func) { 710 f = findfunc(wp[i], hash(wp[i]), 711 (fset&UCASEV_AL) ? true : false); 712 if (!f) { 713 /* at&t ksh does ++rval: bogus */ 714 rval = 1; 715 continue; 716 } 717 if (fset | fclr) { 718 f->flag |= fset; 719 f->flag &= ~fclr; 720 } else 721 fptreef(shl_stdout, 0, 722 f->flag & FKSH ? 723 "function %s %T\n" : 724 "%s() %T\n", wp[i], f->val.t); 725 } else if (!typeset(wp[i], fset, fclr, field, base)) { 726 bi_errorf("%s: not identifier", wp[i]); 727 return 1; 728 } 729 } 730 return rval; 731 } 732 733 /* list variables and attributes */ 734 flag = fset | fclr; /* no difference at this point.. */ 735 if (func) { 736 for (l = genv->loc; l; l = l->next) { 737 for (p = ktsort(&l->funs); (vp = *p++); ) { 738 if (flag && (vp->flag & flag) == 0) 739 continue; 740 if (thing == '-') 741 fptreef(shl_stdout, 0, vp->flag & FKSH ? 742 "function %s %T\n" : "%s() %T\n", 743 vp->name, vp->val.t); 744 else 745 shprintf("%s\n", vp->name); 746 } 747 } 748 } else { 749 for (l = genv->loc; l; l = l->next) { 750 for (p = ktsort(&l->vars); (vp = *p++); ) { 751 struct tbl *tvp; 752 int any_set = 0; 753 /* 754 * See if the parameter is set (for arrays, if any 755 * element is set). 756 */ 757 for (tvp = vp; tvp; tvp = tvp->u.array) 758 if (tvp->flag & ISSET) { 759 any_set = 1; 760 break; 761 } 762 763 /* 764 * Check attributes - note that all array elements 765 * have (should have?) the same attributes, so checking 766 * the first is sufficient. 767 * 768 * Report an unset param only if the user has 769 * explicitly given it some attribute (like export); 770 * otherwise, after "echo $FOO", we would report FOO... 771 */ 772 if (!any_set && !(vp->flag & USERATTRIB)) 773 continue; 774 if (flag && (vp->flag & flag) == 0) 775 continue; 776 for (; vp; vp = vp->u.array) { 777 /* Ignore array elements that aren't 778 * set unless there are no set elements, 779 * in which case the first is reported on */ 780 if ((vp->flag&ARRAY) && any_set && 781 !(vp->flag & ISSET)) 782 continue; 783 /* no arguments */ 784 if (thing == 0 && flag == 0) { 785 /* at&t ksh prints things 786 * like export, integer, 787 * leftadj, zerofill, etc., 788 * but POSIX says must 789 * be suitable for re-entry... 790 */ 791 shprintf("typeset "); 792 if ((vp->flag&INTEGER)) 793 shprintf("-i "); 794 if ((vp->flag&EXPORT)) 795 shprintf("-x "); 796 if ((vp->flag&RDONLY)) 797 shprintf("-r "); 798 if ((vp->flag&TRACE)) 799 shprintf("-t "); 800 if ((vp->flag&LJUST)) 801 shprintf("-L%d ", vp->u2.field); 802 if ((vp->flag&RJUST)) 803 shprintf("-R%d ", vp->u2.field); 804 if ((vp->flag&ZEROFIL)) 805 shprintf("-Z "); 806 if ((vp->flag&LCASEV)) 807 shprintf("-l "); 808 if ((vp->flag&UCASEV_AL)) 809 shprintf("-u "); 810 if ((vp->flag&INT_U)) 811 shprintf("-U "); 812 shprintf("%s\n", vp->name); 813 if (vp->flag&ARRAY) 814 break; 815 } else { 816 if (pflag) 817 shprintf("%s ", 818 (flag & EXPORT) ? 819 "export" : "readonly"); 820 if ((vp->flag&ARRAY) && any_set) 821 shprintf("%s[%d]", 822 vp->name, vp->index); 823 else 824 shprintf("%s", vp->name); 825 if (thing == '-' && (vp->flag&ISSET)) { 826 char *s = str_val(vp); 827 828 shprintf("="); 829 /* at&t ksh can't have 830 * justified integers.. */ 831 if ((vp->flag & 832 (INTEGER|LJUST|RJUST)) == 833 INTEGER) 834 shprintf("%s", s); 835 else 836 print_value_quoted(s); 837 } 838 shprintf("\n"); 839 } 840 /* Only report first `element' of an array with 841 * no set elements. 842 */ 843 if (!any_set) 844 break; 845 } 846 } 847 } 848 } 849 return 0; 850 } 851 852 int 853 c_alias(char **wp) 854 { 855 struct table *t = &aliases; 856 int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0, prefix = 0; 857 int xflag = 0; 858 int optc; 859 860 builtin_opt.flags |= GF_PLUSOPT; 861 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) { 862 prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; 863 switch (optc) { 864 case 'd': 865 t = &homedirs; 866 break; 867 case 'p': 868 pflag = 1; 869 break; 870 case 'r': 871 rflag = 1; 872 break; 873 case 't': 874 t = &taliases; 875 break; 876 case 'U': 877 /* 878 * kludge for tracked alias initialization 879 * (don't do a path search, just make an entry) 880 */ 881 Uflag = 1; 882 break; 883 case 'x': 884 xflag = EXPORT; 885 break; 886 case '?': 887 return 1; 888 } 889 } 890 wp += builtin_opt.optind; 891 892 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp && 893 (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') { 894 prefix = wp[0][0]; 895 wp++; 896 } 897 898 tflag = t == &taliases; 899 900 /* "hash -r" means reset all the tracked aliases.. */ 901 if (rflag) { 902 static const char *const args[] = { 903 "unalias", "-ta", NULL 904 }; 905 906 if (!tflag || *wp) { 907 shprintf("alias: -r flag can only be used with -t" 908 " and without arguments\n"); 909 return 1; 910 } 911 ksh_getopt_reset(&builtin_opt, GF_ERROR); 912 return c_unalias((char **) args); 913 } 914 915 if (*wp == NULL) { 916 struct tbl *ap, **p; 917 918 for (p = ktsort(t); (ap = *p++) != NULL; ) 919 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { 920 if (pflag) 921 shf_puts("alias ", shl_stdout); 922 shf_puts(ap->name, shl_stdout); 923 if (prefix != '+') { 924 shf_putc('=', shl_stdout); 925 print_value_quoted(ap->val.s); 926 } 927 shprintf("\n"); 928 } 929 } 930 931 for (; *wp != NULL; wp++) { 932 char *alias = *wp; 933 char *val = strchr(alias, '='); 934 char *newval; 935 struct tbl *ap; 936 int h; 937 938 if (val) 939 alias = str_nsave(alias, val++ - alias, ATEMP); 940 h = hash(alias); 941 if (val == NULL && !tflag && !xflag) { 942 ap = ktsearch(t, alias, h); 943 if (ap != NULL && (ap->flag&ISSET)) { 944 if (pflag) 945 shf_puts("alias ", shl_stdout); 946 shf_puts(ap->name, shl_stdout); 947 if (prefix != '+') { 948 shf_putc('=', shl_stdout); 949 print_value_quoted(ap->val.s); 950 } 951 shprintf("\n"); 952 } else { 953 shprintf("%s alias not found\n", alias); 954 rv = 1; 955 } 956 continue; 957 } 958 ap = ktenter(t, alias, h); 959 ap->type = tflag ? CTALIAS : CALIAS; 960 /* Are we setting the value or just some flags? */ 961 if ((val && !tflag) || (!val && tflag && !Uflag)) { 962 if (ap->flag&ALLOC) { 963 ap->flag &= ~(ALLOC|ISSET); 964 afree(ap->val.s, APERM); 965 } 966 /* ignore values for -t (at&t ksh does this) */ 967 newval = tflag ? search(alias, search_path, X_OK, NULL) 968 : val; 969 if (newval) { 970 ap->val.s = str_save(newval, APERM); 971 ap->flag |= ALLOC|ISSET; 972 } else 973 ap->flag &= ~ISSET; 974 } 975 ap->flag |= DEFINED; 976 if (prefix == '+') 977 ap->flag &= ~xflag; 978 else 979 ap->flag |= xflag; 980 if (val) 981 afree(alias, ATEMP); 982 } 983 984 return rv; 985 } 986 987 int 988 c_unalias(char **wp) 989 { 990 struct table *t = &aliases; 991 struct tbl *ap; 992 int rv = 0, all = 0; 993 int optc; 994 995 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1) 996 switch (optc) { 997 case 'a': 998 all = 1; 999 break; 1000 case 'd': 1001 t = &homedirs; 1002 break; 1003 case 't': 1004 t = &taliases; 1005 break; 1006 case '?': 1007 return 1; 1008 } 1009 wp += builtin_opt.optind; 1010 1011 for (; *wp != NULL; wp++) { 1012 ap = ktsearch(t, *wp, hash(*wp)); 1013 if (ap == NULL) { 1014 rv = 1; /* POSIX */ 1015 continue; 1016 } 1017 if (ap->flag&ALLOC) { 1018 ap->flag &= ~(ALLOC|ISSET); 1019 afree(ap->val.s, APERM); 1020 } 1021 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1022 } 1023 1024 if (all) { 1025 struct tstate ts; 1026 1027 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) { 1028 if (ap->flag&ALLOC) { 1029 ap->flag &= ~(ALLOC|ISSET); 1030 afree(ap->val.s, APERM); 1031 } 1032 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1033 } 1034 } 1035 1036 return rv; 1037 } 1038 1039 int 1040 c_let(char **wp) 1041 { 1042 int rv = 1; 1043 int64_t val; 1044 1045 if (wp[1] == NULL) /* at&t ksh does this */ 1046 bi_errorf("no arguments"); 1047 else 1048 for (wp++; *wp; wp++) 1049 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) { 1050 rv = 2; /* distinguish error from zero result */ 1051 break; 1052 } else 1053 rv = val == 0; 1054 return rv; 1055 } 1056 1057 int 1058 c_jobs(char **wp) 1059 { 1060 int optc; 1061 int flag = 0; 1062 int nflag = 0; 1063 int rv = 0; 1064 1065 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1) 1066 switch (optc) { 1067 case 'l': 1068 flag = 1; 1069 break; 1070 case 'p': 1071 flag = 2; 1072 break; 1073 case 'n': 1074 nflag = 1; 1075 break; 1076 case 'z': /* debugging: print zombies */ 1077 nflag = -1; 1078 break; 1079 case '?': 1080 return 1; 1081 } 1082 wp += builtin_opt.optind; 1083 if (!*wp) { 1084 if (j_jobs(NULL, flag, nflag)) 1085 rv = 1; 1086 } else { 1087 for (; *wp; wp++) 1088 if (j_jobs(*wp, flag, nflag)) 1089 rv = 1; 1090 } 1091 return rv; 1092 } 1093 1094 int 1095 c_fgbg(char **wp) 1096 { 1097 int bg = strcmp(*wp, "bg") == 0; 1098 int rv = 0; 1099 1100 if (!Flag(FMONITOR)) { 1101 bi_errorf("job control not enabled"); 1102 return 1; 1103 } 1104 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1105 return 1; 1106 wp += builtin_opt.optind; 1107 if (*wp) 1108 for (; *wp; wp++) 1109 rv = j_resume(*wp, bg); 1110 else 1111 rv = j_resume("%%", bg); 1112 /* POSIX says fg shall return 0 (unless an error occurs). 1113 * at&t ksh returns the exit value of the job... 1114 */ 1115 return (bg || Flag(FPOSIX)) ? 0 : rv; 1116 } 1117 1118 struct kill_info { 1119 int num_width; 1120 int name_width; 1121 }; 1122 static char *kill_fmt_entry(void *arg, int i, char *buf, int buflen); 1123 1124 /* format a single kill item */ 1125 static char * 1126 kill_fmt_entry(void *arg, int i, char *buf, int buflen) 1127 { 1128 struct kill_info *ki = (struct kill_info *) arg; 1129 1130 i++; 1131 if (sigtraps[i].name) 1132 shf_snprintf(buf, buflen, "%*d %*s %s", 1133 ki->num_width, i, 1134 ki->name_width, sigtraps[i].name, 1135 sigtraps[i].mess); 1136 else 1137 shf_snprintf(buf, buflen, "%*d %*d %s", 1138 ki->num_width, i, 1139 ki->name_width, sigtraps[i].signal, 1140 sigtraps[i].mess); 1141 return buf; 1142 } 1143 1144 1145 int 1146 c_kill(char **wp) 1147 { 1148 Trap *t = NULL; 1149 char *p; 1150 int lflag = 0; 1151 int i, n, rv, sig; 1152 1153 /* assume old style options if -digits or -UPPERCASE */ 1154 if ((p = wp[1]) && *p == '-' && 1155 (digit(p[1]) || isupper((unsigned char)p[1]))) { 1156 if (!(t = gettrap(p + 1, true))) { 1157 bi_errorf("bad signal `%s'", p + 1); 1158 return 1; 1159 } 1160 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; 1161 } else { 1162 int optc; 1163 1164 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1) 1165 switch (optc) { 1166 case 'l': 1167 lflag = 1; 1168 break; 1169 case 's': 1170 if (!(t = gettrap(builtin_opt.optarg, true))) { 1171 bi_errorf("bad signal `%s'", 1172 builtin_opt.optarg); 1173 return 1; 1174 } 1175 break; 1176 case '?': 1177 return 1; 1178 } 1179 i = builtin_opt.optind; 1180 } 1181 if ((lflag && t) || (!wp[i] && !lflag)) { 1182 shf_fprintf(shl_out, 1183 "usage: kill [-s signame | -signum | -signame] { job | pid | pgrp } ...\n" 1184 " kill -l [exit_status ...]\n"); 1185 bi_errorf(NULL); 1186 return 1; 1187 } 1188 1189 if (lflag) { 1190 if (wp[i]) { 1191 for (; wp[i]; i++) { 1192 if (!bi_getn(wp[i], &n)) 1193 return 1; 1194 if (n > 128 && n < 128 + NSIG) 1195 n -= 128; 1196 if (n > 0 && n < NSIG && sigtraps[n].name) 1197 shprintf("%s\n", sigtraps[n].name); 1198 else 1199 shprintf("%d\n", n); 1200 } 1201 } else if (Flag(FPOSIX)) { 1202 p = null; 1203 for (i = 1; i < NSIG; i++, p = " ") 1204 if (sigtraps[i].name) 1205 shprintf("%s%s", p, sigtraps[i].name); 1206 shprintf("\n"); 1207 } else { 1208 int mess_width = 0, w; 1209 struct kill_info ki = { 1210 .num_width = 1, 1211 .name_width = 0, 1212 }; 1213 1214 for (i = NSIG; i >= 10; i /= 10) 1215 ki.num_width++; 1216 1217 for (i = 0; i < NSIG; i++) { 1218 w = sigtraps[i].name ? 1219 (int)strlen(sigtraps[i].name) : 1220 ki.num_width; 1221 if (w > ki.name_width) 1222 ki.name_width = w; 1223 w = strlen(sigtraps[i].mess); 1224 if (w > mess_width) 1225 mess_width = w; 1226 } 1227 1228 print_columns(shl_stdout, NSIG - 1, 1229 kill_fmt_entry, (void *) &ki, 1230 ki.num_width + ki.name_width + mess_width + 3, 1); 1231 } 1232 return 0; 1233 } 1234 rv = 0; 1235 sig = t ? t->signal : SIGTERM; 1236 for (; (p = wp[i]); i++) { 1237 if (*p == '%') { 1238 if (j_kill(p, sig)) 1239 rv = 1; 1240 } else if (!getn(p, &n)) { 1241 bi_errorf("%s: arguments must be jobs or process IDs", 1242 p); 1243 rv = 1; 1244 } else { 1245 /* use killpg if < -1 since -1 does special things for 1246 * some non-killpg-endowed kills 1247 */ 1248 if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) == -1) { 1249 bi_errorf("%s: %s", p, strerror(errno)); 1250 rv = 1; 1251 } 1252 } 1253 } 1254 return rv; 1255 } 1256 1257 void 1258 getopts_reset(int val) 1259 { 1260 if (val >= 1) { 1261 ksh_getopt_reset(&user_opt, 1262 GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); 1263 user_opt.optind = user_opt.uoptind = val; 1264 } 1265 } 1266 1267 int 1268 c_getopts(char **wp) 1269 { 1270 int argc; 1271 const char *options; 1272 const char *var; 1273 int optc; 1274 int ret; 1275 char buf[3]; 1276 struct tbl *vq, *voptarg; 1277 1278 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1279 return 1; 1280 wp += builtin_opt.optind; 1281 1282 options = *wp++; 1283 if (!options) { 1284 bi_errorf("missing options argument"); 1285 return 1; 1286 } 1287 1288 var = *wp++; 1289 if (!var) { 1290 bi_errorf("missing name argument"); 1291 return 1; 1292 } 1293 if (!*var || *skip_varname(var, true)) { 1294 bi_errorf("%s: is not an identifier", var); 1295 return 1; 1296 } 1297 1298 if (genv->loc->next == NULL) { 1299 internal_warningf("%s: no argv", __func__); 1300 return 1; 1301 } 1302 /* Which arguments are we parsing... */ 1303 if (*wp == NULL) 1304 wp = genv->loc->next->argv; 1305 else 1306 *--wp = genv->loc->next->argv[0]; 1307 1308 /* Check that our saved state won't cause a core dump... */ 1309 for (argc = 0; wp[argc]; argc++) 1310 ; 1311 if (user_opt.optind > argc || 1312 (user_opt.p != 0 && 1313 user_opt.p > strlen(wp[user_opt.optind - 1]))) { 1314 bi_errorf("arguments changed since last call"); 1315 return 1; 1316 } 1317 1318 user_opt.optarg = NULL; 1319 optc = ksh_getopt(wp, &user_opt, options); 1320 1321 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { 1322 buf[0] = '+'; 1323 buf[1] = optc; 1324 buf[2] = '\0'; 1325 } else { 1326 /* POSIX says var is set to ? at end-of-options, at&t ksh 1327 * sets it to null - we go with POSIX... 1328 */ 1329 buf[0] = optc < 0 ? '?' : optc; 1330 buf[1] = '\0'; 1331 } 1332 1333 /* at&t ksh does not change OPTIND if it was an unknown option. 1334 * Scripts counting on this are prone to break... (ie, don't count 1335 * on this staying). 1336 */ 1337 if (optc != '?') { 1338 user_opt.uoptind = user_opt.optind; 1339 } 1340 1341 voptarg = global("OPTARG"); 1342 voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */ 1343 /* Paranoia: ensure no bizarre results. */ 1344 if (voptarg->flag & INTEGER) 1345 typeset("OPTARG", 0, INTEGER, 0, 0); 1346 if (user_opt.optarg == NULL) 1347 unset(voptarg, 0); 1348 else 1349 /* This can't fail (have cleared readonly/integer) */ 1350 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); 1351 1352 ret = 0; 1353 1354 vq = global(var); 1355 /* Error message already printed (integer, readonly) */ 1356 if (!setstr(vq, buf, KSH_RETURN_ERROR)) 1357 ret = 1; 1358 if (Flag(FEXPORT)) 1359 typeset(var, EXPORT, 0, 0, 0); 1360 1361 return optc < 0 ? 1 : ret; 1362 } 1363 1364 #ifdef EMACS 1365 int 1366 c_bind(char **wp) 1367 { 1368 int optc, rv = 0, macro = 0, list = 0; 1369 char *cp; 1370 1371 while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != -1) 1372 switch (optc) { 1373 case 'l': 1374 list = 1; 1375 break; 1376 case 'm': 1377 macro = 1; 1378 break; 1379 case '?': 1380 return 1; 1381 } 1382 wp += builtin_opt.optind; 1383 1384 if (*wp == NULL) /* list all */ 1385 rv = x_bind(NULL, NULL, 0, list); 1386 1387 for (; *wp != NULL; wp++) { 1388 cp = strchr(*wp, '='); 1389 if (cp != NULL) 1390 *cp++ = '\0'; 1391 if (x_bind(*wp, cp, macro, 0)) 1392 rv = 1; 1393 } 1394 1395 return rv; 1396 } 1397 #endif 1398 1399 /* A leading = means assignments before command are kept; 1400 * a leading * means a POSIX special builtin; 1401 * a leading + means a POSIX regular builtin 1402 * (* and + should not be combined). 1403 */ 1404 const struct builtin kshbuiltins [] = { 1405 {"+alias", c_alias}, /* no =: at&t manual wrong */ 1406 {"+cd", c_cd}, 1407 {"+command", c_command}, 1408 {"echo", c_print}, 1409 {"*=export", c_typeset}, 1410 {"+fc", c_fc}, 1411 {"+getopts", c_getopts}, 1412 {"+jobs", c_jobs}, 1413 {"+kill", c_kill}, 1414 {"let", c_let}, 1415 {"print", c_print}, 1416 {"pwd", c_pwd}, 1417 {"*=readonly", c_typeset}, 1418 {"type", c_type}, 1419 {"=typeset", c_typeset}, 1420 {"+unalias", c_unalias}, 1421 {"whence", c_whence}, 1422 {"+bg", c_fgbg}, 1423 {"+fg", c_fgbg}, 1424 #ifdef EMACS 1425 {"bind", c_bind}, 1426 #endif 1427 {NULL, NULL} 1428 }; 1429