1 /* $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */ 2 /* $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $ */ 3 /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ 4 /* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */ 5 6 /*- 7 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 8 * Thorsten Glaser <tg (at) mirbsd.org> 9 * 10 * Provided that these terms and disclaimer and all copyright notices 11 * are retained or reproduced in an accompanying document, permission 12 * is granted to deal in this work without restriction, including un- 13 * limited rights to use, publicly perform, distribute, sell, modify, 14 * merge, give away, or sublicence. 15 * 16 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 17 * the utmost extent permitted by applicable law, neither express nor 18 * implied; without malicious intent or gross negligence. In no event 19 * may a licensor, author or contributor be held liable for indirect, 20 * direct, other damage, loss, or other issues arising in any way out 21 * of dealing in the work, even if advised of the possibility of such 22 * damage or existence of a defect, except proven that it results out 23 * of said person's immediate fault when using the work as intended. 24 */ 25 26 #include "sh.h" 27 28 __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.157 2010/08/24 14:42:01 tg Exp $"); 29 30 #if HAVE_KILLPG 31 /* 32 * use killpg if < -1 since -1 does special things 33 * for some non-killpg-endowed kills 34 */ 35 #define mksh_kill(p,s) ((p) < -1 ? killpg(-(p), (s)) : kill((p), (s))) 36 #else 37 /* cross fingers and hope kill is killpg-endowed */ 38 #define mksh_kill kill 39 #endif 40 41 /* XXX conditions correct? */ 42 #if !defined(RLIM_INFINITY) && !defined(MKSH_NO_LIMITS) 43 #define MKSH_NO_LIMITS 44 #endif 45 46 #ifdef MKSH_NO_LIMITS 47 #define c_ulimit c_label 48 #endif 49 50 extern uint8_t set_refflag; 51 52 /* A leading = means assignments before command are kept; 53 * a leading * means a POSIX special builtin; 54 * a leading + means a POSIX regular builtin 55 * (* and + should not be combined). 56 */ 57 const struct builtin mkshbuiltins[] = { 58 {"*=.", c_dot}, 59 {"*=:", c_label}, 60 {"[", c_test}, 61 {"*=break", c_brkcont}, 62 {"=builtin", c_builtin}, 63 {"*=continue", c_brkcont}, 64 {"*=eval", c_eval}, 65 {"*=exec", c_exec}, 66 {"*=exit", c_exitreturn}, 67 {"+false", c_label}, 68 {"*=return", c_exitreturn}, 69 {"*=set", c_set}, 70 {"*=shift", c_shift}, 71 {"=times", c_times}, 72 {"*=trap", c_trap}, 73 {"+=wait", c_wait}, 74 {"+read", c_read}, 75 {"test", c_test}, 76 {"+true", c_label}, 77 {"ulimit", c_ulimit}, 78 {"+umask", c_umask}, 79 {"*=unset", c_unset}, 80 {"+alias", c_alias}, /* no =: AT&T manual wrong */ 81 {"+cd", c_cd}, 82 {"chdir", c_cd}, /* dash compatibility hack */ 83 {"+command", c_command}, 84 {"echo", c_print}, 85 {"*=export", c_typeset}, 86 {"+fc", c_fc}, 87 {"+getopts", c_getopts}, 88 {"+jobs", c_jobs}, 89 {"+kill", c_kill}, 90 {"let", c_let}, 91 {"print", c_print}, 92 #ifdef MKSH_PRINTF_BUILTIN 93 {"printf", c_printf}, 94 #endif 95 {"pwd", c_pwd}, 96 {"*=readonly", c_typeset}, 97 {T__typeset, c_typeset}, 98 {"+unalias", c_unalias}, 99 {"whence", c_whence}, 100 #ifndef MKSH_UNEMPLOYED 101 {"+bg", c_fgbg}, 102 {"+fg", c_fgbg}, 103 #endif 104 {"bind", c_bind}, 105 #if HAVE_MKNOD 106 {"mknod", c_mknod}, 107 #endif 108 {"realpath", c_realpath}, 109 {"rename", c_rename}, 110 {NULL, (int (*)(const char **))NULL} 111 }; 112 113 struct kill_info { 114 int num_width; 115 int name_width; 116 }; 117 118 static const struct t_op { 119 char op_text[4]; 120 Test_op op_num; 121 } u_ops[] = { 122 {"-a", TO_FILAXST }, 123 {"-b", TO_FILBDEV }, 124 {"-c", TO_FILCDEV }, 125 {"-d", TO_FILID }, 126 {"-e", TO_FILEXST }, 127 {"-f", TO_FILREG }, 128 {"-G", TO_FILGID }, 129 {"-g", TO_FILSETG }, 130 {"-h", TO_FILSYM }, 131 {"-H", TO_FILCDF }, 132 {"-k", TO_FILSTCK }, 133 {"-L", TO_FILSYM }, 134 {"-n", TO_STNZE }, 135 {"-O", TO_FILUID }, 136 {"-o", TO_OPTION }, 137 {"-p", TO_FILFIFO }, 138 {"-r", TO_FILRD }, 139 {"-s", TO_FILGZ }, 140 {"-S", TO_FILSOCK }, 141 {"-t", TO_FILTT }, 142 {"-u", TO_FILSETU }, 143 {"-w", TO_FILWR }, 144 {"-x", TO_FILEX }, 145 {"-z", TO_STZER }, 146 {"", TO_NONOP } 147 }; 148 static const struct t_op b_ops[] = { 149 {"=", TO_STEQL }, 150 {"==", TO_STEQL }, 151 {"!=", TO_STNEQ }, 152 {"<", TO_STLT }, 153 {">", TO_STGT }, 154 {"-eq", TO_INTEQ }, 155 {"-ne", TO_INTNE }, 156 {"-gt", TO_INTGT }, 157 {"-ge", TO_INTGE }, 158 {"-lt", TO_INTLT }, 159 {"-le", TO_INTLE }, 160 {"-ef", TO_FILEQ }, 161 {"-nt", TO_FILNT }, 162 {"-ot", TO_FILOT }, 163 {"", TO_NONOP } 164 }; 165 166 static int test_eaccess(const char *, int); 167 static int test_oexpr(Test_env *, bool); 168 static int test_aexpr(Test_env *, bool); 169 static int test_nexpr(Test_env *, bool); 170 static int test_primary(Test_env *, bool); 171 static Test_op ptest_isa(Test_env *, Test_meta); 172 static const char *ptest_getopnd(Test_env *, Test_op, bool); 173 static void ptest_error(Test_env *, int, const char *); 174 static char *kill_fmt_entry(char *, int, int, const void *); 175 static void p_time(struct shf *, bool, long, int, int, 176 const char *, const char *) 177 MKSH_A_NONNULL((nonnull (6, 7))); 178 static char *do_realpath(const char *); 179 180 static char * 181 do_realpath(const char *upath) 182 { 183 char *xp, *ip, *tp, *ipath, *ldest = NULL; 184 XString xs; 185 ptrdiff_t pos; 186 size_t len; 187 int symlinks = 32; /* max. recursion depth */ 188 int llen; 189 struct stat sb; 190 #ifdef NO_PATH_MAX 191 size_t ldestlen = 0; 192 #define pathlen sb.st_size 193 #define pathcnd (ldestlen < (pathlen + 1)) 194 #else 195 #define pathlen PATH_MAX 196 #define pathcnd (!ldest) 197 #endif 198 199 if (upath[0] == '/') { 200 /* upath is an absolute pathname */ 201 strdupx(ipath, upath, ATEMP); 202 } else { 203 /* upath is a relative pathname, prepend cwd */ 204 if ((tp = ksh_get_wd(NULL)) == NULL || tp[0] != '/') 205 return (NULL); 206 ipath = shf_smprintf("%s/%s", tp, upath); 207 afree(tp, ATEMP); 208 } 209 210 Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP); 211 212 while (*ip) { 213 /* skip slashes in input */ 214 while (*ip == '/') 215 ++ip; 216 if (!*ip) 217 break; 218 219 /* get next pathname component from input */ 220 tp = ip; 221 while (*ip && *ip != '/') 222 ++ip; 223 len = ip - tp; 224 225 /* check input for "." and ".." */ 226 if (tp[0] == '.') { 227 if (len == 1) 228 /* just continue with the next one */ 229 continue; 230 else if (len == 2 && tp[1] == '.') { 231 /* strip off last pathname component */ 232 while (xp > Xstring(xs, xp)) 233 if (*--xp == '/') 234 break; 235 /* then continue with the next one */ 236 continue; 237 } 238 } 239 240 /* store output position away, then append slash to output */ 241 pos = Xsavepos(xs, xp); 242 /* 1 for the '/' and len + 1 for tp and the NUL from below */ 243 XcheckN(xs, xp, 1 + len + 1); 244 Xput(xs, xp, '/'); 245 246 /* append next pathname component to output */ 247 memcpy(xp, tp, len); 248 xp += len; 249 *xp = '\0'; 250 251 /* lstat the current output, see if it's a symlink */ 252 if (lstat(Xstring(xs, xp), &sb)) { 253 /* lstat failed */ 254 if (errno == ENOENT) { 255 /* because the pathname does not exist */ 256 while (*ip == '/') 257 /* skip any trailing slashes */ 258 ++ip; 259 /* no more components left? */ 260 if (!*ip) 261 /* we can still return successfully */ 262 break; 263 /* more components left? fall through */ 264 } 265 /* not ENOENT or not at the end of ipath */ 266 goto notfound; 267 } 268 269 /* check if we encountered a symlink? */ 270 if (S_ISLNK(sb.st_mode)) { 271 /* reached maximum recursion depth? */ 272 if (!symlinks--) { 273 /* yep, prevent infinite loops */ 274 errno = ELOOP; 275 goto notfound; 276 } 277 278 /* get symlink(7) target */ 279 if (pathcnd) 280 ldest = aresize(ldest, pathlen + 1, ATEMP); 281 llen = readlink(Xstring(xs, xp), ldest, pathlen); 282 if (llen < 0) 283 /* oops... */ 284 goto notfound; 285 ldest[llen] = '\0'; 286 287 /* 288 * restart if symlink target is an absolute path, 289 * otherwise continue with currently resolved prefix 290 */ 291 xp = (ldest[0] == '/') ? Xstring(xs, xp) : 292 Xrestpos(xs, xp, pos); 293 tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip); 294 afree(ipath, ATEMP); 295 ip = ipath = tp; 296 } 297 /* otherwise (no symlink) merely go on */ 298 } 299 300 /* 301 * either found the target and successfully resolved it, 302 * or found its parent directory and may create it 303 */ 304 if (Xlength(xs, xp) == 0) 305 /* 306 * if the resolved pathname is "", make it "/", 307 * otherwise do not add a trailing slash 308 */ 309 Xput(xs, xp, '/'); 310 Xput(xs, xp, '\0'); 311 312 /* 313 * if source path had a trailing slash, check if target path 314 * is not a non-directory existing file 315 */ 316 if (ip > ipath && ip[-1] == '/') { 317 if (stat(Xstring(xs, xp), &sb)) { 318 if (errno != ENOENT) 319 goto notfound; 320 } else if (!S_ISDIR(sb.st_mode)) { 321 errno = ENOTDIR; 322 goto notfound; 323 } 324 /* target now either does not exist or is a directory */ 325 } 326 327 /* return target path */ 328 if (ldest != NULL) 329 afree(ldest, ATEMP); 330 afree(ipath, ATEMP); 331 return (Xclose(xs, xp)); 332 333 notfound: 334 llen = errno; /* save; free(3) might trash it */ 335 if (ldest != NULL) 336 afree(ldest, ATEMP); 337 afree(ipath, ATEMP); 338 Xfree(xs, xp); 339 errno = llen; 340 return (NULL); 341 342 #undef pathlen 343 #undef pathcnd 344 } 345 346 int 347 c_cd(const char **wp) 348 { 349 int optc, rv, phys_path; 350 bool physical = Flag(FPHYSICAL) ? true : false; 351 int cdnode; /* was a node from cdpath added in? */ 352 bool printpath = false; /* print where we cd'd? */ 353 struct tbl *pwd_s, *oldpwd_s; 354 XString xs; 355 char *dir, *allocd = NULL, *tryp, *pwd, *cdpath; 356 357 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) 358 switch (optc) { 359 case 'L': 360 physical = false; 361 break; 362 case 'P': 363 physical = true; 364 break; 365 case '?': 366 return (1); 367 } 368 wp += builtin_opt.optind; 369 370 if (Flag(FRESTRICTED)) { 371 bi_errorf("restricted shell - can't cd"); 372 return (1); 373 } 374 375 pwd_s = global("PWD"); 376 oldpwd_s = global("OLDPWD"); 377 378 if (!wp[0]) { 379 /* No arguments - go home */ 380 if ((dir = str_val(global("HOME"))) == null) { 381 bi_errorf("no home directory (HOME not set)"); 382 return (1); 383 } 384 } else if (!wp[1]) { 385 /* One argument: - or dir */ 386 strdupx(allocd, wp[0], ATEMP); 387 if (ksh_isdash((dir = allocd))) { 388 afree(allocd, ATEMP); 389 allocd = NULL; 390 dir = str_val(oldpwd_s); 391 if (dir == null) { 392 bi_errorf("no OLDPWD"); 393 return (1); 394 } 395 printpath = true; 396 } 397 } else if (!wp[2]) { 398 /* Two arguments - substitute arg1 in PWD for arg2 */ 399 int ilen, olen, nlen, elen; 400 char *cp; 401 402 if (!current_wd[0]) { 403 bi_errorf("don't know current directory"); 404 return (1); 405 } 406 /* substitute arg1 for arg2 in current path. 407 * if the first substitution fails because the cd fails 408 * we could try to find another substitution. For now 409 * we don't 410 */ 411 if ((cp = strstr(current_wd, wp[0])) == NULL) { 412 bi_errorf("bad substitution"); 413 return (1); 414 } 415 ilen = cp - current_wd; 416 olen = strlen(wp[0]); 417 nlen = strlen(wp[1]); 418 elen = strlen(current_wd + ilen + olen) + 1; 419 dir = allocd = alloc(ilen + nlen + elen, ATEMP); 420 memcpy(dir, current_wd, ilen); 421 memcpy(dir + ilen, wp[1], nlen); 422 memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); 423 printpath = true; 424 } else { 425 bi_errorf("too many arguments"); 426 return (1); 427 } 428 429 #ifdef NO_PATH_MAX 430 /* only a first guess; make_path will enlarge xs if necessary */ 431 XinitN(xs, 1024, ATEMP); 432 #else 433 XinitN(xs, PATH_MAX, ATEMP); 434 #endif 435 436 cdpath = str_val(global("CDPATH")); 437 do { 438 cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); 439 if (physical) 440 rv = chdir(tryp = Xstring(xs, xp) + phys_path); 441 else { 442 simplify_path(Xstring(xs, xp)); 443 rv = chdir(tryp = Xstring(xs, xp)); 444 } 445 } while (rv < 0 && cdpath != NULL); 446 447 if (rv < 0) { 448 if (cdnode) 449 bi_errorf("%s: bad directory", dir); 450 else 451 bi_errorf("%s - %s", tryp, strerror(errno)); 452 afree(allocd, ATEMP); 453 return (1); 454 } 455 456 /* allocd (above) => dir, which is no longer used */ 457 afree(allocd, ATEMP); 458 allocd = NULL; 459 460 /* Clear out tracked aliases with relative paths */ 461 flushcom(0); 462 463 /* Set OLDPWD (note: unsetting OLDPWD does not disable this 464 * setting in AT&T ksh) 465 */ 466 if (current_wd[0]) 467 /* Ignore failure (happens if readonly or integer) */ 468 setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); 469 470 if (Xstring(xs, xp)[0] != '/') { 471 pwd = NULL; 472 } else if (!physical || !(pwd = allocd = do_realpath(Xstring(xs, xp)))) 473 pwd = Xstring(xs, xp); 474 475 /* Set PWD */ 476 if (pwd) { 477 char *ptmp = pwd; 478 479 set_current_wd(ptmp); 480 /* Ignore failure (happens if readonly or integer) */ 481 setstr(pwd_s, ptmp, KSH_RETURN_ERROR); 482 } else { 483 set_current_wd(null); 484 pwd = Xstring(xs, xp); 485 /* XXX unset $PWD? */ 486 } 487 if (printpath || cdnode) 488 shprintf("%s\n", pwd); 489 490 afree(allocd, ATEMP); 491 return (0); 492 } 493 494 int 495 c_pwd(const char **wp) 496 { 497 int optc; 498 bool physical = Flag(FPHYSICAL) ? true : false; 499 char *p, *allocd = NULL; 500 501 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) 502 switch (optc) { 503 case 'L': 504 physical = false; 505 break; 506 case 'P': 507 physical = true; 508 break; 509 case '?': 510 return (1); 511 } 512 wp += builtin_opt.optind; 513 514 if (wp[0]) { 515 bi_errorf("too many arguments"); 516 return (1); 517 } 518 p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) : 519 current_wd) : NULL; 520 if (p && access(p, R_OK) < 0) 521 p = NULL; 522 if (!p && !(p = allocd = ksh_get_wd(NULL))) { 523 bi_errorf("can't get current directory - %s", strerror(errno)); 524 return (1); 525 } 526 shprintf("%s\n", p); 527 afree(allocd, ATEMP); 528 return (0); 529 } 530 531 static const char *s_ptr; 532 static int s_get(void); 533 static void s_put(int); 534 535 int 536 c_print(const char **wp) 537 { 538 #define PO_NL BIT(0) /* print newline */ 539 #define PO_EXPAND BIT(1) /* expand backslash sequences */ 540 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */ 541 #define PO_HIST BIT(3) /* print to history instead of stdout */ 542 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ 543 int fd = 1, c; 544 int flags = PO_EXPAND|PO_NL; 545 const char *s, *emsg; 546 XString xs; 547 char *xp; 548 549 if (wp[0][0] == 'e') { 550 /* echo builtin */ 551 wp++; 552 if (Flag(FPOSIX) || Flag(FSH)) { 553 /* Debian Policy 10.4 compliant "echo" builtin */ 554 if (*wp && !strcmp(*wp, "-n")) { 555 /* we recognise "-n" only as the first arg */ 556 flags = 0; 557 wp++; 558 } else 559 /* otherwise, we print everything as-is */ 560 flags = PO_NL; 561 } else { 562 int nflags = flags; 563 564 /** 565 * a compromise between sysV and BSD echo commands: 566 * escape sequences are enabled by default, and -n, 567 * -e and -E are recognised if they appear in argu- 568 * ments with no illegal options (ie, echo -nq will 569 * print -nq). 570 * Different from sysV echo since options are reco- 571 * gnised, different from BSD echo since escape se- 572 * quences are enabled by default. 573 */ 574 575 while ((s = *wp) && *s == '-' && s[1]) { 576 while (*++s) 577 if (*s == 'n') 578 nflags &= ~PO_NL; 579 else if (*s == 'e') 580 nflags |= PO_EXPAND; 581 else if (*s == 'E') 582 nflags &= ~PO_EXPAND; 583 else 584 /* 585 * bad option: don't use 586 * nflags, print argument 587 */ 588 break; 589 590 if (*s) 591 break; 592 wp++; 593 flags = nflags; 594 } 595 } 596 } else { 597 int optc; 598 const char *opts = "Rnprsu,"; 599 600 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) 601 switch (optc) { 602 case 'R': /* fake BSD echo command */ 603 flags |= PO_PMINUSMINUS; 604 flags &= ~PO_EXPAND; 605 opts = "ne"; 606 break; 607 case 'e': 608 flags |= PO_EXPAND; 609 break; 610 case 'n': 611 flags &= ~PO_NL; 612 break; 613 case 'p': 614 if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { 615 bi_errorf("-p: %s", emsg); 616 return (1); 617 } 618 break; 619 case 'r': 620 flags &= ~PO_EXPAND; 621 break; 622 case 's': 623 flags |= PO_HIST; 624 break; 625 case 'u': 626 if (!*(s = builtin_opt.optarg)) 627 fd = 0; 628 else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { 629 bi_errorf("-u: %s: %s", s, emsg); 630 return (1); 631 } 632 break; 633 case '?': 634 return (1); 635 } 636 637 if (!(builtin_opt.info & GI_MINUSMINUS)) { 638 /* treat a lone - like -- */ 639 if (wp[builtin_opt.optind] && 640 ksh_isdash(wp[builtin_opt.optind])) 641 builtin_opt.optind++; 642 } else if (flags & PO_PMINUSMINUS) 643 builtin_opt.optind--; 644 wp += builtin_opt.optind; 645 } 646 647 Xinit(xs, xp, 128, ATEMP); 648 649 while (*wp != NULL) { 650 s = *wp; 651 while ((c = *s++) != '\0') { 652 Xcheck(xs, xp); 653 if ((flags & PO_EXPAND) && c == '\\') { 654 s_ptr = s; 655 c = unbksl(false, s_get, s_put); 656 s = s_ptr; 657 if (c == -1) { 658 /* rejected by generic function */ 659 switch ((c = *s++)) { 660 case 'c': 661 flags &= ~PO_NL; 662 /* AT&T brain damage */ 663 continue; 664 case '\0': 665 s--; 666 c = '\\'; 667 break; 668 default: 669 Xput(xs, xp, '\\'); 670 } 671 } else if ((unsigned int)c > 0xFF) { 672 /* generic function returned Unicode */ 673 char ts[4]; 674 675 c = utf_wctomb(ts, c - 0x100); 676 ts[c] = 0; 677 for (c = 0; ts[c]; ++c) 678 Xput(xs, xp, ts[c]); 679 continue; 680 } 681 } 682 Xput(xs, xp, c); 683 } 684 if (*++wp != NULL) 685 Xput(xs, xp, ' '); 686 } 687 if (flags & PO_NL) 688 Xput(xs, xp, '\n'); 689 690 if (flags & PO_HIST) { 691 Xput(xs, xp, '\0'); 692 histsave(&source->line, Xstring(xs, xp), true, false); 693 Xfree(xs, xp); 694 } else { 695 int len = Xlength(xs, xp); 696 int opipe = 0; 697 698 /* Ensure we aren't killed by a SIGPIPE while writing to 699 * a coprocess. AT&T ksh doesn't seem to do this (seems 700 * to just check that the co-process is alive which is 701 * not enough). 702 */ 703 if (coproc.write >= 0 && coproc.write == fd) { 704 flags |= PO_COPROC; 705 opipe = block_pipe(); 706 } 707 for (s = Xstring(xs, xp); len > 0; ) { 708 if ((c = write(fd, s, len)) < 0) { 709 if (flags & PO_COPROC) 710 restore_pipe(opipe); 711 if (errno == EINTR) { 712 /* allow user to ^C out */ 713 intrcheck(); 714 if (flags & PO_COPROC) 715 opipe = block_pipe(); 716 continue; 717 } 718 return (1); 719 } 720 s += c; 721 len -= c; 722 } 723 if (flags & PO_COPROC) 724 restore_pipe(opipe); 725 } 726 727 return (0); 728 } 729 730 static int 731 s_get(void) 732 { 733 return (*s_ptr++); 734 } 735 736 static void 737 s_put(int c MKSH_A_UNUSED) 738 { 739 --s_ptr; 740 } 741 742 int 743 c_whence(const char **wp) 744 { 745 struct tbl *tp; 746 const char *id; 747 bool pflag = false, vflag = false, Vflag = false; 748 int rv = 0, optc, fcflags; 749 bool iam_whence = wp[0][0] == 'w'; 750 const char *opts = iam_whence ? "pv" : "pvV"; 751 752 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) 753 switch (optc) { 754 case 'p': 755 pflag = true; 756 break; 757 case 'v': 758 vflag = true; 759 break; 760 case 'V': 761 Vflag = true; 762 break; 763 case '?': 764 return (1); 765 } 766 wp += builtin_opt.optind; 767 768 fcflags = FC_BI | FC_PATH | FC_FUNC; 769 if (!iam_whence) { 770 /* Note that -p on its own is deal with in comexec() */ 771 if (pflag) 772 fcflags |= FC_DEFPATH; 773 /* Convert command options to whence options - note that 774 * command -pV uses a different path search than whence -v 775 * or whence -pv. This should be considered a feature. 776 */ 777 vflag = Vflag; 778 } 779 if (pflag) 780 fcflags &= ~(FC_BI | FC_FUNC); 781 782 while ((vflag || rv == 0) && (id = *wp++) != NULL) { 783 uint32_t h = 0; 784 785 tp = NULL; 786 if ((iam_whence || vflag) && !pflag) 787 tp = ktsearch(&keywords, id, h = hash(id)); 788 if (!tp && !pflag) { 789 tp = ktsearch(&aliases, id, h ? h : hash(id)); 790 if (tp && !(tp->flag & ISSET)) 791 tp = NULL; 792 } 793 if (!tp) 794 tp = findcom(id, fcflags); 795 if (vflag || (tp->type != CALIAS && tp->type != CEXEC && 796 tp->type != CTALIAS)) 797 shf_puts(id, shl_stdout); 798 switch (tp->type) { 799 case CKEYWD: 800 if (vflag) 801 shf_puts(" is a reserved word", shl_stdout); 802 break; 803 case CALIAS: 804 if (vflag) 805 shprintf(" is an %salias for ", 806 (tp->flag & EXPORT) ? "exported " : null); 807 if (!iam_whence && !vflag) 808 shprintf("alias %s=", id); 809 print_value_quoted(tp->val.s); 810 break; 811 case CFUNC: 812 if (vflag) { 813 shf_puts(" is a", shl_stdout); 814 if (tp->flag & EXPORT) 815 shf_puts("n exported", shl_stdout); 816 if (tp->flag & TRACE) 817 shf_puts(" traced", shl_stdout); 818 if (!(tp->flag & ISSET)) { 819 shf_puts(" undefined", shl_stdout); 820 if (tp->u.fpath) 821 shprintf(" (autoload from %s)", 822 tp->u.fpath); 823 } 824 shf_puts(" function", shl_stdout); 825 } 826 break; 827 case CSHELL: 828 if (vflag) 829 shprintf(" is a%s shell builtin", 830 (tp->flag & SPEC_BI) ? " special" : null); 831 break; 832 case CTALIAS: 833 case CEXEC: 834 if (tp->flag & ISSET) { 835 if (vflag) { 836 shf_puts(" is ", shl_stdout); 837 if (tp->type == CTALIAS) 838 shprintf("a tracked %salias for ", 839 (tp->flag & EXPORT) ? 840 "exported " : null); 841 } 842 shf_puts(tp->val.s, shl_stdout); 843 } else { 844 if (vflag) 845 shf_puts(" not found", shl_stdout); 846 rv = 1; 847 } 848 break; 849 default: 850 shprintf("%s is *GOK*", id); 851 break; 852 } 853 if (vflag || !rv) 854 shf_putc('\n', shl_stdout); 855 } 856 return (rv); 857 } 858 859 /* Deal with command -vV - command -p dealt with in comexec() */ 860 int 861 c_command(const char **wp) 862 { 863 /* Let c_whence do the work. Note that c_command() must be 864 * a distinct function from c_whence() (tested in comexec()). 865 */ 866 return (c_whence(wp)); 867 } 868 869 /* typeset, export, and readonly */ 870 int 871 c_typeset(const char **wp) 872 { 873 struct block *l; 874 struct tbl *vp, **p; 875 Tflag fset = 0, fclr = 0, flag; 876 int thing = 0, field, base, optc; 877 const char *opts; 878 const char *fieldstr, *basestr; 879 bool localv = false, func = false, pflag = false, istset = true; 880 881 switch (**wp) { 882 case 'e': /* export */ 883 fset |= EXPORT; 884 istset = false; 885 break; 886 case 'r': /* readonly */ 887 fset |= RDONLY; 888 istset = false; 889 break; 890 case 's': /* set */ 891 /* called with 'typeset -' */ 892 break; 893 case 't': /* typeset */ 894 localv = true; 895 break; 896 } 897 898 /* see comment below regarding possible opions */ 899 opts = istset ? "L#R#UZ#afi#lnprtux" : "p"; 900 901 fieldstr = basestr = NULL; 902 builtin_opt.flags |= GF_PLUSOPT; 903 /* AT&T ksh seems to have 0-9 as options which are multiplied 904 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 905 * sets right justify in a field of 12). This allows options 906 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and 907 * does not allow the number to be specified as a separate argument 908 * Here, the number must follow the RLZi option, but is optional 909 * (see the # kludge in ksh_getopt()). 910 */ 911 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) { 912 flag = 0; 913 switch (optc) { 914 case 'L': 915 flag = LJUST; 916 fieldstr = builtin_opt.optarg; 917 break; 918 case 'R': 919 flag = RJUST; 920 fieldstr = builtin_opt.optarg; 921 break; 922 case 'U': 923 /* AT&T ksh uses u, but this conflicts with 924 * upper/lower case. If this option is changed, 925 * need to change the -U below as well 926 */ 927 flag = INT_U; 928 break; 929 case 'Z': 930 flag = ZEROFIL; 931 fieldstr = builtin_opt.optarg; 932 break; 933 case 'a': 934 /* 935 * this is supposed to set (-a) or unset (+a) the 936 * indexed array attribute; it does nothing on an 937 * existing regular string or indexed array though 938 */ 939 break; 940 case 'f': 941 func = true; 942 break; 943 case 'i': 944 flag = INTEGER; 945 basestr = builtin_opt.optarg; 946 break; 947 case 'l': 948 flag = LCASEV; 949 break; 950 case 'n': 951 set_refflag = (builtin_opt.info & GI_PLUS) ? 2 : 1; 952 break; 953 case 'p': 954 /* export, readonly: POSIX -p flag */ 955 /* typeset: show values as well */ 956 pflag = true; 957 if (istset) 958 continue; 959 break; 960 case 'r': 961 flag = RDONLY; 962 break; 963 case 't': 964 flag = TRACE; 965 break; 966 case 'u': 967 flag = UCASEV_AL; /* upper case / autoload */ 968 break; 969 case 'x': 970 flag = EXPORT; 971 break; 972 case '?': 973 return (1); 974 } 975 if (builtin_opt.info & GI_PLUS) { 976 fclr |= flag; 977 fset &= ~flag; 978 thing = '+'; 979 } else { 980 fset |= flag; 981 fclr &= ~flag; 982 thing = '-'; 983 } 984 } 985 986 field = 0; 987 if (fieldstr && !bi_getn(fieldstr, &field)) 988 return (1); 989 base = 0; 990 if (basestr && !bi_getn(basestr, &base)) 991 return (1); 992 993 if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && 994 (wp[builtin_opt.optind][0] == '-' || 995 wp[builtin_opt.optind][0] == '+') && 996 wp[builtin_opt.optind][1] == '\0') { 997 thing = wp[builtin_opt.optind][0]; 998 builtin_opt.optind++; 999 } 1000 1001 if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) || set_refflag)) { 1002 bi_errorf("only -t, -u and -x options may be used with -f"); 1003 set_refflag = 0; 1004 return (1); 1005 } 1006 if (wp[builtin_opt.optind]) { 1007 /* Take care of exclusions. 1008 * At this point, flags in fset are cleared in fclr and vice 1009 * versa. This property should be preserved. 1010 */ 1011 if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */ 1012 fset &= ~UCASEV_AL; 1013 if (fset & LJUST) /* LJUST has priority over RJUST */ 1014 fset &= ~RJUST; 1015 if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */ 1016 fset |= RJUST; 1017 fclr &= ~RJUST; 1018 } 1019 /* Setting these attributes clears the others, unless they 1020 * are also set in this command 1021 */ 1022 if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | 1023 INTEGER | INT_U | INT_L)) || set_refflag) 1024 fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | 1025 LCASEV | INTEGER | INT_U | INT_L); 1026 } 1027 1028 /* set variables and attributes */ 1029 if (wp[builtin_opt.optind]) { 1030 int i, rv = 0; 1031 struct tbl *f; 1032 1033 if (localv && !func) 1034 fset |= LOCAL; 1035 for (i = builtin_opt.optind; wp[i]; i++) { 1036 if (func) { 1037 f = findfunc(wp[i], hash(wp[i]), 1038 (fset&UCASEV_AL) ? true : false); 1039 if (!f) { 1040 /* AT&T ksh does ++rv: bogus */ 1041 rv = 1; 1042 continue; 1043 } 1044 if (fset | fclr) { 1045 f->flag |= fset; 1046 f->flag &= ~fclr; 1047 } else 1048 fptreef(shl_stdout, 0, 1049 f->flag & FKSH ? 1050 "function %s %T\n" : 1051 "%s() %T\n", wp[i], f->val.t); 1052 } else if (!typeset(wp[i], fset, fclr, field, base)) { 1053 bi_errorf("%s: not identifier", wp[i]); 1054 set_refflag = 0; 1055 return (1); 1056 } 1057 } 1058 set_refflag = 0; 1059 return (rv); 1060 } 1061 1062 /* list variables and attributes */ 1063 flag = fset | fclr; /* no difference at this point.. */ 1064 if (func) { 1065 for (l = e->loc; l; l = l->next) { 1066 for (p = ktsort(&l->funs); (vp = *p++); ) { 1067 if (flag && (vp->flag & flag) == 0) 1068 continue; 1069 if (thing == '-') 1070 fptreef(shl_stdout, 0, vp->flag & FKSH ? 1071 "function %s %T\n" : "%s() %T\n", 1072 vp->name, vp->val.t); 1073 else 1074 shprintf("%s\n", vp->name); 1075 } 1076 } 1077 } else { 1078 for (l = e->loc; l; l = l->next) { 1079 for (p = ktsort(&l->vars); (vp = *p++); ) { 1080 struct tbl *tvp; 1081 bool any_set = false; 1082 /* 1083 * See if the parameter is set (for arrays, if any 1084 * element is set). 1085 */ 1086 for (tvp = vp; tvp; tvp = tvp->u.array) 1087 if (tvp->flag & ISSET) { 1088 any_set = true; 1089 break; 1090 } 1091 1092 /* 1093 * Check attributes - note that all array elements 1094 * have (should have?) the same attributes, so checking 1095 * the first is sufficient. 1096 * 1097 * Report an unset param only if the user has 1098 * explicitly given it some attribute (like export); 1099 * otherwise, after "echo $FOO", we would report FOO... 1100 */ 1101 if (!any_set && !(vp->flag & USERATTRIB)) 1102 continue; 1103 if (flag && (vp->flag & flag) == 0) 1104 continue; 1105 for (; vp; vp = vp->u.array) { 1106 /* Ignore array elements that aren't 1107 * set unless there are no set elements, 1108 * in which case the first is reported on */ 1109 if ((vp->flag&ARRAY) && any_set && 1110 !(vp->flag & ISSET)) 1111 continue; 1112 /* no arguments */ 1113 if (thing == 0 && flag == 0) { 1114 /* AT&T ksh prints things 1115 * like export, integer, 1116 * leftadj, zerofill, etc., 1117 * but POSIX says must 1118 * be suitable for re-entry... 1119 */ 1120 shf_puts("typeset ", shl_stdout); 1121 if (((vp->flag&(ARRAY|ASSOC))==ASSOC)) 1122 shf_puts("-n ", shl_stdout); 1123 if ((vp->flag&INTEGER)) 1124 shf_puts("-i ", shl_stdout); 1125 if ((vp->flag&EXPORT)) 1126 shf_puts("-x ", shl_stdout); 1127 if ((vp->flag&RDONLY)) 1128 shf_puts("-r ", shl_stdout); 1129 if ((vp->flag&TRACE)) 1130 shf_puts("-t ", shl_stdout); 1131 if ((vp->flag&LJUST)) 1132 shprintf("-L%d ", vp->u2.field); 1133 if ((vp->flag&RJUST)) 1134 shprintf("-R%d ", vp->u2.field); 1135 if ((vp->flag&ZEROFIL)) 1136 shf_puts("-Z ", shl_stdout); 1137 if ((vp->flag&LCASEV)) 1138 shf_puts("-l ", shl_stdout); 1139 if ((vp->flag&UCASEV_AL)) 1140 shf_puts("-u ", shl_stdout); 1141 if ((vp->flag&INT_U)) 1142 shf_puts("-U ", shl_stdout); 1143 shf_puts(vp->name, shl_stdout); 1144 if (pflag) { 1145 char *s = str_val(vp); 1146 1147 shf_putc('=', shl_stdout); 1148 /* AT&T ksh can't have 1149 * justified integers.. */ 1150 if ((vp->flag & 1151 (INTEGER|LJUST|RJUST)) == 1152 INTEGER) 1153 shf_puts(s, shl_stdout); 1154 else 1155 print_value_quoted(s); 1156 } 1157 shf_putc('\n', shl_stdout); 1158 if (vp->flag & ARRAY) 1159 break; 1160 } else { 1161 if (pflag) 1162 shf_puts(istset ? 1163 "typeset " : 1164 (flag & EXPORT) ? 1165 "export " : 1166 "readonly ", 1167 shl_stdout); 1168 if ((vp->flag&ARRAY) && any_set) 1169 shprintf("%s[%lu]", 1170 vp->name, 1171 arrayindex(vp)); 1172 else 1173 shf_puts(vp->name, shl_stdout); 1174 if (thing == '-' && (vp->flag&ISSET)) { 1175 char *s = str_val(vp); 1176 1177 shf_putc('=', shl_stdout); 1178 /* AT&T ksh can't have 1179 * justified integers.. */ 1180 if ((vp->flag & 1181 (INTEGER|LJUST|RJUST)) == 1182 INTEGER) 1183 shf_puts(s, shl_stdout); 1184 else 1185 print_value_quoted(s); 1186 } 1187 shf_putc('\n', shl_stdout); 1188 } 1189 /* Only report first 'element' of an array with 1190 * no set elements. 1191 */ 1192 if (!any_set) 1193 break; 1194 } 1195 } 1196 } 1197 } 1198 return (0); 1199 } 1200 1201 int 1202 c_alias(const char **wp) 1203 { 1204 struct table *t = &aliases; 1205 int rv = 0, prefix = 0; 1206 bool rflag = false, tflag, Uflag = false, pflag = false; 1207 Tflag xflag = 0; 1208 int optc; 1209 1210 builtin_opt.flags |= GF_PLUSOPT; 1211 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) { 1212 prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; 1213 switch (optc) { 1214 case 'd': 1215 #ifdef MKSH_NOPWNAM 1216 t = NULL; /* fix "alias -dt" */ 1217 #else 1218 t = &homedirs; 1219 #endif 1220 break; 1221 case 'p': 1222 pflag = true; 1223 break; 1224 case 'r': 1225 rflag = true; 1226 break; 1227 case 't': 1228 t = &taliases; 1229 break; 1230 case 'U': 1231 /* 1232 * kludge for tracked alias initialization 1233 * (don't do a path search, just make an entry) 1234 */ 1235 Uflag = true; 1236 break; 1237 case 'x': 1238 xflag = EXPORT; 1239 break; 1240 case '?': 1241 return (1); 1242 } 1243 } 1244 #ifdef MKSH_NOPWNAM 1245 if (t == NULL) 1246 return (0); 1247 #endif 1248 wp += builtin_opt.optind; 1249 1250 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp && 1251 (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') { 1252 prefix = wp[0][0]; 1253 wp++; 1254 } 1255 1256 tflag = t == &taliases; 1257 1258 /* "hash -r" means reset all the tracked aliases.. */ 1259 if (rflag) { 1260 static const char *args[] = { 1261 "unalias", "-ta", NULL 1262 }; 1263 1264 if (!tflag || *wp) { 1265 shf_puts("alias: -r flag can only be used with -t" 1266 " and without arguments\n", shl_stdout); 1267 return (1); 1268 } 1269 ksh_getopt_reset(&builtin_opt, GF_ERROR); 1270 return (c_unalias(args)); 1271 } 1272 1273 if (*wp == NULL) { 1274 struct tbl *ap, **p; 1275 1276 for (p = ktsort(t); (ap = *p++) != NULL; ) 1277 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { 1278 if (pflag) 1279 shf_puts("alias ", shl_stdout); 1280 shf_puts(ap->name, shl_stdout); 1281 if (prefix != '+') { 1282 shf_putc('=', shl_stdout); 1283 print_value_quoted(ap->val.s); 1284 } 1285 shf_putc('\n', shl_stdout); 1286 } 1287 } 1288 1289 for (; *wp != NULL; wp++) { 1290 const char *alias = *wp, *val, *newval; 1291 char *xalias = NULL; 1292 struct tbl *ap; 1293 uint32_t h; 1294 1295 if ((val = cstrchr(alias, '='))) { 1296 strndupx(xalias, alias, val++ - alias, ATEMP); 1297 alias = xalias; 1298 } 1299 h = hash(alias); 1300 if (val == NULL && !tflag && !xflag) { 1301 ap = ktsearch(t, alias, h); 1302 if (ap != NULL && (ap->flag&ISSET)) { 1303 if (pflag) 1304 shf_puts("alias ", shl_stdout); 1305 shf_puts(ap->name, shl_stdout); 1306 if (prefix != '+') { 1307 shf_putc('=', shl_stdout); 1308 print_value_quoted(ap->val.s); 1309 } 1310 shf_putc('\n', shl_stdout); 1311 } else { 1312 shprintf("%s alias not found\n", alias); 1313 rv = 1; 1314 } 1315 continue; 1316 } 1317 ap = ktenter(t, alias, h); 1318 ap->type = tflag ? CTALIAS : CALIAS; 1319 /* Are we setting the value or just some flags? */ 1320 if ((val && !tflag) || (!val && tflag && !Uflag)) { 1321 if (ap->flag&ALLOC) { 1322 ap->flag &= ~(ALLOC|ISSET); 1323 afree(ap->val.s, APERM); 1324 } 1325 /* ignore values for -t (AT&T ksh does this) */ 1326 newval = tflag ? search(alias, path, X_OK, NULL) : val; 1327 if (newval) { 1328 strdupx(ap->val.s, newval, APERM); 1329 ap->flag |= ALLOC|ISSET; 1330 } else 1331 ap->flag &= ~ISSET; 1332 } 1333 ap->flag |= DEFINED; 1334 if (prefix == '+') 1335 ap->flag &= ~xflag; 1336 else 1337 ap->flag |= xflag; 1338 afree(xalias, ATEMP); 1339 } 1340 1341 return (rv); 1342 } 1343 1344 int 1345 c_unalias(const char **wp) 1346 { 1347 struct table *t = &aliases; 1348 struct tbl *ap; 1349 int optc, rv = 0; 1350 bool all = false; 1351 1352 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1) 1353 switch (optc) { 1354 case 'a': 1355 all = true; 1356 break; 1357 case 'd': 1358 #ifdef MKSH_NOPWNAM 1359 t = NULL; /* fix "unalias -dt" */ 1360 #else 1361 t = &homedirs; 1362 #endif 1363 break; 1364 case 't': 1365 t = &taliases; 1366 break; 1367 case '?': 1368 return (1); 1369 } 1370 #ifdef MKSH_NOPWNAM 1371 if (t == NULL) 1372 return (0); 1373 #endif 1374 wp += builtin_opt.optind; 1375 1376 for (; *wp != NULL; wp++) { 1377 ap = ktsearch(t, *wp, hash(*wp)); 1378 if (ap == NULL) { 1379 rv = 1; /* POSIX */ 1380 continue; 1381 } 1382 if (ap->flag&ALLOC) { 1383 ap->flag &= ~(ALLOC|ISSET); 1384 afree(ap->val.s, APERM); 1385 } 1386 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1387 } 1388 1389 if (all) { 1390 struct tstate ts; 1391 1392 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) { 1393 if (ap->flag&ALLOC) { 1394 ap->flag &= ~(ALLOC|ISSET); 1395 afree(ap->val.s, APERM); 1396 } 1397 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1398 } 1399 } 1400 1401 return (rv); 1402 } 1403 1404 int 1405 c_let(const char **wp) 1406 { 1407 int rv = 1; 1408 mksh_ari_t val; 1409 1410 if (wp[1] == NULL) /* AT&T ksh does this */ 1411 bi_errorf("no arguments"); 1412 else 1413 for (wp++; *wp; wp++) 1414 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) { 1415 rv = 2; /* distinguish error from zero result */ 1416 break; 1417 } else 1418 rv = val == 0; 1419 return (rv); 1420 } 1421 1422 int 1423 c_jobs(const char **wp) 1424 { 1425 int optc, flag = 0, nflag = 0, rv = 0; 1426 1427 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1) 1428 switch (optc) { 1429 case 'l': 1430 flag = 1; 1431 break; 1432 case 'p': 1433 flag = 2; 1434 break; 1435 case 'n': 1436 nflag = 1; 1437 break; 1438 case 'z': /* debugging: print zombies */ 1439 nflag = -1; 1440 break; 1441 case '?': 1442 return (1); 1443 } 1444 wp += builtin_opt.optind; 1445 if (!*wp) { 1446 if (j_jobs(NULL, flag, nflag)) 1447 rv = 1; 1448 } else { 1449 for (; *wp; wp++) 1450 if (j_jobs(*wp, flag, nflag)) 1451 rv = 1; 1452 } 1453 return (rv); 1454 } 1455 1456 #ifndef MKSH_UNEMPLOYED 1457 int 1458 c_fgbg(const char **wp) 1459 { 1460 bool bg = strcmp(*wp, "bg") == 0; 1461 int rv = 0; 1462 1463 if (!Flag(FMONITOR)) { 1464 bi_errorf("job control not enabled"); 1465 return (1); 1466 } 1467 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1468 return (1); 1469 wp += builtin_opt.optind; 1470 if (*wp) 1471 for (; *wp; wp++) 1472 rv = j_resume(*wp, bg); 1473 else 1474 rv = j_resume("%%", bg); 1475 return (bg ? 0 : rv); 1476 } 1477 #endif 1478 1479 /* format a single kill item */ 1480 static char * 1481 kill_fmt_entry(char *buf, int buflen, int i, const void *arg) 1482 { 1483 const struct kill_info *ki = (const struct kill_info *)arg; 1484 1485 i++; 1486 shf_snprintf(buf, buflen, "%*d %*s %s", 1487 ki->num_width, i, 1488 ki->name_width, sigtraps[i].name, 1489 sigtraps[i].mess); 1490 return (buf); 1491 } 1492 1493 int 1494 c_kill(const char **wp) 1495 { 1496 Trap *t = NULL; 1497 const char *p; 1498 bool lflag = false; 1499 int i, n, rv, sig; 1500 1501 /* assume old style options if -digits or -UPPERCASE */ 1502 if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) || 1503 ksh_isupper(p[1]))) { 1504 if (!(t = gettrap(p + 1, true))) { 1505 bi_errorf("bad signal '%s'", p + 1); 1506 return (1); 1507 } 1508 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; 1509 } else { 1510 int optc; 1511 1512 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1) 1513 switch (optc) { 1514 case 'l': 1515 lflag = true; 1516 break; 1517 case 's': 1518 if (!(t = gettrap(builtin_opt.optarg, true))) { 1519 bi_errorf("bad signal '%s'", 1520 builtin_opt.optarg); 1521 return (1); 1522 } 1523 break; 1524 case '?': 1525 return (1); 1526 } 1527 i = builtin_opt.optind; 1528 } 1529 if ((lflag && t) || (!wp[i] && !lflag)) { 1530 #ifndef MKSH_SMALL 1531 shf_puts("usage:\tkill [-s signame | -signum | -signame]" 1532 " { job | pid | pgrp } ...\n" 1533 "\tkill -l [exit_status ...]\n", shl_out); 1534 #endif 1535 bi_errorfz(); 1536 return (1); 1537 } 1538 1539 if (lflag) { 1540 if (wp[i]) { 1541 for (; wp[i]; i++) { 1542 if (!bi_getn(wp[i], &n)) 1543 return (1); 1544 if (n > 128 && n < 128 + NSIG) 1545 n -= 128; 1546 if (n > 0 && n < NSIG) 1547 shprintf("%s\n", sigtraps[n].name); 1548 else 1549 shprintf("%d\n", n); 1550 } 1551 } else { 1552 int w, j, mess_cols, mess_octs; 1553 struct kill_info ki; 1554 1555 for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10) 1556 ki.num_width++; 1557 ki.name_width = mess_cols = mess_octs = 0; 1558 for (j = 0; j < NSIG; j++) { 1559 w = strlen(sigtraps[j].name); 1560 if (w > ki.name_width) 1561 ki.name_width = w; 1562 w = strlen(sigtraps[j].mess); 1563 if (w > mess_octs) 1564 mess_octs = w; 1565 w = utf_mbswidth(sigtraps[j].mess); 1566 if (w > mess_cols) 1567 mess_cols = w; 1568 } 1569 1570 print_columns(shl_stdout, NSIG - 1, 1571 kill_fmt_entry, (void *)&ki, 1572 ki.num_width + 1 + ki.name_width + 1 + mess_octs, 1573 ki.num_width + 1 + ki.name_width + 1 + mess_cols, 1574 true); 1575 } 1576 return (0); 1577 } 1578 rv = 0; 1579 sig = t ? t->signal : SIGTERM; 1580 for (; (p = wp[i]); i++) { 1581 if (*p == '%') { 1582 if (j_kill(p, sig)) 1583 rv = 1; 1584 } else if (!getn(p, &n)) { 1585 bi_errorf("%s: arguments must be jobs or process IDs", 1586 p); 1587 rv = 1; 1588 } else { 1589 if (mksh_kill(n, sig) < 0) { 1590 bi_errorf("%s: %s", p, strerror(errno)); 1591 rv = 1; 1592 } 1593 } 1594 } 1595 return (rv); 1596 } 1597 1598 void 1599 getopts_reset(int val) 1600 { 1601 if (val >= 1) { 1602 ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT); 1603 user_opt.optind = user_opt.uoptind = val; 1604 } 1605 } 1606 1607 int 1608 c_getopts(const char **wp) 1609 { 1610 int argc, optc, rv; 1611 const char *opts, *var; 1612 char buf[3]; 1613 struct tbl *vq, *voptarg; 1614 1615 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1616 return (1); 1617 wp += builtin_opt.optind; 1618 1619 opts = *wp++; 1620 if (!opts) { 1621 bi_errorf("missing options argument"); 1622 return (1); 1623 } 1624 1625 var = *wp++; 1626 if (!var) { 1627 bi_errorf("missing name argument"); 1628 return (1); 1629 } 1630 if (!*var || *skip_varname(var, true)) { 1631 bi_errorf("%s: is not an identifier", var); 1632 return (1); 1633 } 1634 1635 if (e->loc->next == NULL) { 1636 internal_warningf("c_getopts: no argv"); 1637 return (1); 1638 } 1639 /* Which arguments are we parsing... */ 1640 if (*wp == NULL) 1641 wp = e->loc->next->argv; 1642 else 1643 *--wp = e->loc->next->argv[0]; 1644 1645 /* Check that our saved state won't cause a core dump... */ 1646 for (argc = 0; wp[argc]; argc++) 1647 ; 1648 if (user_opt.optind > argc || 1649 (user_opt.p != 0 && 1650 user_opt.p > strlen(wp[user_opt.optind - 1]))) { 1651 bi_errorf("arguments changed since last call"); 1652 return (1); 1653 } 1654 1655 user_opt.optarg = NULL; 1656 optc = ksh_getopt(wp, &user_opt, opts); 1657 1658 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { 1659 buf[0] = '+'; 1660 buf[1] = optc; 1661 buf[2] = '\0'; 1662 } else { 1663 /* POSIX says var is set to ? at end-of-options, AT&T ksh 1664 * sets it to null - we go with POSIX... 1665 */ 1666 buf[0] = optc < 0 ? '?' : optc; 1667 buf[1] = '\0'; 1668 } 1669 1670 /* AT&T ksh93 in fact does change OPTIND for unknown options too */ 1671 user_opt.uoptind = user_opt.optind; 1672 1673 voptarg = global("OPTARG"); 1674 voptarg->flag &= ~RDONLY; /* AT&T ksh clears ro and int */ 1675 /* Paranoia: ensure no bizarre results. */ 1676 if (voptarg->flag & INTEGER) 1677 typeset("OPTARG", 0, INTEGER, 0, 0); 1678 if (user_opt.optarg == NULL) 1679 unset(voptarg, 1); 1680 else 1681 /* This can't fail (have cleared readonly/integer) */ 1682 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); 1683 1684 rv = 0; 1685 1686 vq = global(var); 1687 /* Error message already printed (integer, readonly) */ 1688 if (!setstr(vq, buf, KSH_RETURN_ERROR)) 1689 rv = 1; 1690 if (Flag(FEXPORT)) 1691 typeset(var, EXPORT, 0, 0, 0); 1692 1693 return (optc < 0 ? 1 : rv); 1694 } 1695 1696 int 1697 c_bind(const char **wp) 1698 { 1699 int optc, rv = 0; 1700 #ifndef MKSH_SMALL 1701 bool macro = false; 1702 #endif 1703 bool list = false; 1704 const char *cp; 1705 char *up; 1706 1707 while ((optc = ksh_getopt(wp, &builtin_opt, 1708 #ifndef MKSH_SMALL 1709 "lm" 1710 #else 1711 "l" 1712 #endif 1713 )) != -1) 1714 switch (optc) { 1715 case 'l': 1716 list = true; 1717 break; 1718 #ifndef MKSH_SMALL 1719 case 'm': 1720 macro = true; 1721 break; 1722 #endif 1723 case '?': 1724 return (1); 1725 } 1726 wp += builtin_opt.optind; 1727 1728 if (*wp == NULL) /* list all */ 1729 rv = x_bind(NULL, NULL, 1730 #ifndef MKSH_SMALL 1731 false, 1732 #endif 1733 list); 1734 1735 for (; *wp != NULL; wp++) { 1736 if ((cp = cstrchr(*wp, '=')) == NULL) 1737 up = NULL; 1738 else { 1739 strdupx(up, *wp, ATEMP); 1740 up[cp++ - *wp] = '\0'; 1741 } 1742 if (x_bind(up ? up : *wp, cp, 1743 #ifndef MKSH_SMALL 1744 macro, 1745 #endif 1746 false)) 1747 rv = 1; 1748 afree(up, ATEMP); 1749 } 1750 1751 return (rv); 1752 } 1753 1754 /* :, false and true (and ulimit if MKSH_NO_LIMITS) */ 1755 int 1756 c_label(const char **wp) 1757 { 1758 return (wp[0][0] == 'f' ? 1 : 0); 1759 } 1760 1761 int 1762 c_shift(const char **wp) 1763 { 1764 struct block *l = e->loc; 1765 int n; 1766 mksh_ari_t val; 1767 const char *arg; 1768 1769 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1770 return (1); 1771 arg = wp[builtin_opt.optind]; 1772 1773 if (arg) { 1774 evaluate(arg, &val, KSH_UNWIND_ERROR, false); 1775 n = val; 1776 } else 1777 n = 1; 1778 if (n < 0) { 1779 bi_errorf("%s: bad number", arg); 1780 return (1); 1781 } 1782 if (l->argc < n) { 1783 bi_errorf("nothing to shift"); 1784 return (1); 1785 } 1786 l->argv[n] = l->argv[0]; 1787 l->argv += n; 1788 l->argc -= n; 1789 return (0); 1790 } 1791 1792 int 1793 c_umask(const char **wp) 1794 { 1795 int i, optc; 1796 const char *cp; 1797 bool symbolic = false; 1798 mode_t old_umask; 1799 1800 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1) 1801 switch (optc) { 1802 case 'S': 1803 symbolic = true; 1804 break; 1805 case '?': 1806 return (1); 1807 } 1808 cp = wp[builtin_opt.optind]; 1809 if (cp == NULL) { 1810 old_umask = umask((mode_t)0); 1811 umask(old_umask); 1812 if (symbolic) { 1813 char buf[18], *p; 1814 int j; 1815 1816 old_umask = ~old_umask; 1817 p = buf; 1818 for (i = 0; i < 3; i++) { 1819 *p++ = "ugo"[i]; 1820 *p++ = '='; 1821 for (j = 0; j < 3; j++) 1822 if (old_umask & (1 << (8 - (3*i + j)))) 1823 *p++ = "rwx"[j]; 1824 *p++ = ','; 1825 } 1826 p[-1] = '\0'; 1827 shprintf("%s\n", buf); 1828 } else 1829 shprintf("%#3.3o\n", (unsigned int)old_umask); 1830 } else { 1831 mode_t new_umask; 1832 1833 if (ksh_isdigit(*cp)) { 1834 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) 1835 new_umask = new_umask * 8 + (*cp - '0'); 1836 if (*cp) { 1837 bi_errorf("bad number"); 1838 return (1); 1839 } 1840 } else { 1841 /* symbolic format */ 1842 int positions, new_val; 1843 char op; 1844 1845 old_umask = umask((mode_t)0); 1846 umask(old_umask); /* in case of error */ 1847 old_umask = ~old_umask; 1848 new_umask = old_umask; 1849 positions = 0; 1850 while (*cp) { 1851 while (*cp && vstrchr("augo", *cp)) 1852 switch (*cp++) { 1853 case 'a': 1854 positions |= 0111; 1855 break; 1856 case 'u': 1857 positions |= 0100; 1858 break; 1859 case 'g': 1860 positions |= 0010; 1861 break; 1862 case 'o': 1863 positions |= 0001; 1864 break; 1865 } 1866 if (!positions) 1867 positions = 0111; /* default is a */ 1868 if (!vstrchr("=+-", op = *cp)) 1869 break; 1870 cp++; 1871 new_val = 0; 1872 while (*cp && vstrchr("rwxugoXs", *cp)) 1873 switch (*cp++) { 1874 case 'r': new_val |= 04; break; 1875 case 'w': new_val |= 02; break; 1876 case 'x': new_val |= 01; break; 1877 case 'u': 1878 new_val |= old_umask >> 6; 1879 break; 1880 case 'g': 1881 new_val |= old_umask >> 3; 1882 break; 1883 case 'o': 1884 new_val |= old_umask >> 0; 1885 break; 1886 case 'X': 1887 if (old_umask & 0111) 1888 new_val |= 01; 1889 break; 1890 case 's': 1891 /* ignored */ 1892 break; 1893 } 1894 new_val = (new_val & 07) * positions; 1895 switch (op) { 1896 case '-': 1897 new_umask &= ~new_val; 1898 break; 1899 case '=': 1900 new_umask = new_val | 1901 (new_umask & ~(positions * 07)); 1902 break; 1903 case '+': 1904 new_umask |= new_val; 1905 } 1906 if (*cp == ',') { 1907 positions = 0; 1908 cp++; 1909 } else if (!vstrchr("=+-", *cp)) 1910 break; 1911 } 1912 if (*cp) { 1913 bi_errorf("bad mask"); 1914 return (1); 1915 } 1916 new_umask = ~new_umask; 1917 } 1918 umask(new_umask); 1919 } 1920 return (0); 1921 } 1922 1923 int 1924 c_dot(const char **wp) 1925 { 1926 const char *file, *cp, **argv; 1927 int argc, i, errcode; 1928 1929 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1930 return (1); 1931 1932 if ((cp = wp[builtin_opt.optind]) == NULL) { 1933 bi_errorf("missing argument"); 1934 return (1); 1935 } 1936 if ((file = search(cp, path, R_OK, &errcode)) == NULL) { 1937 bi_errorf("%s: %s", cp, 1938 errcode ? strerror(errcode) : "not found"); 1939 return (1); 1940 } 1941 1942 /* Set positional parameters? */ 1943 if (wp[builtin_opt.optind + 1]) { 1944 argv = wp + builtin_opt.optind; 1945 argv[0] = e->loc->argv[0]; /* preserve $0 */ 1946 for (argc = 0; argv[argc + 1]; argc++) 1947 ; 1948 } else { 1949 argc = 0; 1950 argv = NULL; 1951 } 1952 if ((i = include(file, argc, argv, 0)) < 0) { 1953 /* should not happen */ 1954 bi_errorf("%s: %s", cp, strerror(errno)); 1955 return (1); 1956 } 1957 return (i); 1958 } 1959 1960 int 1961 c_wait(const char **wp) 1962 { 1963 int rv = 0, sig; 1964 1965 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1966 return (1); 1967 wp += builtin_opt.optind; 1968 if (*wp == NULL) { 1969 while (waitfor(NULL, &sig) >= 0) 1970 ; 1971 rv = sig; 1972 } else { 1973 for (; *wp; wp++) 1974 rv = waitfor(*wp, &sig); 1975 if (rv < 0) 1976 rv = sig ? sig : 127; /* magic exit code: bad job-id */ 1977 } 1978 return (rv); 1979 } 1980 1981 int 1982 c_read(const char **wp) 1983 { 1984 int c = 0, ecode = 0, fd = 0, optc; 1985 bool expande = true, historyr = false, expanding; 1986 const char *cp, *emsg; 1987 struct shf *shf; 1988 XString cs, xs = { NULL, NULL, 0, NULL}; 1989 struct tbl *vp; 1990 char *ccp, *xp = NULL, *wpalloc = NULL; 1991 static char REPLY[] = "REPLY"; 1992 1993 while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1) 1994 switch (optc) { 1995 case 'p': 1996 if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { 1997 bi_errorf("-p: %s", emsg); 1998 return (1); 1999 } 2000 break; 2001 case 'r': 2002 expande = false; 2003 break; 2004 case 's': 2005 historyr = true; 2006 break; 2007 case 'u': 2008 if (!*(cp = builtin_opt.optarg)) 2009 fd = 0; 2010 else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) { 2011 bi_errorf("-u: %s: %s", cp, emsg); 2012 return (1); 2013 } 2014 break; 2015 case '?': 2016 return (1); 2017 } 2018 wp += builtin_opt.optind; 2019 2020 if (*wp == NULL) 2021 *--wp = REPLY; 2022 2023 /* Since we can't necessarily seek backwards on non-regular files, 2024 * don't buffer them so we can't read too much. 2025 */ 2026 shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); 2027 2028 if ((cp = cstrchr(*wp, '?')) != NULL) { 2029 strdupx(wpalloc, *wp, ATEMP); 2030 wpalloc[cp - *wp] = '\0'; 2031 *wp = wpalloc; 2032 if (isatty(fd)) { 2033 /* AT&T ksh says it prints prompt on fd if it's open 2034 * for writing and is a tty, but it doesn't do it 2035 * (it also doesn't check the interactive flag, 2036 * as is indicated in the Kornshell book). 2037 */ 2038 shellf("%s", cp+1); 2039 } 2040 } 2041 2042 /* If we are reading from the co-process for the first time, 2043 * make sure the other side of the pipe is closed first. This allows 2044 * the detection of eof. 2045 * 2046 * This is not compatible with AT&T ksh... the fd is kept so another 2047 * coproc can be started with same output, however, this means eof 2048 * can't be detected... This is why it is closed here. 2049 * If this call is removed, remove the eof check below, too. 2050 * coproc_readw_close(fd); 2051 */ 2052 2053 if (historyr) 2054 Xinit(xs, xp, 128, ATEMP); 2055 expanding = false; 2056 Xinit(cs, ccp, 128, ATEMP); 2057 for (; *wp != NULL; wp++) { 2058 for (ccp = Xstring(cs, ccp); ; ) { 2059 if (c == '\n' || c == EOF) 2060 break; 2061 while (1) { 2062 c = shf_getc(shf); 2063 if (c == '\0') 2064 continue; 2065 if (c == EOF && shf_error(shf) && 2066 shf_errno(shf) == EINTR) { 2067 /* Was the offending signal one that 2068 * would normally kill a process? 2069 * If so, pretend the read was killed. 2070 */ 2071 ecode = fatal_trap_check(); 2072 2073 /* non fatal (eg, CHLD), carry on */ 2074 if (!ecode) { 2075 shf_clearerr(shf); 2076 continue; 2077 } 2078 } 2079 break; 2080 } 2081 if (historyr) { 2082 Xcheck(xs, xp); 2083 Xput(xs, xp, c); 2084 } 2085 Xcheck(cs, ccp); 2086 if (expanding) { 2087 expanding = false; 2088 if (c == '\n') { 2089 c = 0; 2090 if (Flag(FTALKING_I) && isatty(fd)) { 2091 /* set prompt in case this is 2092 * called from .profile or $ENV 2093 */ 2094 set_prompt(PS2, NULL); 2095 pprompt(prompt, 0); 2096 } 2097 } else if (c != EOF) 2098 Xput(cs, ccp, c); 2099 continue; 2100 } 2101 if (expande && c == '\\') { 2102 expanding = true; 2103 continue; 2104 } 2105 if (c == '\n' || c == EOF) 2106 break; 2107 if (ctype(c, C_IFS)) { 2108 if (Xlength(cs, ccp) == 0 && ctype(c, C_IFSWS)) 2109 continue; 2110 if (wp[1]) 2111 break; 2112 } 2113 Xput(cs, ccp, c); 2114 } 2115 /* strip trailing IFS white space from last variable */ 2116 if (!wp[1]) 2117 while (Xlength(cs, ccp) && ctype(ccp[-1], C_IFS) && 2118 ctype(ccp[-1], C_IFSWS)) 2119 ccp--; 2120 Xput(cs, ccp, '\0'); 2121 vp = global(*wp); 2122 /* Must be done before setting export. */ 2123 if (vp->flag & RDONLY) { 2124 shf_flush(shf); 2125 bi_errorf("%s is read only", *wp); 2126 afree(wpalloc, ATEMP); 2127 return (1); 2128 } 2129 if (Flag(FEXPORT)) 2130 typeset(*wp, EXPORT, 0, 0, 0); 2131 if (!setstr(vp, Xstring(cs, ccp), KSH_RETURN_ERROR)) { 2132 shf_flush(shf); 2133 afree(wpalloc, ATEMP); 2134 return (1); 2135 } 2136 } 2137 2138 shf_flush(shf); 2139 if (historyr) { 2140 Xput(xs, xp, '\0'); 2141 histsave(&source->line, Xstring(xs, xp), true, false); 2142 Xfree(xs, xp); 2143 } 2144 /* if this is the co-process fd, close the file descriptor 2145 * (can get eof if and only if all processes are have died, ie, 2146 * coproc.njobs is 0 and the pipe is closed). 2147 */ 2148 if (c == EOF && !ecode) 2149 coproc_read_close(fd); 2150 2151 afree(wpalloc, ATEMP); 2152 return (ecode ? ecode : c == EOF); 2153 } 2154 2155 int 2156 c_eval(const char **wp) 2157 { 2158 struct source *s, *saves = source; 2159 unsigned char savef; 2160 int rv; 2161 2162 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2163 return (1); 2164 s = pushs(SWORDS, ATEMP); 2165 s->u.strv = wp + builtin_opt.optind; 2166 2167 /*- 2168 * The following code handles the case where the command is 2169 * empty due to failed command substitution, for example by 2170 * eval "$(false)" 2171 * This has historically returned 1 by AT&T ksh88. In this 2172 * case, shell() will not set or change exstat because the 2173 * compiled tree is empty, so it will use the value we pass 2174 * from subst_exstat, which is cleared in execute(), so it 2175 * should have been 0 if there were no substitutions. 2176 * 2177 * POSIX however says we don't do this, even though it is 2178 * traditionally done. AT&T ksh93 agrees with POSIX, so we 2179 * do. The following is an excerpt from SUSv4 [1003.2-2008]: 2180 * 2181 * 2.9.1: Simple Commands 2182 * ... If there is a command name, execution shall 2183 * continue as described in 2.9.1.1 [Command Search 2184 * and Execution]. If there is no command name, but 2185 * the command contained a command substitution, the 2186 * command shall complete with the exit status of the 2187 * last command substitution performed. 2188 * 2.9.1.1: Command Search and Execution 2189 * (1) a. If the command name matches the name of a 2190 * special built-in utility, that special built-in 2191 * utility shall be invoked. 2192 * 2.14.5: eval 2193 * If there are no arguments, or only null arguments, 2194 * eval shall return a zero exit status; ... 2195 */ 2196 /* exstat = subst_exstat; */ /* AT&T ksh88 */ 2197 exstat = 0; /* SUSv4 */ 2198 2199 savef = Flag(FERREXIT); 2200 Flag(FERREXIT) = 0; 2201 rv = shell(s, false); 2202 Flag(FERREXIT) = savef; 2203 source = saves; 2204 afree(s, ATEMP); 2205 return (rv); 2206 } 2207 2208 int 2209 c_trap(const char **wp) 2210 { 2211 int i; 2212 const char *s; 2213 Trap *p; 2214 2215 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2216 return (1); 2217 wp += builtin_opt.optind; 2218 2219 if (*wp == NULL) { 2220 for (p = sigtraps, i = NSIG+1; --i >= 0; p++) 2221 if (p->trap != NULL) { 2222 shf_puts("trap -- ", shl_stdout); 2223 print_value_quoted(p->trap); 2224 shprintf(" %s\n", p->name); 2225 } 2226 return (0); 2227 } 2228 2229 /* 2230 * Use case sensitive lookup for first arg so the 2231 * command 'exit' isn't confused with the pseudo-signal 2232 * 'EXIT'. 2233 */ 2234 s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; /* get command */ 2235 if (s != NULL && s[0] == '-' && s[1] == '\0') 2236 s = NULL; 2237 2238 /* set/clear traps */ 2239 while (*wp != NULL) { 2240 p = gettrap(*wp++, true); 2241 if (p == NULL) { 2242 bi_errorf("bad signal %s", wp[-1]); 2243 return (1); 2244 } 2245 settrap(p, s); 2246 } 2247 return (0); 2248 } 2249 2250 int 2251 c_exitreturn(const char **wp) 2252 { 2253 int n, how = LEXIT; 2254 const char *arg; 2255 2256 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2257 return (1); 2258 arg = wp[builtin_opt.optind]; 2259 2260 if (arg) { 2261 if (!getn(arg, &n)) { 2262 exstat = 1; 2263 warningf(true, "%s: bad number", arg); 2264 } else 2265 exstat = n; 2266 } 2267 if (wp[0][0] == 'r') { /* return */ 2268 struct env *ep; 2269 2270 /* need to tell if this is exit or return so trap exit will 2271 * work right (POSIX) 2272 */ 2273 for (ep = e; ep; ep = ep->oenv) 2274 if (STOP_RETURN(ep->type)) { 2275 how = LRETURN; 2276 break; 2277 } 2278 } 2279 2280 if (how == LEXIT && !really_exit && j_stopped_running()) { 2281 really_exit = 1; 2282 how = LSHELL; 2283 } 2284 2285 quitenv(NULL); /* get rid of any i/o redirections */ 2286 unwind(how); 2287 /* NOTREACHED */ 2288 } 2289 2290 int 2291 c_brkcont(const char **wp) 2292 { 2293 int n, quit; 2294 struct env *ep, *last_ep = NULL; 2295 const char *arg; 2296 2297 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2298 return (1); 2299 arg = wp[builtin_opt.optind]; 2300 2301 if (!arg) 2302 n = 1; 2303 else if (!bi_getn(arg, &n)) 2304 return (1); 2305 quit = n; 2306 if (quit <= 0) { 2307 /* AT&T ksh does this for non-interactive shells only - weird */ 2308 bi_errorf("%s: bad value", arg); 2309 return (1); 2310 } 2311 2312 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ 2313 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) 2314 if (ep->type == E_LOOP) { 2315 if (--quit == 0) 2316 break; 2317 ep->flags |= EF_BRKCONT_PASS; 2318 last_ep = ep; 2319 } 2320 2321 if (quit) { 2322 /* AT&T ksh doesn't print a message - just does what it 2323 * can. We print a message 'cause it helps in debugging 2324 * scripts, but don't generate an error (ie, keep going). 2325 */ 2326 if (n == quit) { 2327 warningf(true, "%s: cannot %s", wp[0], wp[0]); 2328 return (0); 2329 } 2330 /* POSIX says if n is too big, the last enclosing loop 2331 * shall be used. Doesn't say to print an error but we 2332 * do anyway 'cause the user messed up. 2333 */ 2334 if (last_ep) 2335 last_ep->flags &= ~EF_BRKCONT_PASS; 2336 warningf(true, "%s: can only %s %d level(s)", 2337 wp[0], wp[0], n - quit); 2338 } 2339 2340 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); 2341 /* NOTREACHED */ 2342 } 2343 2344 int 2345 c_set(const char **wp) 2346 { 2347 int argi; 2348 bool setargs; 2349 struct block *l = e->loc; 2350 const char **owp; 2351 2352 if (wp[1] == NULL) { 2353 static const char *args[] = { "set", "-", NULL }; 2354 return (c_typeset(args)); 2355 } 2356 2357 argi = parse_args(wp, OF_SET, &setargs); 2358 if (argi < 0) 2359 return (1); 2360 /* set $# and $* */ 2361 if (setargs) { 2362 wp += argi - 1; 2363 owp = wp; 2364 wp[0] = l->argv[0]; /* save $0 */ 2365 while (*++wp != NULL) 2366 strdupx(*wp, *wp, &l->area); 2367 l->argc = wp - owp - 1; 2368 l->argv = alloc((l->argc + 2) * sizeof(char *), &l->area); 2369 for (wp = l->argv; (*wp++ = *owp++) != NULL; ) 2370 ; 2371 } 2372 /*- 2373 * POSIX says set exit status is 0, but old scripts that use 2374 * getopt(1) use the construct 2375 * set -- $(getopt ab:c "$@") 2376 * which assumes the exit value set will be that of the $() 2377 * (subst_exstat is cleared in execute() so that it will be 0 2378 * if there are no command substitutions). 2379 * Switched ksh (!posix !sh) to POSIX in mksh R39b. 2380 */ 2381 return (Flag(FSH) ? subst_exstat : 0); 2382 } 2383 2384 int 2385 c_unset(const char **wp) 2386 { 2387 const char *id; 2388 int optc; 2389 bool unset_var = true; 2390 2391 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1) 2392 switch (optc) { 2393 case 'f': 2394 unset_var = false; 2395 break; 2396 case 'v': 2397 unset_var = true; 2398 break; 2399 case '?': 2400 return (1); 2401 } 2402 wp += builtin_opt.optind; 2403 for (; (id = *wp) != NULL; wp++) 2404 if (unset_var) { /* unset variable */ 2405 struct tbl *vp; 2406 char *cp = NULL; 2407 size_t n; 2408 2409 n = strlen(id); 2410 if (n > 3 && id[n-3] == '[' && id[n-2] == '*' && 2411 id[n-1] == ']') { 2412 strndupx(cp, id, n - 3, ATEMP); 2413 id = cp; 2414 optc = 3; 2415 } else 2416 optc = vstrchr(id, '[') ? 0 : 1; 2417 2418 vp = global(id); 2419 afree(cp, ATEMP); 2420 2421 if ((vp->flag&RDONLY)) { 2422 bi_errorf("%s is read only", vp->name); 2423 return (1); 2424 } 2425 unset(vp, optc); 2426 } else /* unset function */ 2427 define(id, NULL); 2428 return (0); 2429 } 2430 2431 static void 2432 p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width, 2433 const char *prefix, const char *suffix) 2434 { 2435 tv_usec /= 10000; 2436 if (posix) 2437 shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width, 2438 tv_sec, tv_usec, suffix); 2439 else 2440 shf_fprintf(shf, "%s%*ldm%d.%02ds%s", prefix, width, 2441 tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix); 2442 } 2443 2444 int 2445 c_times(const char **wp MKSH_A_UNUSED) 2446 { 2447 struct rusage usage; 2448 2449 getrusage(RUSAGE_SELF, &usage); 2450 p_time(shl_stdout, false, usage.ru_utime.tv_sec, 2451 usage.ru_utime.tv_usec, 0, null, " "); 2452 p_time(shl_stdout, false, usage.ru_stime.tv_sec, 2453 usage.ru_stime.tv_usec, 0, null, "\n"); 2454 2455 getrusage(RUSAGE_CHILDREN, &usage); 2456 p_time(shl_stdout, false, usage.ru_utime.tv_sec, 2457 usage.ru_utime.tv_usec, 0, null, " "); 2458 p_time(shl_stdout, false, usage.ru_stime.tv_sec, 2459 usage.ru_stime.tv_usec, 0, null, "\n"); 2460 2461 return (0); 2462 } 2463 2464 /* 2465 * time pipeline (really a statement, not a built-in command) 2466 */ 2467 int 2468 timex(struct op *t, int f, volatile int *xerrok) 2469 { 2470 #define TF_NOARGS BIT(0) 2471 #define TF_NOREAL BIT(1) /* don't report real time */ 2472 #define TF_POSIX BIT(2) /* report in POSIX format */ 2473 int rv = 0, tf = 0; 2474 struct rusage ru0, ru1, cru0, cru1; 2475 struct timeval usrtime, systime, tv0, tv1; 2476 2477 gettimeofday(&tv0, NULL); 2478 getrusage(RUSAGE_SELF, &ru0); 2479 getrusage(RUSAGE_CHILDREN, &cru0); 2480 if (t->left) { 2481 /* 2482 * Two ways of getting cpu usage of a command: just use t0 2483 * and t1 (which will get cpu usage from other jobs that 2484 * finish while we are executing t->left), or get the 2485 * cpu usage of t->left. AT&T ksh does the former, while 2486 * pdksh tries to do the later (the j_usrtime hack doesn't 2487 * really work as it only counts the last job). 2488 */ 2489 timerclear(&j_usrtime); 2490 timerclear(&j_systime); 2491 rv = execute(t->left, f | XTIME, xerrok); 2492 if (t->left->type == TCOM) 2493 tf |= t->left->str[0]; 2494 gettimeofday(&tv1, NULL); 2495 getrusage(RUSAGE_SELF, &ru1); 2496 getrusage(RUSAGE_CHILDREN, &cru1); 2497 } else 2498 tf = TF_NOARGS; 2499 2500 if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */ 2501 tf |= TF_NOREAL; 2502 timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime); 2503 timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime); 2504 } else { 2505 timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime); 2506 timeradd(&usrtime, &j_usrtime, &usrtime); 2507 timersub(&ru1.ru_stime, &ru0.ru_stime, &systime); 2508 timeradd(&systime, &j_systime, &systime); 2509 } 2510 2511 if (!(tf & TF_NOREAL)) { 2512 timersub(&tv1, &tv0, &tv1); 2513 if (tf & TF_POSIX) 2514 p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec, 2515 5, "real ", "\n"); 2516 else 2517 p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec, 2518 5, null, " real "); 2519 } 2520 if (tf & TF_POSIX) 2521 p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec, 2522 5, "user ", "\n"); 2523 else 2524 p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec, 2525 5, null, " user "); 2526 if (tf & TF_POSIX) 2527 p_time(shl_out, true, systime.tv_sec, systime.tv_usec, 2528 5, "sys ", "\n"); 2529 else 2530 p_time(shl_out, false, systime.tv_sec, systime.tv_usec, 2531 5, null, " system\n"); 2532 shf_flush(shl_out); 2533 2534 return (rv); 2535 } 2536 2537 void 2538 timex_hook(struct op *t, char **volatile *app) 2539 { 2540 char **wp = *app; 2541 int optc, i, j; 2542 Getopt opt; 2543 2544 ksh_getopt_reset(&opt, 0); 2545 opt.optind = 0; /* start at the start */ 2546 while ((optc = ksh_getopt((const char **)wp, &opt, ":p")) != -1) 2547 switch (optc) { 2548 case 'p': 2549 t->str[0] |= TF_POSIX; 2550 break; 2551 case '?': 2552 errorf("time: -%s unknown option", opt.optarg); 2553 case ':': 2554 errorf("time: -%s requires an argument", 2555 opt.optarg); 2556 } 2557 /* Copy command words down over options. */ 2558 if (opt.optind != 0) { 2559 for (i = 0; i < opt.optind; i++) 2560 afree(wp[i], ATEMP); 2561 for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++) 2562 ; 2563 } 2564 if (!wp[0]) 2565 t->str[0] |= TF_NOARGS; 2566 *app = wp; 2567 } 2568 2569 /* exec with no args - args case is taken care of in comexec() */ 2570 int 2571 c_exec(const char **wp MKSH_A_UNUSED) 2572 { 2573 int i; 2574 2575 /* make sure redirects stay in place */ 2576 if (e->savefd != NULL) { 2577 for (i = 0; i < NUFILE; i++) { 2578 if (e->savefd[i] > 0) 2579 close(e->savefd[i]); 2580 /* 2581 * keep all file descriptors > 2 private for ksh, 2582 * but not for POSIX or legacy/kludge sh 2583 */ 2584 if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 && 2585 e->savefd[i]) 2586 fcntl(i, F_SETFD, FD_CLOEXEC); 2587 } 2588 e->savefd = NULL; 2589 } 2590 return (0); 2591 } 2592 2593 #if HAVE_MKNOD 2594 int 2595 c_mknod(const char **wp) 2596 { 2597 int argc, optc, rv = 0; 2598 bool ismkfifo = false; 2599 const char **argv; 2600 void *set = NULL; 2601 mode_t mode = 0, oldmode = 0; 2602 2603 while ((optc = ksh_getopt(wp, &builtin_opt, "m:")) != -1) { 2604 switch (optc) { 2605 case 'm': 2606 set = setmode(builtin_opt.optarg); 2607 if (set == NULL) { 2608 bi_errorf("invalid file mode"); 2609 return (1); 2610 } 2611 mode = getmode(set, (mode_t)(DEFFILEMODE)); 2612 free(set); 2613 break; 2614 default: 2615 goto c_mknod_usage; 2616 } 2617 } 2618 argv = &wp[builtin_opt.optind]; 2619 if (argv[0] == NULL) 2620 goto c_mknod_usage; 2621 for (argc = 0; argv[argc]; argc++) 2622 ; 2623 if (argc == 2 && argv[1][0] == 'p') 2624 ismkfifo = true; 2625 else if (argc != 4 || (argv[1][0] != 'b' && argv[1][0] != 'c')) 2626 goto c_mknod_usage; 2627 2628 if (set != NULL) 2629 oldmode = umask((mode_t)0); 2630 else 2631 mode = DEFFILEMODE; 2632 2633 mode |= (argv[1][0] == 'b') ? S_IFBLK : 2634 (argv[1][0] == 'c') ? S_IFCHR : 0; 2635 2636 if (!ismkfifo) { 2637 unsigned long majnum, minnum; 2638 dev_t dv; 2639 char *c; 2640 2641 majnum = strtoul(argv[2], &c, 0); 2642 if ((c == argv[2]) || (*c != '\0')) { 2643 bi_errorf("non-numeric device major '%s'", argv[2]); 2644 goto c_mknod_err; 2645 } 2646 minnum = strtoul(argv[3], &c, 0); 2647 if ((c == argv[3]) || (*c != '\0')) { 2648 bi_errorf("non-numeric device minor '%s'", argv[3]); 2649 goto c_mknod_err; 2650 } 2651 dv = makedev(majnum, minnum); 2652 if ((unsigned long)(major(dv)) != majnum) { 2653 bi_errorf("device major too large: %lu", majnum); 2654 goto c_mknod_err; 2655 } 2656 if ((unsigned long)(minor(dv)) != minnum) { 2657 bi_errorf("device minor too large: %lu", minnum); 2658 goto c_mknod_err; 2659 } 2660 if (mknod(argv[0], mode, dv)) 2661 goto c_mknod_failed; 2662 } else if (mkfifo(argv[0], mode)) { 2663 c_mknod_failed: 2664 bi_errorf("%s: %s", *wp, strerror(errno)); 2665 c_mknod_err: 2666 rv = 1; 2667 } 2668 2669 if (set) 2670 umask(oldmode); 2671 return (rv); 2672 c_mknod_usage: 2673 bi_errorf("usage: mknod [-m mode] name b|c major minor"); 2674 bi_errorf("usage: mknod [-m mode] name p"); 2675 return (1); 2676 } 2677 #endif 2678 2679 /* dummy function, special case in comexec() */ 2680 int 2681 c_builtin(const char **wp MKSH_A_UNUSED) 2682 { 2683 return (0); 2684 } 2685 2686 /* test(1) accepts the following grammar: 2687 oexpr ::= aexpr | aexpr "-o" oexpr ; 2688 aexpr ::= nexpr | nexpr "-a" aexpr ; 2689 nexpr ::= primary | "!" nexpr ; 2690 primary ::= unary-operator operand 2691 | operand binary-operator operand 2692 | operand 2693 | "(" oexpr ")" 2694 ; 2695 2696 unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"| 2697 "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"| 2698 "-L"|"-h"|"-S"|"-H"; 2699 2700 binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 2701 "-nt"|"-ot"|"-ef"| 2702 "<"|">" # rules used for [[ .. ]] expressions 2703 ; 2704 operand ::= <any thing> 2705 */ 2706 2707 #define T_ERR_EXIT 2 /* POSIX says > 1 for errors */ 2708 2709 int 2710 c_test(const char **wp) 2711 { 2712 int argc, res; 2713 Test_env te; 2714 2715 te.flags = 0; 2716 te.isa = ptest_isa; 2717 te.getopnd = ptest_getopnd; 2718 te.eval = test_eval; 2719 te.error = ptest_error; 2720 2721 for (argc = 0; wp[argc]; argc++) 2722 ; 2723 2724 if (strcmp(wp[0], "[") == 0) { 2725 if (strcmp(wp[--argc], "]") != 0) { 2726 bi_errorf("missing ]"); 2727 return (T_ERR_EXIT); 2728 } 2729 } 2730 2731 te.pos.wp = wp + 1; 2732 te.wp_end = wp + argc; 2733 2734 /* 2735 * Handle the special cases from POSIX.2, section 4.62.4. 2736 * Implementation of all the rules isn't necessary since 2737 * our parser does the right thing for the omitted steps. 2738 */ 2739 if (argc <= 5) { 2740 const char **owp = wp; 2741 int invert = 0; 2742 Test_op op; 2743 const char *opnd1, *opnd2; 2744 2745 while (--argc >= 0) { 2746 if ((*te.isa)(&te, TM_END)) 2747 return (!0); 2748 if (argc == 3) { 2749 opnd1 = (*te.getopnd)(&te, TO_NONOP, 1); 2750 if ((op = (*te.isa)(&te, TM_BINOP))) { 2751 opnd2 = (*te.getopnd)(&te, op, 1); 2752 res = (*te.eval)(&te, op, opnd1, 2753 opnd2, 1); 2754 if (te.flags & TEF_ERROR) 2755 return (T_ERR_EXIT); 2756 if (invert & 1) 2757 res = !res; 2758 return (!res); 2759 } 2760 /* back up to opnd1 */ 2761 te.pos.wp--; 2762 } 2763 if (argc == 1) { 2764 opnd1 = (*te.getopnd)(&te, TO_NONOP, 1); 2765 if (strcmp(opnd1, "-t") == 0) 2766 break; 2767 res = (*te.eval)(&te, TO_STNZE, opnd1, 2768 NULL, 1); 2769 if (invert & 1) 2770 res = !res; 2771 return (!res); 2772 } 2773 if ((*te.isa)(&te, TM_NOT)) { 2774 invert++; 2775 } else 2776 break; 2777 } 2778 te.pos.wp = owp + 1; 2779 } 2780 2781 return (test_parse(&te)); 2782 } 2783 2784 /* 2785 * Generic test routines. 2786 */ 2787 2788 Test_op 2789 test_isop(Test_meta meta, const char *s) 2790 { 2791 char sc1; 2792 const struct t_op *tbl; 2793 2794 tbl = meta == TM_UNOP ? u_ops : b_ops; 2795 if (*s) { 2796 sc1 = s[1]; 2797 for (; tbl->op_text[0]; tbl++) 2798 if (sc1 == tbl->op_text[1] && !strcmp(s, tbl->op_text)) 2799 return (tbl->op_num); 2800 } 2801 return (TO_NONOP); 2802 } 2803 2804 int 2805 test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2, 2806 bool do_eval) 2807 { 2808 int i, s; 2809 size_t k; 2810 struct stat b1, b2; 2811 mksh_ari_t v1, v2; 2812 2813 if (!do_eval) 2814 return (0); 2815 2816 switch ((int)op) { 2817 /* 2818 * Unary Operators 2819 */ 2820 case TO_STNZE: /* -n */ 2821 return (*opnd1 != '\0'); 2822 case TO_STZER: /* -z */ 2823 return (*opnd1 == '\0'); 2824 case TO_OPTION: /* -o */ 2825 if ((i = *opnd1) == '!' || i == '?') 2826 opnd1++; 2827 if ((k = option(opnd1)) == (size_t)-1) 2828 return (0); 2829 return (i == '?' ? 1 : i == '!' ? !Flag(k) : Flag(k)); 2830 case TO_FILRD: /* -r */ 2831 return (test_eaccess(opnd1, R_OK) == 0); 2832 case TO_FILWR: /* -w */ 2833 return (test_eaccess(opnd1, W_OK) == 0); 2834 case TO_FILEX: /* -x */ 2835 return (test_eaccess(opnd1, X_OK) == 0); 2836 case TO_FILAXST: /* -a */ 2837 case TO_FILEXST: /* -e */ 2838 return (stat(opnd1, &b1) == 0); 2839 case TO_FILREG: /* -r */ 2840 return (stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode)); 2841 case TO_FILID: /* -d */ 2842 return (stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode)); 2843 case TO_FILCDEV: /* -c */ 2844 return (stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode)); 2845 case TO_FILBDEV: /* -b */ 2846 return (stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode)); 2847 case TO_FILFIFO: /* -p */ 2848 return (stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode)); 2849 case TO_FILSYM: /* -h -L */ 2850 return (lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode)); 2851 case TO_FILSOCK: /* -S */ 2852 return (stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode)); 2853 case TO_FILCDF:/* -H HP context dependent files (directories) */ 2854 return (0); 2855 case TO_FILSETU: /* -u */ 2856 return (stat(opnd1, &b1) == 0 && 2857 (b1.st_mode & S_ISUID) == S_ISUID); 2858 case TO_FILSETG: /* -g */ 2859 return (stat(opnd1, &b1) == 0 && 2860 (b1.st_mode & S_ISGID) == S_ISGID); 2861 case TO_FILSTCK: /* -k */ 2862 #ifdef S_ISVTX 2863 return (stat(opnd1, &b1) == 0 && 2864 (b1.st_mode & S_ISVTX) == S_ISVTX); 2865 #else 2866 return (0); 2867 #endif 2868 case TO_FILGZ: /* -s */ 2869 return (stat(opnd1, &b1) == 0 && b1.st_size > 0L); 2870 case TO_FILTT: /* -t */ 2871 if (opnd1 && !bi_getn(opnd1, &i)) { 2872 te->flags |= TEF_ERROR; 2873 i = 0; 2874 } else 2875 i = isatty(opnd1 ? i : 0); 2876 return (i); 2877 case TO_FILUID: /* -O */ 2878 return (stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid); 2879 case TO_FILGID: /* -G */ 2880 return (stat(opnd1, &b1) == 0 && b1.st_gid == getegid()); 2881 /* 2882 * Binary Operators 2883 */ 2884 case TO_STEQL: /* = */ 2885 if (te->flags & TEF_DBRACKET) 2886 return (gmatchx(opnd1, opnd2, false)); 2887 return (strcmp(opnd1, opnd2) == 0); 2888 case TO_STNEQ: /* != */ 2889 if (te->flags & TEF_DBRACKET) 2890 return (!gmatchx(opnd1, opnd2, false)); 2891 return (strcmp(opnd1, opnd2) != 0); 2892 case TO_STLT: /* < */ 2893 return (strcmp(opnd1, opnd2) < 0); 2894 case TO_STGT: /* > */ 2895 return (strcmp(opnd1, opnd2) > 0); 2896 case TO_INTEQ: /* -eq */ 2897 case TO_INTNE: /* -ne */ 2898 case TO_INTGE: /* -ge */ 2899 case TO_INTGT: /* -gt */ 2900 case TO_INTLE: /* -le */ 2901 case TO_INTLT: /* -lt */ 2902 if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) || 2903 !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) { 2904 /* error already printed.. */ 2905 te->flags |= TEF_ERROR; 2906 return (1); 2907 } 2908 switch ((int)op) { 2909 case TO_INTEQ: 2910 return (v1 == v2); 2911 case TO_INTNE: 2912 return (v1 != v2); 2913 case TO_INTGE: 2914 return (v1 >= v2); 2915 case TO_INTGT: 2916 return (v1 > v2); 2917 case TO_INTLE: 2918 return (v1 <= v2); 2919 case TO_INTLT: 2920 return (v1 < v2); 2921 } 2922 case TO_FILNT: /* -nt */ 2923 /* ksh88/ksh93 succeed if file2 can't be stated 2924 * (subtly different from 'does not exist'). 2925 */ 2926 return (stat(opnd1, &b1) == 0 && 2927 (((s = stat(opnd2, &b2)) == 0 && 2928 b1.st_mtime > b2.st_mtime) || s < 0)); 2929 case TO_FILOT: /* -ot */ 2930 /* ksh88/ksh93 succeed if file1 can't be stated 2931 * (subtly different from 'does not exist'). 2932 */ 2933 return (stat(opnd2, &b2) == 0 && 2934 (((s = stat(opnd1, &b1)) == 0 && 2935 b1.st_mtime < b2.st_mtime) || s < 0)); 2936 case TO_FILEQ: /* -ef */ 2937 return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 && 2938 b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino); 2939 } 2940 (*te->error)(te, 0, "internal error: unknown op"); 2941 return (1); 2942 } 2943 2944 /* On most/all unixen, access() says everything is executable for root... */ 2945 static int 2946 test_eaccess(const char *pathl, int mode) 2947 { 2948 int rv; 2949 2950 if ((rv = access(pathl, mode)) == 0 && ksheuid == 0 && (mode & X_OK)) { 2951 struct stat statb; 2952 2953 if (stat(pathl, &statb) < 0) 2954 rv = -1; 2955 else if (S_ISDIR(statb.st_mode)) 2956 rv = 0; 2957 else 2958 rv = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ? 2959 0 : -1; 2960 } 2961 return (rv); 2962 } 2963 2964 int 2965 test_parse(Test_env *te) 2966 { 2967 int rv; 2968 2969 rv = test_oexpr(te, 1); 2970 2971 if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END)) 2972 (*te->error)(te, 0, "unexpected operator/operand"); 2973 2974 return ((te->flags & TEF_ERROR) ? T_ERR_EXIT : !rv); 2975 } 2976 2977 static int 2978 test_oexpr(Test_env *te, bool do_eval) 2979 { 2980 int rv; 2981 2982 if ((rv = test_aexpr(te, do_eval))) 2983 do_eval = false; 2984 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR)) 2985 return (test_oexpr(te, do_eval) || rv); 2986 return (rv); 2987 } 2988 2989 static int 2990 test_aexpr(Test_env *te, bool do_eval) 2991 { 2992 int rv; 2993 2994 if (!(rv = test_nexpr(te, do_eval))) 2995 do_eval = false; 2996 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND)) 2997 return (test_aexpr(te, do_eval) && rv); 2998 return (rv); 2999 } 3000 3001 static int 3002 test_nexpr(Test_env *te, bool do_eval) 3003 { 3004 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT)) 3005 return (!test_nexpr(te, do_eval)); 3006 return (test_primary(te, do_eval)); 3007 } 3008 3009 static int 3010 test_primary(Test_env *te, bool do_eval) 3011 { 3012 const char *opnd1, *opnd2; 3013 int rv; 3014 Test_op op; 3015 3016 if (te->flags & TEF_ERROR) 3017 return (0); 3018 if ((*te->isa)(te, TM_OPAREN)) { 3019 rv = test_oexpr(te, do_eval); 3020 if (te->flags & TEF_ERROR) 3021 return (0); 3022 if (!(*te->isa)(te, TM_CPAREN)) { 3023 (*te->error)(te, 0, "missing closing paren"); 3024 return (0); 3025 } 3026 return (rv); 3027 } 3028 /* 3029 * Binary should have precedence over unary in this case 3030 * so that something like test \( -f = -f \) is accepted 3031 */ 3032 if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end && 3033 !test_isop(TM_BINOP, te->pos.wp[1]))) { 3034 if ((op = (*te->isa)(te, TM_UNOP))) { 3035 /* unary expression */ 3036 opnd1 = (*te->getopnd)(te, op, do_eval); 3037 if (!opnd1) { 3038 (*te->error)(te, -1, "missing argument"); 3039 return (0); 3040 } 3041 3042 return ((*te->eval)(te, op, opnd1, NULL, do_eval)); 3043 } 3044 } 3045 opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval); 3046 if (!opnd1) { 3047 (*te->error)(te, 0, "expression expected"); 3048 return (0); 3049 } 3050 if ((op = (*te->isa)(te, TM_BINOP))) { 3051 /* binary expression */ 3052 opnd2 = (*te->getopnd)(te, op, do_eval); 3053 if (!opnd2) { 3054 (*te->error)(te, -1, "missing second argument"); 3055 return (0); 3056 } 3057 3058 return ((*te->eval)(te, op, opnd1, opnd2, do_eval)); 3059 } 3060 return ((*te->eval)(te, TO_STNZE, opnd1, NULL, do_eval)); 3061 } 3062 3063 /* 3064 * Plain test (test and [ .. ]) specific routines. 3065 */ 3066 3067 /* 3068 * Test if the current token is a whatever. Accepts the current token if 3069 * it is. Returns 0 if it is not, non-zero if it is (in the case of 3070 * TM_UNOP and TM_BINOP, the returned value is a Test_op). 3071 */ 3072 static Test_op 3073 ptest_isa(Test_env *te, Test_meta meta) 3074 { 3075 /* Order important - indexed by Test_meta values */ 3076 static const char *const tokens[] = { 3077 "-o", "-a", "!", "(", ")" 3078 }; 3079 Test_op rv; 3080 3081 if (te->pos.wp >= te->wp_end) 3082 return (meta == TM_END ? TO_NONNULL : TO_NONOP); 3083 3084 if (meta == TM_UNOP || meta == TM_BINOP) 3085 rv = test_isop(meta, *te->pos.wp); 3086 else if (meta == TM_END) 3087 rv = TO_NONOP; 3088 else 3089 rv = !strcmp(*te->pos.wp, tokens[(int)meta]) ? 3090 TO_NONNULL : TO_NONOP; 3091 3092 /* Accept the token? */ 3093 if (rv != TO_NONOP) 3094 te->pos.wp++; 3095 3096 return (rv); 3097 } 3098 3099 static const char * 3100 ptest_getopnd(Test_env *te, Test_op op, bool do_eval MKSH_A_UNUSED) 3101 { 3102 if (te->pos.wp >= te->wp_end) 3103 return (op == TO_FILTT ? "1" : NULL); 3104 return (*te->pos.wp++); 3105 } 3106 3107 static void 3108 ptest_error(Test_env *te, int ofs, const char *msg) 3109 { 3110 const char *op; 3111 3112 te->flags |= TEF_ERROR; 3113 if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs])) 3114 bi_errorf("%s: %s", op, msg); 3115 else 3116 bi_errorf("%s", msg); 3117 } 3118 3119 #ifndef MKSH_NO_LIMITS 3120 #define SOFT 0x1 3121 #define HARD 0x2 3122 3123 struct limits { 3124 const char *name; 3125 int resource; /* resource to get/set */ 3126 int factor; /* multiply by to get rlim_{cur,max} values */ 3127 char option; 3128 }; 3129 3130 static void print_ulimit(const struct limits *, int); 3131 static int set_ulimit(const struct limits *, const char *, int); 3132 3133 /* Magic to divine the 'm' and 'v' limits */ 3134 3135 #ifdef RLIMIT_AS 3136 #if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \ 3137 !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS) 3138 #define ULIMIT_V_IS_AS 3139 #elif defined(RLIMIT_VMEM) 3140 #if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS) 3141 #define ULIMIT_V_IS_AS 3142 #else 3143 #define ULIMIT_V_IS_VMEM 3144 #endif 3145 #endif 3146 #endif 3147 3148 #ifdef RLIMIT_RSS 3149 #ifdef ULIMIT_V_IS_VMEM 3150 #define ULIMIT_M_IS_RSS 3151 #elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS) 3152 #define ULIMIT_M_IS_VMEM 3153 #else 3154 #define ULIMIT_M_IS_RSS 3155 #endif 3156 #if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS) 3157 #undef ULIMIT_M_IS_RSS 3158 #endif 3159 #endif 3160 3161 #if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM) 3162 #define ULIMIT_V_IS_VMEM 3163 #endif 3164 3165 #if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \ 3166 (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS))) 3167 #define ULIMIT_M_IS_VMEM 3168 #endif 3169 3170 #if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \ 3171 (RLIMIT_VMEM == RLIMIT_AS) 3172 #undef ULIMIT_M_IS_VMEM 3173 #endif 3174 3175 3176 int 3177 c_ulimit(const char **wp) 3178 { 3179 static const struct limits limits[] = { 3180 /* do not use options -H, -S or -a or change the order */ 3181 #ifdef RLIMIT_CPU 3182 { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' }, 3183 #endif 3184 #ifdef RLIMIT_FSIZE 3185 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, 3186 #endif 3187 #ifdef RLIMIT_CORE 3188 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, 3189 #endif 3190 #ifdef RLIMIT_DATA 3191 { "data(KiB)", RLIMIT_DATA, 1024, 'd' }, 3192 #endif 3193 #ifdef RLIMIT_STACK 3194 { "stack(KiB)", RLIMIT_STACK, 1024, 's' }, 3195 #endif 3196 #ifdef RLIMIT_MEMLOCK 3197 { "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' }, 3198 #endif 3199 #ifdef RLIMIT_NOFILE 3200 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, 3201 #endif 3202 #ifdef RLIMIT_NPROC 3203 { "processes", RLIMIT_NPROC, 1, 'p' }, 3204 #endif 3205 #ifdef RLIMIT_SWAP 3206 { "swap(KiB)", RLIMIT_SWAP, 1024, 'w' }, 3207 #endif 3208 #ifdef RLIMIT_LOCKS 3209 { "flocks", RLIMIT_LOCKS, -1, 'L' }, 3210 #endif 3211 #ifdef RLIMIT_TIME 3212 { "humantime(seconds)", RLIMIT_TIME, 1, 'T' }, 3213 #endif 3214 #ifdef RLIMIT_NOVMON 3215 { "vnodemonitors", RLIMIT_NOVMON, 1, 'V' }, 3216 #endif 3217 #ifdef RLIMIT_SIGPENDING 3218 { "sigpending", RLIMIT_SIGPENDING, 1, 'i' }, 3219 #endif 3220 #ifdef RLIMIT_MSGQUEUE 3221 { "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' }, 3222 #endif 3223 #ifdef RLIMIT_AIO_MEM 3224 { "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' }, 3225 #endif 3226 #ifdef RLIMIT_AIO_OPS 3227 { "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' }, 3228 #endif 3229 #ifdef RLIMIT_TCACHE 3230 { "cachedthreads", RLIMIT_TCACHE, 1, 'C' }, 3231 #endif 3232 #ifdef RLIMIT_SBSIZE 3233 { "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' }, 3234 #endif 3235 #ifdef RLIMIT_PTHREAD 3236 { "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' }, 3237 #endif 3238 #ifdef RLIMIT_NICE 3239 { "maxnice", RLIMIT_NICE, 1, 'e' }, 3240 #endif 3241 #ifdef RLIMIT_RTPRIO 3242 { "maxrtprio", RLIMIT_RTPRIO, 1, 'r' }, 3243 #endif 3244 #if defined(ULIMIT_M_IS_RSS) 3245 { "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' }, 3246 #elif defined(ULIMIT_M_IS_VMEM) 3247 { "memory(KiB)", RLIMIT_VMEM, 1024, 'm' }, 3248 #endif 3249 #if defined(ULIMIT_V_IS_VMEM) 3250 { "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' }, 3251 #elif defined(ULIMIT_V_IS_AS) 3252 { "address-space(KiB)", RLIMIT_AS, 1024, 'v' }, 3253 #endif 3254 { NULL, 0, 0, 0 } 3255 }; 3256 static char opts[3 + NELEM(limits)]; 3257 int how = SOFT | HARD, optc, what = 'f'; 3258 bool all = false; 3259 const struct limits *l; 3260 3261 if (!opts[0]) { 3262 /* build options string on first call - yuck */ 3263 char *p = opts; 3264 3265 *p++ = 'H'; *p++ = 'S'; *p++ = 'a'; 3266 for (l = limits; l->name; l++) 3267 *p++ = l->option; 3268 *p = '\0'; 3269 } 3270 3271 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) 3272 switch (optc) { 3273 case 'H': 3274 how = HARD; 3275 break; 3276 case 'S': 3277 how = SOFT; 3278 break; 3279 case 'a': 3280 all = true; 3281 break; 3282 case '?': 3283 bi_errorf("usage: ulimit [-acdfHLlmnpSsTtvw] [value]"); 3284 return (1); 3285 default: 3286 what = optc; 3287 } 3288 3289 for (l = limits; l->name && l->option != what; l++) 3290 ; 3291 if (!l->name) { 3292 internal_warningf("ulimit: %c", what); 3293 return (1); 3294 } 3295 3296 if (wp[builtin_opt.optind]) { 3297 if (all || wp[builtin_opt.optind + 1]) { 3298 bi_errorf("too many arguments"); 3299 return (1); 3300 } 3301 return (set_ulimit(l, wp[builtin_opt.optind], how)); 3302 } 3303 if (!all) 3304 print_ulimit(l, how); 3305 else for (l = limits; l->name; l++) { 3306 shprintf("%-20s ", l->name); 3307 print_ulimit(l, how); 3308 } 3309 return (0); 3310 } 3311 3312 static int 3313 set_ulimit(const struct limits *l, const char *v, int how) 3314 { 3315 rlim_t val = (rlim_t)0; 3316 struct rlimit limit; 3317 3318 if (strcmp(v, "unlimited") == 0) 3319 val = (rlim_t)RLIM_INFINITY; 3320 else { 3321 mksh_ari_t rval; 3322 3323 if (!evaluate(v, &rval, KSH_RETURN_ERROR, false)) 3324 return (1); 3325 /* 3326 * Avoid problems caused by typos that evaluate misses due 3327 * to evaluating unset parameters to 0... 3328 * If this causes problems, will have to add parameter to 3329 * evaluate() to control if unset params are 0 or an error. 3330 */ 3331 if (!rval && !ksh_isdigit(v[0])) { 3332 bi_errorf("invalid %s limit: %s", l->name, v); 3333 return (1); 3334 } 3335 val = (rlim_t)((rlim_t)rval * l->factor); 3336 } 3337 3338 if (getrlimit(l->resource, &limit) < 0) { 3339 /* some cannot be read, e.g. Linux RLIMIT_LOCKS */ 3340 limit.rlim_cur = RLIM_INFINITY; 3341 limit.rlim_max = RLIM_INFINITY; 3342 } 3343 if (how & SOFT) 3344 limit.rlim_cur = val; 3345 if (how & HARD) 3346 limit.rlim_max = val; 3347 if (!setrlimit(l->resource, &limit)) 3348 return (0); 3349 if (errno == EPERM) 3350 bi_errorf("%s exceeds allowable %s limit", v, l->name); 3351 else 3352 bi_errorf("bad %s limit: %s", l->name, strerror(errno)); 3353 return (1); 3354 } 3355 3356 static void 3357 print_ulimit(const struct limits *l, int how) 3358 { 3359 rlim_t val = (rlim_t)0; 3360 struct rlimit limit; 3361 3362 if (getrlimit(l->resource, &limit)) { 3363 shf_puts("unknown\n", shl_stdout); 3364 return; 3365 } 3366 if (how & SOFT) 3367 val = limit.rlim_cur; 3368 else if (how & HARD) 3369 val = limit.rlim_max; 3370 if (val == (rlim_t)RLIM_INFINITY) 3371 shf_puts("unlimited\n", shl_stdout); 3372 else 3373 shprintf("%ld\n", (long)(val / l->factor)); 3374 } 3375 #endif 3376 3377 int 3378 c_rename(const char **wp) 3379 { 3380 int rv = 1; 3381 3382 if (wp == NULL /* argv */ || 3383 wp[0] == NULL /* name of builtin */ || 3384 wp[1] == NULL /* first argument */ || 3385 wp[2] == NULL /* second argument */ || 3386 wp[3] != NULL /* no further args please */) 3387 bi_errorf(T_synerr); 3388 else if ((rv = rename(wp[1], wp[2])) != 0) { 3389 rv = errno; 3390 bi_errorf("failed: %s", strerror(rv)); 3391 } 3392 3393 return (rv); 3394 } 3395 3396 int 3397 c_realpath(const char **wp) 3398 { 3399 int rv = 1; 3400 char *buf; 3401 3402 if (wp != NULL && wp[0] != NULL && wp[1] != NULL) { 3403 if (strcmp(wp[1], "--")) { 3404 if (wp[2] == NULL) { 3405 wp += 1; 3406 rv = 0; 3407 } 3408 } else { 3409 if (wp[2] != NULL && wp[3] == NULL) { 3410 wp += 2; 3411 rv = 0; 3412 } 3413 } 3414 } 3415 3416 if (rv) 3417 bi_errorf(T_synerr); 3418 else if ((buf = do_realpath(*wp)) == NULL) { 3419 rv = errno; 3420 bi_errorf("%s: %s", *wp, strerror(rv)); 3421 if ((unsigned int)rv > 255) 3422 rv = 255; 3423 } else { 3424 shprintf("%s\n", buf); 3425 afree(buf, ATEMP); 3426 } 3427 3428 return (rv); 3429 } 3430