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