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