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