1 /* $OpenBSD: c_ksh.c,v 1.50 2016/03/21 13:35:00 tb 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, 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 < 0 && cdpath != NULL); 118 119 if (rval < 0) { 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) < 0) 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 < 0) { 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 = wp[0][0] == 'w'; 414 int fcflags; 415 const char *options = iam_whence ? "pv" : "pvV"; 416 417 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) 418 switch (optc) { 419 case 'p': 420 pflag = 1; 421 break; 422 case 'v': 423 vflag = 1; 424 break; 425 case 'V': 426 Vflag = 1; 427 break; 428 case '?': 429 return 1; 430 } 431 wp += builtin_opt.optind; 432 433 434 fcflags = FC_BI | FC_PATH | FC_FUNC; 435 if (!iam_whence) { 436 /* Note that -p on its own is dealt with in comexec() */ 437 if (pflag) 438 fcflags |= FC_DEFPATH; 439 /* Convert command options to whence options. Note that 440 * command -pV and command -pv use a different path search 441 * than whence -v or whence -pv. This should be considered 442 * a feature. 443 */ 444 vflag = Vflag; 445 } else if (pflag) 446 fcflags &= ~(FC_BI | FC_FUNC); 447 448 while ((vflag || ret == 0) && (id = *wp++) != NULL) { 449 tp = NULL; 450 if (!iam_whence || !pflag) 451 tp = ktsearch(&keywords, id, hash(id)); 452 if (!tp && (!iam_whence || !pflag)) { 453 tp = ktsearch(&aliases, id, hash(id)); 454 if (tp && !(tp->flag & ISSET)) 455 tp = NULL; 456 } 457 if (!tp) 458 tp = findcom(id, fcflags); 459 if (vflag || (tp->type != CALIAS && tp->type != CEXEC && 460 tp->type != CTALIAS)) 461 shprintf("%s", id); 462 switch (tp->type) { 463 case CKEYWD: 464 if (vflag) 465 shprintf(" is a reserved word"); 466 break; 467 case CALIAS: 468 if (vflag) 469 shprintf(" is an %salias for ", 470 (tp->flag & EXPORT) ? "exported " : ""); 471 if (!iam_whence && !vflag) 472 shprintf("alias %s=", id); 473 print_value_quoted(tp->val.s); 474 break; 475 case CFUNC: 476 if (vflag) { 477 shprintf(" is a"); 478 if (tp->flag & EXPORT) 479 shprintf("n exported"); 480 if (tp->flag & TRACE) 481 shprintf(" traced"); 482 if (!(tp->flag & ISSET)) { 483 shprintf(" undefined"); 484 if (tp->u.fpath) 485 shprintf(" (autoload from %s)", 486 tp->u.fpath); 487 } 488 shprintf(" function"); 489 } 490 break; 491 case CSHELL: 492 if (vflag) 493 shprintf(" is a%s shell builtin", 494 (tp->flag & SPEC_BI) ? " special" : ""); 495 break; 496 case CTALIAS: 497 case CEXEC: 498 if (tp->flag & ISSET) { 499 if (vflag) { 500 shprintf(" is "); 501 if (tp->type == CTALIAS) 502 shprintf("a tracked %salias for ", 503 (tp->flag & EXPORT) ? 504 "exported " : ""); 505 } 506 shprintf("%s", tp->val.s); 507 } else { 508 if (vflag) 509 shprintf(" not found"); 510 ret = 1; 511 } 512 break; 513 default: 514 shprintf("%s is *GOK*", id); 515 break; 516 } 517 if (vflag || !ret) 518 shprintf("\n"); 519 } 520 return ret; 521 } 522 523 /* Deal with command -vV - command -p dealt with in comexec() */ 524 int 525 c_command(char **wp) 526 { 527 /* Let c_whence do the work. Note that c_command() must be 528 * a distinct function from c_whence() (tested in comexec()). 529 */ 530 return c_whence(wp); 531 } 532 533 /* typeset, export, and readonly */ 534 int 535 c_typeset(char **wp) 536 { 537 struct block *l; 538 struct tbl *vp, **p; 539 int fset = 0, fclr = 0, thing = 0, func = 0, local = 0, pflag = 0; 540 const char *options = "L#R#UZ#fi#lprtux"; /* see comment below */ 541 char *fieldstr, *basestr; 542 int field, base, optc, flag; 543 544 switch (**wp) { 545 case 'e': /* export */ 546 fset |= EXPORT; 547 options = "p"; 548 break; 549 case 'r': /* readonly */ 550 fset |= RDONLY; 551 options = "p"; 552 break; 553 case 's': /* set */ 554 /* called with 'typeset -' */ 555 break; 556 case 't': /* typeset */ 557 local = 1; 558 break; 559 } 560 561 fieldstr = basestr = NULL; 562 builtin_opt.flags |= GF_PLUSOPT; 563 /* at&t ksh seems to have 0-9 as options, which are multiplied 564 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 565 * sets right justify in a field of 12). This allows options 566 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and 567 * does not allow the number to be specified as a separate argument 568 * Here, the number must follow the RLZi option, but is optional 569 * (see the # kludge in ksh_getopt()). 570 */ 571 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) { 572 flag = 0; 573 switch (optc) { 574 case 'L': 575 flag = LJUST; 576 fieldstr = builtin_opt.optarg; 577 break; 578 case 'R': 579 flag = RJUST; 580 fieldstr = builtin_opt.optarg; 581 break; 582 case 'U': 583 /* at&t ksh uses u, but this conflicts with 584 * upper/lower case. If this option is changed, 585 * need to change the -U below as well 586 */ 587 flag = INT_U; 588 break; 589 case 'Z': 590 flag = ZEROFIL; 591 fieldstr = builtin_opt.optarg; 592 break; 593 case 'f': 594 func = 1; 595 break; 596 case 'i': 597 flag = INTEGER; 598 basestr = builtin_opt.optarg; 599 break; 600 case 'l': 601 flag = LCASEV; 602 break; 603 case 'p': 604 /* posix export/readonly -p flag. 605 * typeset -p is the same as typeset (in pdksh); 606 * here for compatibility with ksh93. 607 */ 608 pflag = 1; 609 break; 610 case 'r': 611 flag = RDONLY; 612 break; 613 case 't': 614 flag = TRACE; 615 break; 616 case 'u': 617 flag = UCASEV_AL; /* upper case / autoload */ 618 break; 619 case 'x': 620 flag = EXPORT; 621 break; 622 case '?': 623 return 1; 624 } 625 if (builtin_opt.info & GI_PLUS) { 626 fclr |= flag; 627 fset &= ~flag; 628 thing = '+'; 629 } else { 630 fset |= flag; 631 fclr &= ~flag; 632 thing = '-'; 633 } 634 } 635 636 field = 0; 637 if (fieldstr && !bi_getn(fieldstr, &field)) 638 return 1; 639 base = 0; 640 if (basestr && !bi_getn(basestr, &base)) 641 return 1; 642 643 if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && 644 (wp[builtin_opt.optind][0] == '-' || 645 wp[builtin_opt.optind][0] == '+') && 646 wp[builtin_opt.optind][1] == '\0') { 647 thing = wp[builtin_opt.optind][0]; 648 builtin_opt.optind++; 649 } 650 651 if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) { 652 bi_errorf("only -t, -u and -x options may be used with -f"); 653 return 1; 654 } 655 if (wp[builtin_opt.optind]) { 656 /* Take care of exclusions. 657 * At this point, flags in fset are cleared in fclr and vise 658 * versa. This property should be preserved. 659 */ 660 if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */ 661 fset &= ~UCASEV_AL; 662 if (fset & LJUST) /* LJUST has priority over RJUST */ 663 fset &= ~RJUST; 664 if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */ 665 fset |= RJUST; 666 fclr &= ~RJUST; 667 } 668 /* Setting these attributes clears the others, unless they 669 * are also set in this command 670 */ 671 if (fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | 672 INTEGER | INT_U | INT_L)) 673 fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | 674 LCASEV | INTEGER | INT_U | INT_L); 675 } 676 677 /* set variables and attributes */ 678 if (wp[builtin_opt.optind]) { 679 int i; 680 int rval = 0; 681 struct tbl *f; 682 683 if (local && !func) 684 fset |= LOCAL; 685 for (i = builtin_opt.optind; wp[i]; i++) { 686 if (func) { 687 f = findfunc(wp[i], hash(wp[i]), 688 (fset&UCASEV_AL) ? true : false); 689 if (!f) { 690 /* at&t ksh does ++rval: bogus */ 691 rval = 1; 692 continue; 693 } 694 if (fset | fclr) { 695 f->flag |= fset; 696 f->flag &= ~fclr; 697 } else 698 fptreef(shl_stdout, 0, 699 f->flag & FKSH ? 700 "function %s %T\n" : 701 "%s() %T\n", wp[i], f->val.t); 702 } else if (!typeset(wp[i], fset, fclr, field, base)) { 703 bi_errorf("%s: not identifier", wp[i]); 704 return 1; 705 } 706 } 707 return rval; 708 } 709 710 /* list variables and attributes */ 711 flag = fset | fclr; /* no difference at this point.. */ 712 if (func) { 713 for (l = genv->loc; l; l = l->next) { 714 for (p = ktsort(&l->funs); (vp = *p++); ) { 715 if (flag && (vp->flag & flag) == 0) 716 continue; 717 if (thing == '-') 718 fptreef(shl_stdout, 0, vp->flag & FKSH ? 719 "function %s %T\n" : "%s() %T\n", 720 vp->name, vp->val.t); 721 else 722 shprintf("%s\n", vp->name); 723 } 724 } 725 } else { 726 for (l = genv->loc; l; l = l->next) { 727 for (p = ktsort(&l->vars); (vp = *p++); ) { 728 struct tbl *tvp; 729 int any_set = 0; 730 /* 731 * See if the parameter is set (for arrays, if any 732 * element is set). 733 */ 734 for (tvp = vp; tvp; tvp = tvp->u.array) 735 if (tvp->flag & ISSET) { 736 any_set = 1; 737 break; 738 } 739 740 /* 741 * Check attributes - note that all array elements 742 * have (should have?) the same attributes, so checking 743 * the first is sufficient. 744 * 745 * Report an unset param only if the user has 746 * explicitly given it some attribute (like export); 747 * otherwise, after "echo $FOO", we would report FOO... 748 */ 749 if (!any_set && !(vp->flag & USERATTRIB)) 750 continue; 751 if (flag && (vp->flag & flag) == 0) 752 continue; 753 for (; vp; vp = vp->u.array) { 754 /* Ignore array elements that aren't 755 * set unless there are no set elements, 756 * in which case the first is reported on */ 757 if ((vp->flag&ARRAY) && any_set && 758 !(vp->flag & ISSET)) 759 continue; 760 /* no arguments */ 761 if (thing == 0 && flag == 0) { 762 /* at&t ksh prints things 763 * like export, integer, 764 * leftadj, zerofill, etc., 765 * but POSIX says must 766 * be suitable for re-entry... 767 */ 768 shprintf("typeset "); 769 if ((vp->flag&INTEGER)) 770 shprintf("-i "); 771 if ((vp->flag&EXPORT)) 772 shprintf("-x "); 773 if ((vp->flag&RDONLY)) 774 shprintf("-r "); 775 if ((vp->flag&TRACE)) 776 shprintf("-t "); 777 if ((vp->flag&LJUST)) 778 shprintf("-L%d ", vp->u2.field); 779 if ((vp->flag&RJUST)) 780 shprintf("-R%d ", vp->u2.field); 781 if ((vp->flag&ZEROFIL)) 782 shprintf("-Z "); 783 if ((vp->flag&LCASEV)) 784 shprintf("-l "); 785 if ((vp->flag&UCASEV_AL)) 786 shprintf("-u "); 787 if ((vp->flag&INT_U)) 788 shprintf("-U "); 789 shprintf("%s\n", vp->name); 790 if (vp->flag&ARRAY) 791 break; 792 } else { 793 if (pflag) 794 shprintf("%s ", 795 (flag & EXPORT) ? 796 "export" : "readonly"); 797 if ((vp->flag&ARRAY) && any_set) 798 shprintf("%s[%d]", 799 vp->name, vp->index); 800 else 801 shprintf("%s", vp->name); 802 if (thing == '-' && (vp->flag&ISSET)) { 803 char *s = str_val(vp); 804 805 shprintf("="); 806 /* at&t ksh can't have 807 * justified integers.. */ 808 if ((vp->flag & 809 (INTEGER|LJUST|RJUST)) == 810 INTEGER) 811 shprintf("%s", s); 812 else 813 print_value_quoted(s); 814 } 815 shprintf("\n"); 816 } 817 /* Only report first `element' of an array with 818 * no set elements. 819 */ 820 if (!any_set) 821 break; 822 } 823 } 824 } 825 } 826 return 0; 827 } 828 829 int 830 c_alias(char **wp) 831 { 832 struct table *t = &aliases; 833 int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0, prefix = 0; 834 int xflag = 0; 835 int optc; 836 837 builtin_opt.flags |= GF_PLUSOPT; 838 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) { 839 prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; 840 switch (optc) { 841 case 'd': 842 t = &homedirs; 843 break; 844 case 'p': 845 pflag = 1; 846 break; 847 case 'r': 848 rflag = 1; 849 break; 850 case 't': 851 t = &taliases; 852 break; 853 case 'U': 854 /* 855 * kludge for tracked alias initialization 856 * (don't do a path search, just make an entry) 857 */ 858 Uflag = 1; 859 break; 860 case 'x': 861 xflag = EXPORT; 862 break; 863 case '?': 864 return 1; 865 } 866 } 867 wp += builtin_opt.optind; 868 869 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp && 870 (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') { 871 prefix = wp[0][0]; 872 wp++; 873 } 874 875 tflag = t == &taliases; 876 877 /* "hash -r" means reset all the tracked aliases.. */ 878 if (rflag) { 879 static const char *const args[] = { 880 "unalias", "-ta", NULL 881 }; 882 883 if (!tflag || *wp) { 884 shprintf("alias: -r flag can only be used with -t" 885 " and without arguments\n"); 886 return 1; 887 } 888 ksh_getopt_reset(&builtin_opt, GF_ERROR); 889 return c_unalias((char **) args); 890 } 891 892 if (*wp == NULL) { 893 struct tbl *ap, **p; 894 895 for (p = ktsort(t); (ap = *p++) != NULL; ) 896 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { 897 if (pflag) 898 shf_puts("alias ", shl_stdout); 899 shf_puts(ap->name, shl_stdout); 900 if (prefix != '+') { 901 shf_putc('=', shl_stdout); 902 print_value_quoted(ap->val.s); 903 } 904 shprintf("\n"); 905 } 906 } 907 908 for (; *wp != NULL; wp++) { 909 char *alias = *wp; 910 char *val = strchr(alias, '='); 911 char *newval; 912 struct tbl *ap; 913 int h; 914 915 if (val) 916 alias = str_nsave(alias, val++ - alias, ATEMP); 917 h = hash(alias); 918 if (val == NULL && !tflag && !xflag) { 919 ap = ktsearch(t, alias, h); 920 if (ap != NULL && (ap->flag&ISSET)) { 921 if (pflag) 922 shf_puts("alias ", shl_stdout); 923 shf_puts(ap->name, shl_stdout); 924 if (prefix != '+') { 925 shf_putc('=', shl_stdout); 926 print_value_quoted(ap->val.s); 927 } 928 shprintf("\n"); 929 } else { 930 shprintf("%s alias not found\n", alias); 931 rv = 1; 932 } 933 continue; 934 } 935 ap = ktenter(t, alias, h); 936 ap->type = tflag ? CTALIAS : CALIAS; 937 /* Are we setting the value or just some flags? */ 938 if ((val && !tflag) || (!val && tflag && !Uflag)) { 939 if (ap->flag&ALLOC) { 940 ap->flag &= ~(ALLOC|ISSET); 941 afree(ap->val.s, APERM); 942 } 943 /* ignore values for -t (at&t ksh does this) */ 944 newval = tflag ? search(alias, path, X_OK, NULL) : 945 val; 946 if (newval) { 947 ap->val.s = str_save(newval, APERM); 948 ap->flag |= ALLOC|ISSET; 949 } else 950 ap->flag &= ~ISSET; 951 } 952 ap->flag |= DEFINED; 953 if (prefix == '+') 954 ap->flag &= ~xflag; 955 else 956 ap->flag |= xflag; 957 if (val) 958 afree(alias, ATEMP); 959 } 960 961 return rv; 962 } 963 964 int 965 c_unalias(char **wp) 966 { 967 struct table *t = &aliases; 968 struct tbl *ap; 969 int rv = 0, all = 0; 970 int optc; 971 972 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1) 973 switch (optc) { 974 case 'a': 975 all = 1; 976 break; 977 case 'd': 978 t = &homedirs; 979 break; 980 case 't': 981 t = &taliases; 982 break; 983 case '?': 984 return 1; 985 } 986 wp += builtin_opt.optind; 987 988 for (; *wp != NULL; wp++) { 989 ap = ktsearch(t, *wp, hash(*wp)); 990 if (ap == NULL) { 991 rv = 1; /* POSIX */ 992 continue; 993 } 994 if (ap->flag&ALLOC) { 995 ap->flag &= ~(ALLOC|ISSET); 996 afree(ap->val.s, APERM); 997 } 998 ap->flag &= ~(DEFINED|ISSET|EXPORT); 999 } 1000 1001 if (all) { 1002 struct tstate ts; 1003 1004 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) { 1005 if (ap->flag&ALLOC) { 1006 ap->flag &= ~(ALLOC|ISSET); 1007 afree(ap->val.s, APERM); 1008 } 1009 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1010 } 1011 } 1012 1013 return rv; 1014 } 1015 1016 int 1017 c_let(char **wp) 1018 { 1019 int rv = 1; 1020 long val; 1021 1022 if (wp[1] == NULL) /* at&t ksh does this */ 1023 bi_errorf("no arguments"); 1024 else 1025 for (wp++; *wp; wp++) 1026 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) { 1027 rv = 2; /* distinguish error from zero result */ 1028 break; 1029 } else 1030 rv = val == 0; 1031 return rv; 1032 } 1033 1034 int 1035 c_jobs(char **wp) 1036 { 1037 int optc; 1038 int flag = 0; 1039 int nflag = 0; 1040 int rv = 0; 1041 1042 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1) 1043 switch (optc) { 1044 case 'l': 1045 flag = 1; 1046 break; 1047 case 'p': 1048 flag = 2; 1049 break; 1050 case 'n': 1051 nflag = 1; 1052 break; 1053 case 'z': /* debugging: print zombies */ 1054 nflag = -1; 1055 break; 1056 case '?': 1057 return 1; 1058 } 1059 wp += builtin_opt.optind; 1060 if (!*wp) { 1061 if (j_jobs(NULL, flag, nflag)) 1062 rv = 1; 1063 } else { 1064 for (; *wp; wp++) 1065 if (j_jobs(*wp, flag, nflag)) 1066 rv = 1; 1067 } 1068 return rv; 1069 } 1070 1071 #ifdef JOBS 1072 int 1073 c_fgbg(char **wp) 1074 { 1075 int bg = strcmp(*wp, "bg") == 0; 1076 int rv = 0; 1077 1078 if (!Flag(FMONITOR)) { 1079 bi_errorf("job control not enabled"); 1080 return 1; 1081 } 1082 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1083 return 1; 1084 wp += builtin_opt.optind; 1085 if (*wp) 1086 for (; *wp; wp++) 1087 rv = j_resume(*wp, bg); 1088 else 1089 rv = j_resume("%%", bg); 1090 /* POSIX says fg shall return 0 (unless an error occurs). 1091 * at&t ksh returns the exit value of the job... 1092 */ 1093 return (bg || Flag(FPOSIX)) ? 0 : rv; 1094 } 1095 #endif 1096 1097 struct kill_info { 1098 int num_width; 1099 int name_width; 1100 }; 1101 static char *kill_fmt_entry(void *arg, int i, char *buf, int buflen); 1102 1103 /* format a single kill item */ 1104 static char * 1105 kill_fmt_entry(void *arg, int i, char *buf, int buflen) 1106 { 1107 struct kill_info *ki = (struct kill_info *) arg; 1108 1109 i++; 1110 if (sigtraps[i].name) 1111 shf_snprintf(buf, buflen, "%*d %*s %s", 1112 ki->num_width, i, 1113 ki->name_width, sigtraps[i].name, 1114 sigtraps[i].mess); 1115 else 1116 shf_snprintf(buf, buflen, "%*d %*d %s", 1117 ki->num_width, i, 1118 ki->name_width, sigtraps[i].signal, 1119 sigtraps[i].mess); 1120 return buf; 1121 } 1122 1123 1124 int 1125 c_kill(char **wp) 1126 { 1127 Trap *t = NULL; 1128 char *p; 1129 int lflag = 0; 1130 int i, n, rv, sig; 1131 1132 /* assume old style options if -digits or -UPPERCASE */ 1133 if ((p = wp[1]) && *p == '-' && 1134 (digit(p[1]) || isupper((unsigned char)p[1]))) { 1135 if (!(t = gettrap(p + 1, true))) { 1136 bi_errorf("bad signal `%s'", p + 1); 1137 return 1; 1138 } 1139 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; 1140 } else { 1141 int optc; 1142 1143 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1) 1144 switch (optc) { 1145 case 'l': 1146 lflag = 1; 1147 break; 1148 case 's': 1149 if (!(t = gettrap(builtin_opt.optarg, true))) { 1150 bi_errorf("bad signal `%s'", 1151 builtin_opt.optarg); 1152 return 1; 1153 } 1154 break; 1155 case '?': 1156 return 1; 1157 } 1158 i = builtin_opt.optind; 1159 } 1160 if ((lflag && t) || (!wp[i] && !lflag)) { 1161 shf_fprintf(shl_out, 1162 "usage: kill [-s signame | -signum | -signame] { job | pid | pgrp } ...\n" 1163 " kill -l [exit_status ...]\n"); 1164 bi_errorf(NULL); 1165 return 1; 1166 } 1167 1168 if (lflag) { 1169 if (wp[i]) { 1170 for (; wp[i]; i++) { 1171 if (!bi_getn(wp[i], &n)) 1172 return 1; 1173 if (n > 128 && n < 128 + NSIG) 1174 n -= 128; 1175 if (n > 0 && n < NSIG && sigtraps[n].name) 1176 shprintf("%s\n", sigtraps[n].name); 1177 else 1178 shprintf("%d\n", n); 1179 } 1180 } else if (Flag(FPOSIX)) { 1181 p = null; 1182 for (i = 1; i < NSIG; i++, p = " ") 1183 if (sigtraps[i].name) 1184 shprintf("%s%s", p, sigtraps[i].name); 1185 shprintf("\n"); 1186 } else { 1187 int mess_width = 0, w, i; 1188 struct kill_info ki = { 1189 .num_width = 1, 1190 .name_width = 0, 1191 }; 1192 1193 for (i = NSIG; i >= 10; i /= 10) 1194 ki.num_width++; 1195 1196 for (i = 0; i < NSIG; i++) { 1197 w = sigtraps[i].name ? strlen(sigtraps[i].name) : 1198 ki.num_width; 1199 if (w > ki.name_width) 1200 ki.name_width = w; 1201 w = strlen(sigtraps[i].mess); 1202 if (w > mess_width) 1203 mess_width = w; 1204 } 1205 1206 print_columns(shl_stdout, NSIG - 1, 1207 kill_fmt_entry, (void *) &ki, 1208 ki.num_width + ki.name_width + mess_width + 3, 1); 1209 } 1210 return 0; 1211 } 1212 rv = 0; 1213 sig = t ? t->signal : SIGTERM; 1214 for (; (p = wp[i]); i++) { 1215 if (*p == '%') { 1216 if (j_kill(p, sig)) 1217 rv = 1; 1218 } else if (!getn(p, &n)) { 1219 bi_errorf("%s: arguments must be jobs or process IDs", 1220 p); 1221 rv = 1; 1222 } else { 1223 /* use killpg if < -1 since -1 does special things for 1224 * some non-killpg-endowed kills 1225 */ 1226 if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) { 1227 bi_errorf("%s: %s", p, strerror(errno)); 1228 rv = 1; 1229 } 1230 } 1231 } 1232 return rv; 1233 } 1234 1235 void 1236 getopts_reset(int val) 1237 { 1238 if (val >= 1) { 1239 ksh_getopt_reset(&user_opt, 1240 GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); 1241 user_opt.optind = user_opt.uoptind = val; 1242 } 1243 } 1244 1245 int 1246 c_getopts(char **wp) 1247 { 1248 int argc; 1249 const char *options; 1250 const char *var; 1251 int optc; 1252 int ret; 1253 char buf[3]; 1254 struct tbl *vq, *voptarg; 1255 1256 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1257 return 1; 1258 wp += builtin_opt.optind; 1259 1260 options = *wp++; 1261 if (!options) { 1262 bi_errorf("missing options argument"); 1263 return 1; 1264 } 1265 1266 var = *wp++; 1267 if (!var) { 1268 bi_errorf("missing name argument"); 1269 return 1; 1270 } 1271 if (!*var || *skip_varname(var, true)) { 1272 bi_errorf("%s: is not an identifier", var); 1273 return 1; 1274 } 1275 1276 if (genv->loc->next == NULL) { 1277 internal_errorf(0, "c_getopts: no argv"); 1278 return 1; 1279 } 1280 /* Which arguments are we parsing... */ 1281 if (*wp == NULL) 1282 wp = genv->loc->next->argv; 1283 else 1284 *--wp = genv->loc->next->argv[0]; 1285 1286 /* Check that our saved state won't cause a core dump... */ 1287 for (argc = 0; wp[argc]; argc++) 1288 ; 1289 if (user_opt.optind > argc || 1290 (user_opt.p != 0 && 1291 user_opt.p > strlen(wp[user_opt.optind - 1]))) { 1292 bi_errorf("arguments changed since last call"); 1293 return 1; 1294 } 1295 1296 user_opt.optarg = NULL; 1297 optc = ksh_getopt(wp, &user_opt, options); 1298 1299 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { 1300 buf[0] = '+'; 1301 buf[1] = optc; 1302 buf[2] = '\0'; 1303 } else { 1304 /* POSIX says var is set to ? at end-of-options, at&t ksh 1305 * sets it to null - we go with POSIX... 1306 */ 1307 buf[0] = optc < 0 ? '?' : optc; 1308 buf[1] = '\0'; 1309 } 1310 1311 /* at&t ksh does not change OPTIND if it was an unknown option. 1312 * Scripts counting on this are prone to break... (ie, don't count 1313 * on this staying). 1314 */ 1315 if (optc != '?') { 1316 user_opt.uoptind = user_opt.optind; 1317 } 1318 1319 voptarg = global("OPTARG"); 1320 voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */ 1321 /* Paranoia: ensure no bizarre results. */ 1322 if (voptarg->flag & INTEGER) 1323 typeset("OPTARG", 0, INTEGER, 0, 0); 1324 if (user_opt.optarg == NULL) 1325 unset(voptarg, 0); 1326 else 1327 /* This can't fail (have cleared readonly/integer) */ 1328 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); 1329 1330 ret = 0; 1331 1332 vq = global(var); 1333 /* Error message already printed (integer, readonly) */ 1334 if (!setstr(vq, buf, KSH_RETURN_ERROR)) 1335 ret = 1; 1336 if (Flag(FEXPORT)) 1337 typeset(var, EXPORT, 0, 0, 0); 1338 1339 return optc < 0 ? 1 : ret; 1340 } 1341 1342 #ifdef EMACS 1343 int 1344 c_bind(char **wp) 1345 { 1346 int optc, rv = 0, macro = 0, list = 0; 1347 char *cp; 1348 1349 while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != -1) 1350 switch (optc) { 1351 case 'l': 1352 list = 1; 1353 break; 1354 case 'm': 1355 macro = 1; 1356 break; 1357 case '?': 1358 return 1; 1359 } 1360 wp += builtin_opt.optind; 1361 1362 if (*wp == NULL) /* list all */ 1363 rv = x_bind(NULL, NULL, 0, list); 1364 1365 for (; *wp != NULL; wp++) { 1366 cp = strchr(*wp, '='); 1367 if (cp != NULL) 1368 *cp++ = '\0'; 1369 if (x_bind(*wp, cp, macro, 0)) 1370 rv = 1; 1371 } 1372 1373 return rv; 1374 } 1375 #endif 1376 1377 /* A leading = means assignments before command are kept; 1378 * a leading * means a POSIX special builtin; 1379 * a leading + means a POSIX regular builtin 1380 * (* and + should not be combined). 1381 */ 1382 const struct builtin kshbuiltins [] = { 1383 {"+alias", c_alias}, /* no =: at&t manual wrong */ 1384 {"+cd", c_cd}, 1385 {"+command", c_command}, 1386 {"echo", c_print}, 1387 {"*=export", c_typeset}, 1388 #ifdef HISTORY 1389 {"+fc", c_fc}, 1390 #endif /* HISTORY */ 1391 {"+getopts", c_getopts}, 1392 {"+jobs", c_jobs}, 1393 {"+kill", c_kill}, 1394 {"let", c_let}, 1395 {"print", c_print}, 1396 {"pwd", c_pwd}, 1397 {"*=readonly", c_typeset}, 1398 {"=typeset", c_typeset}, 1399 {"+unalias", c_unalias}, 1400 {"whence", c_whence}, 1401 #ifdef JOBS 1402 {"+bg", c_fgbg}, 1403 {"+fg", c_fgbg}, 1404 #endif 1405 #ifdef EMACS 1406 {"bind", c_bind}, 1407 #endif 1408 {NULL, NULL} 1409 }; 1410