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