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