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