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