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