1 /* $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */ 2 /* $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $ */ 3 /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ 4 /* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */ 5 6 /*- 7 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 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.238 2013/02/18 22:47: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 * a leading + means a POSIX regular builtin 90 * (* and + should not be combined). 91 */ 92 const struct builtin mkshbuiltins[] = { 93 {"*=.", c_dot}, 94 {"*=:", c_true}, 95 {"[", c_test}, 96 {"*=break", c_brkcont}, 97 {Tgbuiltin, c_builtin}, 98 {"*=continue", c_brkcont}, 99 {"*=eval", c_eval}, 100 {"*=exec", c_exec}, 101 {"*=exit", c_exitreturn}, 102 {"+false", c_false}, 103 {"*=return", c_exitreturn}, 104 {Tsgset, c_set}, 105 {"*=shift", c_shift}, 106 {"=times", c_times}, 107 {"*=trap", c_trap}, 108 {"+=wait", c_wait}, 109 {"+read", c_read}, 110 {"test", c_test}, 111 {"+true", c_true}, 112 {"ulimit", c_ulimit}, 113 {"+umask", c_umask}, 114 {Tsgunset, c_unset}, 115 /* no =: AT&T manual wrong */ 116 {Tpalias, c_alias}, 117 {"+cd", c_cd}, 118 /* dash compatibility hack */ 119 {"chdir", c_cd}, 120 {"+command", c_command}, 121 {"echo", c_print}, 122 {Tsgexport, c_typeset}, 123 {"+fc", c_fc}, 124 {"+getopts", c_getopts}, 125 {"=global", c_typeset}, 126 {"+jobs", c_jobs}, 127 {"+kill", c_kill}, 128 {"let", c_let}, 129 {"print", c_print}, 130 #ifdef MKSH_PRINTF_BUILTIN 131 {"printf", c_printf}, 132 #endif 133 {"pwd", c_pwd}, 134 {Tsgreadonly, c_typeset}, 135 {T_typeset, c_typeset}, 136 {Tpunalias, c_unalias}, 137 {"whence", c_whence}, 138 #ifndef MKSH_UNEMPLOYED 139 {"+bg", c_fgbg}, 140 {"+fg", c_fgbg}, 141 #endif 142 #ifndef MKSH_NO_CMDLINE_EDITING 143 {"bind", c_bind}, 144 #endif 145 {"cat", c_cat}, 146 #if HAVE_MKNOD 147 {"mknod", c_mknod}, 148 #endif 149 {"realpath", c_realpath}, 150 {"rename", c_rename}, 151 #if HAVE_SELECT 152 {"sleep", c_sleep}, 153 #endif 154 #ifdef __MirBSD__ 155 /* alias to "true" for historical reasons */ 156 {"domainname", c_true}, 157 #endif 158 {NULL, (int (*)(const char **))NULL} 159 }; 160 161 struct kill_info { 162 int num_width; 163 int name_width; 164 }; 165 166 static const struct t_op { 167 char op_text[4]; 168 Test_op op_num; 169 } u_ops[] = { 170 {"-a", TO_FILAXST }, 171 {"-b", TO_FILBDEV }, 172 {"-c", TO_FILCDEV }, 173 {"-d", TO_FILID }, 174 {"-e", TO_FILEXST }, 175 {"-f", TO_FILREG }, 176 {"-G", TO_FILGID }, 177 {"-g", TO_FILSETG }, 178 {"-h", TO_FILSYM }, 179 {"-H", TO_FILCDF }, 180 {"-k", TO_FILSTCK }, 181 {"-L", TO_FILSYM }, 182 {"-n", TO_STNZE }, 183 {"-O", TO_FILUID }, 184 {"-o", TO_OPTION }, 185 {"-p", TO_FILFIFO }, 186 {"-r", TO_FILRD }, 187 {"-s", TO_FILGZ }, 188 {"-S", TO_FILSOCK }, 189 {"-t", TO_FILTT }, 190 {"-u", TO_FILSETU }, 191 {"-w", TO_FILWR }, 192 {"-x", TO_FILEX }, 193 {"-z", TO_STZER }, 194 {"", TO_NONOP } 195 }; 196 static const struct t_op b_ops[] = { 197 {"=", TO_STEQL }, 198 {"==", TO_STEQL }, 199 {"!=", TO_STNEQ }, 200 {"<", TO_STLT }, 201 {">", TO_STGT }, 202 {"-eq", TO_INTEQ }, 203 {"-ne", TO_INTNE }, 204 {"-gt", TO_INTGT }, 205 {"-ge", TO_INTGE }, 206 {"-lt", TO_INTLT }, 207 {"-le", TO_INTLE }, 208 {"-ef", TO_FILEQ }, 209 {"-nt", TO_FILNT }, 210 {"-ot", TO_FILOT }, 211 {"", TO_NONOP } 212 }; 213 214 static int test_oexpr(Test_env *, bool); 215 static int test_aexpr(Test_env *, bool); 216 static int test_nexpr(Test_env *, bool); 217 static int test_primary(Test_env *, bool); 218 static Test_op ptest_isa(Test_env *, Test_meta); 219 static const char *ptest_getopnd(Test_env *, Test_op, bool); 220 static void ptest_error(Test_env *, int, const char *); 221 static char *kill_fmt_entry(char *, size_t, unsigned int, const void *); 222 static void p_time(struct shf *, bool, long, int, int, 223 const char *, const char *); 224 225 int 226 c_pwd(const char **wp) 227 { 228 int optc; 229 bool physical = tobool(Flag(FPHYSICAL)); 230 char *p, *allocd = NULL; 231 232 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) 233 switch (optc) { 234 case 'L': 235 physical = false; 236 break; 237 case 'P': 238 physical = true; 239 break; 240 case '?': 241 return (1); 242 } 243 wp += builtin_opt.optind; 244 245 if (wp[0]) { 246 bi_errorf("too many arguments"); 247 return (1); 248 } 249 p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) : 250 current_wd) : NULL; 251 /* LINTED use of access */ 252 if (p && access(p, R_OK) < 0) 253 p = NULL; 254 if (!p && !(p = allocd = ksh_get_wd())) { 255 bi_errorf("%s: %s", "can't determine current directory", 256 cstrerror(errno)); 257 return (1); 258 } 259 shprintf("%s\n", p); 260 afree(allocd, ATEMP); 261 return (0); 262 } 263 264 static const char *s_ptr; 265 static int s_get(void); 266 static void s_put(int); 267 268 int 269 c_print(const char **wp) 270 { 271 #define PO_NL BIT(0) /* print newline */ 272 #define PO_EXPAND BIT(1) /* expand backslash sequences */ 273 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */ 274 #define PO_HIST BIT(3) /* print to history instead of stdout */ 275 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ 276 int fd = 1, c; 277 int flags = PO_EXPAND | PO_NL; 278 const char *s, *emsg; 279 XString xs; 280 char *xp; 281 282 if (wp[0][0] == 'e') { 283 /* echo builtin */ 284 wp++; 285 #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT 286 if (Flag(FSH)) { 287 /* 288 * MidnightBSD /bin/sh needs a BSD echo, that is, 289 * one that supports -e but does not enable it by 290 * default 291 */ 292 flags = PO_NL; 293 } 294 #endif 295 if (Flag(FPOSIX) || 296 #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT 297 Flag(FSH) || 298 #endif 299 Flag(FAS_BUILTIN)) { 300 /* Debian Policy 10.4 compliant "echo" builtin */ 301 if (*wp && !strcmp(*wp, "-n")) { 302 /* we recognise "-n" only as the first arg */ 303 flags = 0; 304 wp++; 305 } else 306 /* otherwise, we print everything as-is */ 307 flags = PO_NL; 308 } else { 309 int nflags = flags; 310 311 /** 312 * a compromise between sysV and BSD echo commands: 313 * escape sequences are enabled by default, and -n, 314 * -e and -E are recognised if they appear in argu- 315 * ments with no illegal options (ie, echo -nq will 316 * print -nq). 317 * Different from sysV echo since options are reco- 318 * gnised, different from BSD echo since escape se- 319 * quences are enabled by default. 320 */ 321 322 while ((s = *wp) && *s == '-' && s[1]) { 323 while (*++s) 324 if (*s == 'n') 325 nflags &= ~PO_NL; 326 else if (*s == 'e') 327 nflags |= PO_EXPAND; 328 else if (*s == 'E') 329 nflags &= ~PO_EXPAND; 330 else 331 /* 332 * bad option: don't use 333 * nflags, print argument 334 */ 335 break; 336 337 if (*s) 338 break; 339 wp++; 340 flags = nflags; 341 } 342 } 343 } else { 344 int optc; 345 const char *opts = "Rnprsu,"; 346 347 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) 348 switch (optc) { 349 case 'R': 350 /* fake BSD echo command */ 351 flags |= PO_PMINUSMINUS; 352 flags &= ~PO_EXPAND; 353 opts = "ne"; 354 break; 355 case 'e': 356 flags |= PO_EXPAND; 357 break; 358 case 'n': 359 flags &= ~PO_NL; 360 break; 361 case 'p': 362 if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { 363 bi_errorf("%s: %s", "-p", emsg); 364 return (1); 365 } 366 break; 367 case 'r': 368 flags &= ~PO_EXPAND; 369 break; 370 case 's': 371 flags |= PO_HIST; 372 break; 373 case 'u': 374 if (!*(s = builtin_opt.optarg)) 375 fd = 0; 376 else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { 377 bi_errorf("%s: %s: %s", "-u", s, emsg); 378 return (1); 379 } 380 break; 381 case '?': 382 return (1); 383 } 384 385 if (!(builtin_opt.info & GI_MINUSMINUS)) { 386 /* treat a lone - like -- */ 387 if (wp[builtin_opt.optind] && 388 ksh_isdash(wp[builtin_opt.optind])) 389 builtin_opt.optind++; 390 } else if (flags & PO_PMINUSMINUS) 391 builtin_opt.optind--; 392 wp += builtin_opt.optind; 393 } 394 395 Xinit(xs, xp, 128, ATEMP); 396 397 while (*wp != NULL) { 398 s = *wp; 399 while ((c = *s++) != '\0') { 400 Xcheck(xs, xp); 401 if ((flags & PO_EXPAND) && c == '\\') { 402 s_ptr = s; 403 c = unbksl(false, s_get, s_put); 404 s = s_ptr; 405 if (c == -1) { 406 /* rejected by generic function */ 407 switch ((c = *s++)) { 408 case 'c': 409 flags &= ~PO_NL; 410 /* AT&T brain damage */ 411 continue; 412 case '\0': 413 s--; 414 c = '\\'; 415 break; 416 default: 417 Xput(xs, xp, '\\'); 418 } 419 } else if ((unsigned int)c > 0xFF) { 420 /* generic function returned Unicode */ 421 char ts[4]; 422 423 ts[utf_wctomb(ts, c - 0x100)] = 0; 424 for (c = 0; ts[c]; ++c) 425 Xput(xs, xp, ts[c]); 426 continue; 427 } 428 } 429 Xput(xs, xp, c); 430 } 431 if (*++wp != NULL) 432 Xput(xs, xp, ' '); 433 } 434 if (flags & PO_NL) 435 Xput(xs, xp, '\n'); 436 437 if (flags & PO_HIST) { 438 Xput(xs, xp, '\0'); 439 histsave(&source->line, Xstring(xs, xp), true, false); 440 Xfree(xs, xp); 441 } else { 442 int len = Xlength(xs, xp); 443 int opipe = 0; 444 445 /* 446 * Ensure we aren't killed by a SIGPIPE while writing to 447 * a coprocess. AT&T ksh doesn't seem to do this (seems 448 * to just check that the co-process is alive which is 449 * not enough). 450 */ 451 if (coproc.write >= 0 && coproc.write == fd) { 452 flags |= PO_COPROC; 453 opipe = block_pipe(); 454 } 455 for (s = Xstring(xs, xp); len > 0; ) { 456 if ((c = write(fd, s, len)) < 0) { 457 if (flags & PO_COPROC) 458 restore_pipe(opipe); 459 if (errno == EINTR) { 460 /* allow user to ^C out */ 461 intrcheck(); 462 if (flags & PO_COPROC) 463 opipe = block_pipe(); 464 continue; 465 } 466 return (1); 467 } 468 s += c; 469 len -= c; 470 } 471 if (flags & PO_COPROC) 472 restore_pipe(opipe); 473 } 474 475 return (0); 476 } 477 478 static int 479 s_get(void) 480 { 481 return (*s_ptr++); 482 } 483 484 static void 485 s_put(int c MKSH_A_UNUSED) 486 { 487 --s_ptr; 488 } 489 490 int 491 c_whence(const char **wp) 492 { 493 struct tbl *tp; 494 const char *id; 495 bool pflag = false, vflag = false, Vflag = false; 496 int rv = 0, optc, fcflags; 497 bool iam_whence = wp[0][0] == 'w'; 498 const char *opts = iam_whence ? "pv" : "pvV"; 499 500 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) 501 switch (optc) { 502 case 'p': 503 pflag = true; 504 break; 505 case 'v': 506 vflag = true; 507 break; 508 case 'V': 509 Vflag = true; 510 break; 511 case '?': 512 return (1); 513 } 514 wp += builtin_opt.optind; 515 516 fcflags = FC_BI | FC_PATH | FC_FUNC; 517 if (!iam_whence) { 518 /* Note that -p on its own is deal with in comexec() */ 519 if (pflag) 520 fcflags |= FC_DEFPATH; 521 /* 522 * Convert command options to whence options - note that 523 * command -pV uses a different path search than whence -v 524 * or whence -pv. This should be considered a feature. 525 */ 526 vflag = Vflag; 527 } 528 if (pflag) 529 fcflags &= ~(FC_BI | FC_FUNC); 530 531 while ((vflag || rv == 0) && (id = *wp++) != NULL) { 532 uint32_t h = 0; 533 534 tp = NULL; 535 if ((iam_whence || vflag) && !pflag) 536 tp = ktsearch(&keywords, id, h = hash(id)); 537 if (!tp && !pflag) { 538 tp = ktsearch(&aliases, id, h ? h : hash(id)); 539 if (tp && !(tp->flag & ISSET)) 540 tp = NULL; 541 } 542 if (!tp) 543 tp = findcom(id, fcflags); 544 if (vflag || (tp->type != CALIAS && tp->type != CEXEC && 545 tp->type != CTALIAS)) 546 shf_puts(id, shl_stdout); 547 if (vflag) 548 switch (tp->type) { 549 case CKEYWD: 550 case CALIAS: 551 case CFUNC: 552 case CSHELL: 553 shf_puts(" is a", shl_stdout); 554 break; 555 } 556 557 switch (tp->type) { 558 case CKEYWD: 559 if (vflag) 560 shf_puts(" reserved word", shl_stdout); 561 break; 562 case CALIAS: 563 if (vflag) 564 shprintf("n %s%s for ", 565 (tp->flag & EXPORT) ? "exported " : null, 566 Talias); 567 if (!iam_whence && !vflag) 568 shprintf("%s %s=", Talias, id); 569 print_value_quoted(shl_stdout, tp->val.s); 570 break; 571 case CFUNC: 572 if (vflag) { 573 if (tp->flag & EXPORT) 574 shf_puts("n exported", shl_stdout); 575 if (tp->flag & TRACE) 576 shf_puts(" traced", shl_stdout); 577 if (!(tp->flag & ISSET)) { 578 shf_puts(" undefined", shl_stdout); 579 if (tp->u.fpath) 580 shprintf(" (autoload from %s)", 581 tp->u.fpath); 582 } 583 shf_puts(T_function, shl_stdout); 584 } 585 break; 586 case CSHELL: 587 if (vflag) 588 shprintf("%s %s %s", 589 (tp->flag & SPEC_BI) ? " special" : null, 590 "shell", Tbuiltin); 591 break; 592 case CTALIAS: 593 case CEXEC: 594 if (tp->flag & ISSET) { 595 if (vflag) { 596 shf_puts(" is ", shl_stdout); 597 if (tp->type == CTALIAS) 598 shprintf("a tracked %s%s for ", 599 (tp->flag & EXPORT) ? 600 "exported " : null, 601 Talias); 602 } 603 shf_puts(tp->val.s, shl_stdout); 604 } else { 605 if (vflag) 606 shprintf(" %s\n", "not found"); 607 rv = 1; 608 } 609 break; 610 default: 611 shprintf("%s is *GOK*", id); 612 break; 613 } 614 if (vflag || !rv) 615 shf_putc('\n', shl_stdout); 616 } 617 return (rv); 618 } 619 620 /* Deal with command -vV - command -p dealt with in comexec() */ 621 int 622 c_command(const char **wp) 623 { 624 /* 625 * Let c_whence do the work. Note that c_command() must be 626 * a distinct function from c_whence() (tested in comexec()). 627 */ 628 return (c_whence(wp)); 629 } 630 631 /* typeset, global, export, and readonly */ 632 static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool); 633 static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool, 634 bool); 635 int 636 c_typeset(const char **wp) 637 { 638 struct tbl *vp, **p; 639 uint32_t fset = 0, fclr = 0, flag; 640 int thing = 0, field = 0, base = 0, i; 641 struct block *l; 642 const char *opts; 643 const char *fieldstr = NULL, *basestr = NULL; 644 bool localv = false, func = false, pflag = false, istset = true; 645 646 switch (**wp) { 647 648 /* export */ 649 case 'e': 650 fset |= EXPORT; 651 istset = false; 652 break; 653 654 /* readonly */ 655 case 'r': 656 fset |= RDONLY; 657 istset = false; 658 break; 659 660 /* set */ 661 case 's': 662 /* called with 'typeset -' */ 663 break; 664 665 /* typeset */ 666 case 't': 667 localv = true; 668 break; 669 } 670 671 /* see comment below regarding possible opions */ 672 opts = istset ? "L#R#UZ#afi#lnprtux" : "p"; 673 674 builtin_opt.flags |= GF_PLUSOPT; 675 /* 676 * AT&T ksh seems to have 0-9 as options which are multiplied 677 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 678 * sets right justify in a field of 12). This allows options 679 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and 680 * does not allow the number to be specified as a separate argument 681 * Here, the number must follow the RLZi option, but is optional 682 * (see the # kludge in ksh_getopt()). 683 */ 684 while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) { 685 flag = 0; 686 switch (i) { 687 case 'L': 688 flag = LJUST; 689 fieldstr = builtin_opt.optarg; 690 break; 691 case 'R': 692 flag = RJUST; 693 fieldstr = builtin_opt.optarg; 694 break; 695 case 'U': 696 /* 697 * AT&T ksh uses u, but this conflicts with 698 * upper/lower case. If this option is changed, 699 * need to change the -U below as well 700 */ 701 flag = INT_U; 702 break; 703 case 'Z': 704 flag = ZEROFIL; 705 fieldstr = builtin_opt.optarg; 706 break; 707 case 'a': 708 /* 709 * this is supposed to set (-a) or unset (+a) the 710 * indexed array attribute; it does nothing on an 711 * existing regular string or indexed array though 712 */ 713 break; 714 case 'f': 715 func = true; 716 break; 717 case 'i': 718 flag = INTEGER; 719 basestr = builtin_opt.optarg; 720 break; 721 case 'l': 722 flag = LCASEV; 723 break; 724 case 'n': 725 set_refflag = (builtin_opt.info & GI_PLUS) ? 726 SRF_DISABLE : SRF_ENABLE; 727 break; 728 /* export, readonly: POSIX -p flag */ 729 case 'p': 730 /* typeset: show values as well */ 731 pflag = true; 732 if (istset) 733 continue; 734 break; 735 case 'r': 736 flag = RDONLY; 737 break; 738 case 't': 739 flag = TRACE; 740 break; 741 case 'u': 742 /* upper case / autoload */ 743 flag = UCASEV_AL; 744 break; 745 case 'x': 746 flag = EXPORT; 747 break; 748 case '?': 749 errout: 750 set_refflag = SRF_NOP; 751 return (1); 752 } 753 if (builtin_opt.info & GI_PLUS) { 754 fclr |= flag; 755 fset &= ~flag; 756 thing = '+'; 757 } else { 758 fset |= flag; 759 fclr &= ~flag; 760 thing = '-'; 761 } 762 } 763 764 if (fieldstr && !bi_getn(fieldstr, &field)) 765 goto errout; 766 if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) { 767 bi_errorf("%s: %s", "bad integer base", basestr); 768 goto errout; 769 } 770 771 if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && 772 (wp[builtin_opt.optind][0] == '-' || 773 wp[builtin_opt.optind][0] == '+') && 774 wp[builtin_opt.optind][1] == '\0') { 775 thing = wp[builtin_opt.optind][0]; 776 builtin_opt.optind++; 777 } 778 779 if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) || 780 set_refflag != SRF_NOP)) { 781 bi_errorf("only -t, -u and -x options may be used with -f"); 782 goto errout; 783 } 784 if (wp[builtin_opt.optind]) { 785 /* 786 * Take care of exclusions. 787 * At this point, flags in fset are cleared in fclr and vice 788 * versa. This property should be preserved. 789 */ 790 if (fset & LCASEV) 791 /* LCASEV has priority over UCASEV_AL */ 792 fset &= ~UCASEV_AL; 793 if (fset & LJUST) 794 /* LJUST has priority over RJUST */ 795 fset &= ~RJUST; 796 if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { 797 /* -Z implies -ZR */ 798 fset |= RJUST; 799 fclr &= ~RJUST; 800 } 801 /* 802 * Setting these attributes clears the others, unless they 803 * are also set in this command 804 */ 805 if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | 806 INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP) 807 fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | 808 LCASEV | INTEGER | INT_U | INT_L); 809 } 810 811 /* set variables and attributes */ 812 if (wp[builtin_opt.optind] && 813 /* not "typeset -p varname" */ 814 !(!func && pflag && !(fset | fclr))) { 815 int rv = 0; 816 struct tbl *f; 817 818 if (localv && !func) 819 fset |= LOCAL; 820 for (i = builtin_opt.optind; wp[i]; i++) { 821 if (func) { 822 f = findfunc(wp[i], hash(wp[i]), 823 tobool(fset & UCASEV_AL)); 824 if (!f) { 825 /* AT&T ksh does ++rv: bogus */ 826 rv = 1; 827 continue; 828 } 829 if (fset | fclr) { 830 f->flag |= fset; 831 f->flag &= ~fclr; 832 } else { 833 fpFUNCTf(shl_stdout, 0, 834 tobool(f->flag & FKSH), 835 wp[i], f->val.t); 836 shf_putc('\n', shl_stdout); 837 } 838 } else if (!typeset(wp[i], fset, fclr, field, base)) { 839 bi_errorf("%s: %s", wp[i], "not identifier"); 840 goto errout; 841 } 842 } 843 set_refflag = SRF_NOP; 844 return (rv); 845 } 846 847 set_refflag = SRF_NOP; 848 /* list variables and attributes */ 849 850 /* no difference at this point.. */ 851 flag = fset | fclr; 852 if (func) { 853 for (l = e->loc; l; l = l->next) { 854 for (p = ktsort(&l->funs); (vp = *p++); ) { 855 if (flag && (vp->flag & flag) == 0) 856 continue; 857 if (thing == '-') 858 fpFUNCTf(shl_stdout, 0, 859 tobool(vp->flag & FKSH), 860 vp->name, vp->val.t); 861 else 862 shf_puts(vp->name, shl_stdout); 863 shf_putc('\n', shl_stdout); 864 } 865 } 866 } else if (wp[builtin_opt.optind]) { 867 for (i = builtin_opt.optind; wp[i]; i++) { 868 varsearch(e->loc, &vp, wp[i], hash(wp[i])); 869 c_typeset_vardump(vp, flag, thing, pflag, istset); 870 } 871 } else 872 c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset); 873 return (0); 874 } 875 876 static void 877 c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing, 878 bool pflag, bool istset) 879 { 880 struct tbl **blockvars, *vp; 881 882 if (l->next) 883 c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset); 884 blockvars = ktsort(&l->vars); 885 while ((vp = *blockvars++)) 886 c_typeset_vardump(vp, flag, thing, pflag, istset); 887 /*XXX doesnt this leak? */ 888 } 889 890 static void 891 c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag, 892 bool istset) 893 { 894 struct tbl *tvp; 895 int any_set = 0; 896 char *s; 897 898 if (!vp) 899 return; 900 901 /* 902 * See if the parameter is set (for arrays, if any 903 * element is set). 904 */ 905 for (tvp = vp; tvp; tvp = tvp->u.array) 906 if (tvp->flag & ISSET) { 907 any_set = 1; 908 break; 909 } 910 911 /* 912 * Check attributes - note that all array elements 913 * have (should have?) the same attributes, so checking 914 * the first is sufficient. 915 * 916 * Report an unset param only if the user has 917 * explicitly given it some attribute (like export); 918 * otherwise, after "echo $FOO", we would report FOO... 919 */ 920 if (!any_set && !(vp->flag & USERATTRIB)) 921 return; 922 if (flag && (vp->flag & flag) == 0) 923 return; 924 if (!(vp->flag & ARRAY)) 925 /* optimise later conditionals */ 926 any_set = 0; 927 do { 928 /* 929 * Ignore array elements that aren't set unless there 930 * are no set elements, in which case the first is 931 * reported on 932 */ 933 if (any_set && !(vp->flag & ISSET)) 934 continue; 935 /* no arguments */ 936 if (!thing && !flag) { 937 if (any_set == 1) { 938 shprintf("%s %s %s\n", Tset, "-A", vp->name); 939 any_set = 2; 940 } 941 /* 942 * AT&T ksh prints things like export, integer, 943 * leftadj, zerofill, etc., but POSIX says must 944 * be suitable for re-entry... 945 */ 946 shprintf("%s %s", Ttypeset, ""); 947 if (((vp->flag & (ARRAY | ASSOC)) == ASSOC)) 948 shprintf("%s ", "-n"); 949 if ((vp->flag & INTEGER)) 950 shprintf("%s ", "-i"); 951 if ((vp->flag & EXPORT)) 952 shprintf("%s ", "-x"); 953 if ((vp->flag & RDONLY)) 954 shprintf("%s ", "-r"); 955 if ((vp->flag & TRACE)) 956 shprintf("%s ", "-t"); 957 if ((vp->flag & LJUST)) 958 shprintf("-L%d ", vp->u2.field); 959 if ((vp->flag & RJUST)) 960 shprintf("-R%d ", vp->u2.field); 961 if ((vp->flag & ZEROFIL)) 962 shprintf("%s ", "-Z"); 963 if ((vp->flag & LCASEV)) 964 shprintf("%s ", "-l"); 965 if ((vp->flag & UCASEV_AL)) 966 shprintf("%s ", "-u"); 967 if ((vp->flag & INT_U)) 968 shprintf("%s ", "-U"); 969 } else if (pflag) { 970 shprintf("%s %s", istset ? Ttypeset : 971 (flag & EXPORT) ? Texport : Treadonly, ""); 972 } 973 if (any_set) 974 shprintf("%s[%lu]", vp->name, arrayindex(vp)); 975 else 976 shf_puts(vp->name, shl_stdout); 977 if ((!thing && !flag && pflag) || 978 (thing == '-' && (vp->flag & ISSET))) { 979 s = str_val(vp); 980 shf_putc('=', shl_stdout); 981 /* AT&T ksh can't have justified integers... */ 982 if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER) 983 shf_puts(s, shl_stdout); 984 else 985 print_value_quoted(shl_stdout, s); 986 } 987 shf_putc('\n', shl_stdout); 988 989 /* 990 * Only report first 'element' of an array with 991 * no set elements. 992 */ 993 if (!any_set) 994 return; 995 } while ((vp = vp->u.array)); 996 } 997 998 int 999 c_alias(const char **wp) 1000 { 1001 struct table *t = &aliases; 1002 int rv = 0, prefix = 0; 1003 bool rflag = false, tflag, Uflag = false, pflag = false; 1004 uint32_t xflag = 0; 1005 int optc; 1006 1007 builtin_opt.flags |= GF_PLUSOPT; 1008 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) { 1009 prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; 1010 switch (optc) { 1011 case 'd': 1012 #ifdef MKSH_NOPWNAM 1013 t = NULL; /* fix "alias -dt" */ 1014 #else 1015 t = &homedirs; 1016 #endif 1017 break; 1018 case 'p': 1019 pflag = true; 1020 break; 1021 case 'r': 1022 rflag = true; 1023 break; 1024 case 't': 1025 t = &taliases; 1026 break; 1027 case 'U': 1028 /* 1029 * kludge for tracked alias initialization 1030 * (don't do a path search, just make an entry) 1031 */ 1032 Uflag = true; 1033 break; 1034 case 'x': 1035 xflag = EXPORT; 1036 break; 1037 case '?': 1038 return (1); 1039 } 1040 } 1041 #ifdef MKSH_NOPWNAM 1042 if (t == NULL) 1043 return (0); 1044 #endif 1045 wp += builtin_opt.optind; 1046 1047 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp && 1048 (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') { 1049 prefix = wp[0][0]; 1050 wp++; 1051 } 1052 1053 tflag = t == &taliases; 1054 1055 /* "hash -r" means reset all the tracked aliases.. */ 1056 if (rflag) { 1057 static const char *args[] = { 1058 Tunalias, "-ta", NULL 1059 }; 1060 1061 if (!tflag || *wp) { 1062 shprintf("%s: -r flag can only be used with -t" 1063 " and without arguments\n", Talias); 1064 return (1); 1065 } 1066 ksh_getopt_reset(&builtin_opt, GF_ERROR); 1067 return (c_unalias(args)); 1068 } 1069 1070 if (*wp == NULL) { 1071 struct tbl *ap, **p; 1072 1073 for (p = ktsort(t); (ap = *p++) != NULL; ) 1074 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { 1075 if (pflag) 1076 shprintf("%s ", Talias); 1077 shf_puts(ap->name, shl_stdout); 1078 if (prefix != '+') { 1079 shf_putc('=', shl_stdout); 1080 print_value_quoted(shl_stdout, ap->val.s); 1081 } 1082 shf_putc('\n', shl_stdout); 1083 } 1084 } 1085 1086 for (; *wp != NULL; wp++) { 1087 const char *alias = *wp, *val, *newval; 1088 char *xalias = NULL; 1089 struct tbl *ap; 1090 uint32_t h; 1091 1092 if ((val = cstrchr(alias, '='))) { 1093 strndupx(xalias, alias, val++ - alias, ATEMP); 1094 alias = xalias; 1095 } 1096 h = hash(alias); 1097 if (val == NULL && !tflag && !xflag) { 1098 ap = ktsearch(t, alias, h); 1099 if (ap != NULL && (ap->flag&ISSET)) { 1100 if (pflag) 1101 shprintf("%s ", Talias); 1102 shf_puts(ap->name, shl_stdout); 1103 if (prefix != '+') { 1104 shf_putc('=', shl_stdout); 1105 print_value_quoted(shl_stdout, ap->val.s); 1106 } 1107 shf_putc('\n', shl_stdout); 1108 } else { 1109 shprintf("%s %s %s\n", alias, Talias, 1110 "not found"); 1111 rv = 1; 1112 } 1113 continue; 1114 } 1115 ap = ktenter(t, alias, h); 1116 ap->type = tflag ? CTALIAS : CALIAS; 1117 /* Are we setting the value or just some flags? */ 1118 if ((val && !tflag) || (!val && tflag && !Uflag)) { 1119 if (ap->flag&ALLOC) { 1120 ap->flag &= ~(ALLOC|ISSET); 1121 afree(ap->val.s, APERM); 1122 } 1123 /* ignore values for -t (AT&T ksh does this) */ 1124 newval = tflag ? 1125 search_path(alias, path, X_OK, NULL) : 1126 val; 1127 if (newval) { 1128 strdupx(ap->val.s, newval, APERM); 1129 ap->flag |= ALLOC|ISSET; 1130 } else 1131 ap->flag &= ~ISSET; 1132 } 1133 ap->flag |= DEFINED; 1134 if (prefix == '+') 1135 ap->flag &= ~xflag; 1136 else 1137 ap->flag |= xflag; 1138 afree(xalias, ATEMP); 1139 } 1140 1141 return (rv); 1142 } 1143 1144 int 1145 c_unalias(const char **wp) 1146 { 1147 struct table *t = &aliases; 1148 struct tbl *ap; 1149 int optc, rv = 0; 1150 bool all = false; 1151 1152 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1) 1153 switch (optc) { 1154 case 'a': 1155 all = true; 1156 break; 1157 case 'd': 1158 #ifdef MKSH_NOPWNAM 1159 /* fix "unalias -dt" */ 1160 t = NULL; 1161 #else 1162 t = &homedirs; 1163 #endif 1164 break; 1165 case 't': 1166 t = &taliases; 1167 break; 1168 case '?': 1169 return (1); 1170 } 1171 #ifdef MKSH_NOPWNAM 1172 if (t == NULL) 1173 return (0); 1174 #endif 1175 wp += builtin_opt.optind; 1176 1177 for (; *wp != NULL; wp++) { 1178 ap = ktsearch(t, *wp, hash(*wp)); 1179 if (ap == NULL) { 1180 /* POSIX */ 1181 rv = 1; 1182 continue; 1183 } 1184 if (ap->flag&ALLOC) { 1185 ap->flag &= ~(ALLOC|ISSET); 1186 afree(ap->val.s, APERM); 1187 } 1188 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1189 } 1190 1191 if (all) { 1192 struct tstate ts; 1193 1194 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) { 1195 if (ap->flag&ALLOC) { 1196 ap->flag &= ~(ALLOC|ISSET); 1197 afree(ap->val.s, APERM); 1198 } 1199 ap->flag &= ~(DEFINED|ISSET|EXPORT); 1200 } 1201 } 1202 1203 return (rv); 1204 } 1205 1206 int 1207 c_let(const char **wp) 1208 { 1209 int rv = 1; 1210 mksh_ari_t val; 1211 1212 if (wp[1] == NULL) 1213 /* AT&T ksh does this */ 1214 bi_errorf("no arguments"); 1215 else 1216 for (wp++; *wp; wp++) 1217 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) { 1218 /* distinguish error from zero result */ 1219 rv = 2; 1220 break; 1221 } else 1222 rv = val == 0; 1223 return (rv); 1224 } 1225 1226 int 1227 c_jobs(const char **wp) 1228 { 1229 int optc, flag = 0, nflag = 0, rv = 0; 1230 1231 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1) 1232 switch (optc) { 1233 case 'l': 1234 flag = 1; 1235 break; 1236 case 'p': 1237 flag = 2; 1238 break; 1239 case 'n': 1240 nflag = 1; 1241 break; 1242 case 'z': 1243 /* debugging: print zombies */ 1244 nflag = -1; 1245 break; 1246 case '?': 1247 return (1); 1248 } 1249 wp += builtin_opt.optind; 1250 if (!*wp) { 1251 if (j_jobs(NULL, flag, nflag)) 1252 rv = 1; 1253 } else { 1254 for (; *wp; wp++) 1255 if (j_jobs(*wp, flag, nflag)) 1256 rv = 1; 1257 } 1258 return (rv); 1259 } 1260 1261 #ifndef MKSH_UNEMPLOYED 1262 int 1263 c_fgbg(const char **wp) 1264 { 1265 bool bg = strcmp(*wp, "bg") == 0; 1266 int rv = 0; 1267 1268 if (!Flag(FMONITOR)) { 1269 bi_errorf("job control not enabled"); 1270 return (1); 1271 } 1272 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1273 return (1); 1274 wp += builtin_opt.optind; 1275 if (*wp) 1276 for (; *wp; wp++) 1277 rv = j_resume(*wp, bg); 1278 else 1279 rv = j_resume("%%", bg); 1280 return (bg ? 0 : rv); 1281 } 1282 #endif 1283 1284 /* format a single kill item */ 1285 static char * 1286 kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) 1287 { 1288 const struct kill_info *ki = (const struct kill_info *)arg; 1289 1290 i++; 1291 shf_snprintf(buf, buflen, "%*u %*s %s", 1292 ki->num_width, i, 1293 ki->name_width, sigtraps[i].name, 1294 sigtraps[i].mess); 1295 return (buf); 1296 } 1297 1298 int 1299 c_kill(const char **wp) 1300 { 1301 Trap *t = NULL; 1302 const char *p; 1303 bool lflag = false; 1304 int i, n, rv, sig; 1305 1306 /* assume old style options if -digits or -UPPERCASE */ 1307 if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) || 1308 ksh_isupper(p[1]))) { 1309 if (!(t = gettrap(p + 1, false))) { 1310 bi_errorf("bad signal '%s'", p + 1); 1311 return (1); 1312 } 1313 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; 1314 } else { 1315 int optc; 1316 1317 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1) 1318 switch (optc) { 1319 case 'l': 1320 lflag = true; 1321 break; 1322 case 's': 1323 if (!(t = gettrap(builtin_opt.optarg, true))) { 1324 bi_errorf("bad signal '%s'", 1325 builtin_opt.optarg); 1326 return (1); 1327 } 1328 break; 1329 case '?': 1330 return (1); 1331 } 1332 i = builtin_opt.optind; 1333 } 1334 if ((lflag && t) || (!wp[i] && !lflag)) { 1335 #ifndef MKSH_SMALL 1336 shf_puts("usage:\tkill [-s signame | -signum | -signame]" 1337 " { job | pid | pgrp } ...\n" 1338 "\tkill -l [exit_status ...]\n", shl_out); 1339 #endif 1340 bi_errorfz(); 1341 return (1); 1342 } 1343 1344 if (lflag) { 1345 if (wp[i]) { 1346 for (; wp[i]; i++) { 1347 if (!bi_getn(wp[i], &n)) 1348 return (1); 1349 if (n > 128 && n < 128 + NSIG) 1350 n -= 128; 1351 if (n > 0 && n < NSIG) 1352 shprintf("%s\n", sigtraps[n].name); 1353 else 1354 shprintf("%d\n", n); 1355 } 1356 } else { 1357 ssize_t w, mess_cols, mess_octs; 1358 int j; 1359 struct kill_info ki; 1360 1361 for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10) 1362 ki.num_width++; 1363 ki.name_width = mess_cols = mess_octs = 0; 1364 for (j = 0; j < NSIG; j++) { 1365 w = strlen(sigtraps[j].name); 1366 if (w > ki.name_width) 1367 ki.name_width = w; 1368 w = strlen(sigtraps[j].mess); 1369 if (w > mess_octs) 1370 mess_octs = w; 1371 w = utf_mbswidth(sigtraps[j].mess); 1372 if (w > mess_cols) 1373 mess_cols = w; 1374 } 1375 1376 print_columns(shl_stdout, (unsigned int)(NSIG - 1), 1377 kill_fmt_entry, (void *)&ki, 1378 ki.num_width + 1 + ki.name_width + 1 + mess_octs, 1379 ki.num_width + 1 + ki.name_width + 1 + mess_cols, 1380 true); 1381 } 1382 return (0); 1383 } 1384 rv = 0; 1385 sig = t ? t->signal : SIGTERM; 1386 for (; (p = wp[i]); i++) { 1387 if (*p == '%') { 1388 if (j_kill(p, sig)) 1389 rv = 1; 1390 } else if (!getn(p, &n)) { 1391 bi_errorf("%s: %s", p, 1392 "arguments must be jobs or process IDs"); 1393 rv = 1; 1394 } else { 1395 if (mksh_kill(n, sig) < 0) { 1396 bi_errorf("%s: %s", p, cstrerror(errno)); 1397 rv = 1; 1398 } 1399 } 1400 } 1401 return (rv); 1402 } 1403 1404 void 1405 getopts_reset(int val) 1406 { 1407 if (val >= 1) { 1408 ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT); 1409 user_opt.optind = user_opt.uoptind = val; 1410 } 1411 } 1412 1413 int 1414 c_getopts(const char **wp) 1415 { 1416 int argc, optc, rv; 1417 const char *opts, *var; 1418 char buf[3]; 1419 struct tbl *vq, *voptarg; 1420 1421 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1422 return (1); 1423 wp += builtin_opt.optind; 1424 1425 opts = *wp++; 1426 if (!opts) { 1427 bi_errorf("missing %s argument", "options"); 1428 return (1); 1429 } 1430 1431 var = *wp++; 1432 if (!var) { 1433 bi_errorf("missing %s argument", "name"); 1434 return (1); 1435 } 1436 if (!*var || *skip_varname(var, true)) { 1437 bi_errorf("%s: %s", var, "is not an identifier"); 1438 return (1); 1439 } 1440 1441 if (e->loc->next == NULL) { 1442 internal_warningf("%s: %s", "c_getopts", "no argv"); 1443 return (1); 1444 } 1445 /* Which arguments are we parsing... */ 1446 if (*wp == NULL) 1447 wp = e->loc->next->argv; 1448 else 1449 *--wp = e->loc->next->argv[0]; 1450 1451 /* Check that our saved state won't cause a core dump... */ 1452 for (argc = 0; wp[argc]; argc++) 1453 ; 1454 if (user_opt.optind > argc || 1455 (user_opt.p != 0 && 1456 user_opt.p > strlen(wp[user_opt.optind - 1]))) { 1457 bi_errorf("arguments changed since last call"); 1458 return (1); 1459 } 1460 1461 user_opt.optarg = NULL; 1462 optc = ksh_getopt(wp, &user_opt, opts); 1463 1464 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { 1465 buf[0] = '+'; 1466 buf[1] = optc; 1467 buf[2] = '\0'; 1468 } else { 1469 /* 1470 * POSIX says var is set to ? at end-of-options, AT&T ksh 1471 * sets it to null - we go with POSIX... 1472 */ 1473 buf[0] = optc < 0 ? '?' : optc; 1474 buf[1] = '\0'; 1475 } 1476 1477 /* AT&T ksh93 in fact does change OPTIND for unknown options too */ 1478 user_opt.uoptind = user_opt.optind; 1479 1480 voptarg = global("OPTARG"); 1481 /* AT&T ksh clears ro and int */ 1482 voptarg->flag &= ~RDONLY; 1483 /* Paranoia: ensure no bizarre results. */ 1484 if (voptarg->flag & INTEGER) 1485 typeset("OPTARG", 0, INTEGER, 0, 0); 1486 if (user_opt.optarg == NULL) 1487 unset(voptarg, 1); 1488 else 1489 /* This can't fail (have cleared readonly/integer) */ 1490 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); 1491 1492 rv = 0; 1493 1494 vq = global(var); 1495 /* Error message already printed (integer, readonly) */ 1496 if (!setstr(vq, buf, KSH_RETURN_ERROR)) 1497 rv = 2; 1498 if (Flag(FEXPORT)) 1499 typeset(var, EXPORT, 0, 0, 0); 1500 1501 return (optc < 0 ? 1 : rv); 1502 } 1503 1504 #ifndef MKSH_NO_CMDLINE_EDITING 1505 int 1506 c_bind(const char **wp) 1507 { 1508 int optc, rv = 0; 1509 #ifndef MKSH_SMALL 1510 bool macro = false; 1511 #endif 1512 bool list = false; 1513 const char *cp; 1514 char *up; 1515 1516 while ((optc = ksh_getopt(wp, &builtin_opt, 1517 #ifndef MKSH_SMALL 1518 "lm" 1519 #else 1520 "l" 1521 #endif 1522 )) != -1) 1523 switch (optc) { 1524 case 'l': 1525 list = true; 1526 break; 1527 #ifndef MKSH_SMALL 1528 case 'm': 1529 macro = true; 1530 break; 1531 #endif 1532 case '?': 1533 return (1); 1534 } 1535 wp += builtin_opt.optind; 1536 1537 if (*wp == NULL) 1538 /* list all */ 1539 rv = x_bind(NULL, NULL, 1540 #ifndef MKSH_SMALL 1541 false, 1542 #endif 1543 list); 1544 1545 for (; *wp != NULL; wp++) { 1546 if ((cp = cstrchr(*wp, '=')) == NULL) 1547 up = NULL; 1548 else { 1549 strdupx(up, *wp, ATEMP); 1550 up[cp++ - *wp] = '\0'; 1551 } 1552 if (x_bind(up ? up : *wp, cp, 1553 #ifndef MKSH_SMALL 1554 macro, 1555 #endif 1556 false)) 1557 rv = 1; 1558 afree(up, ATEMP); 1559 } 1560 1561 return (rv); 1562 } 1563 #endif 1564 1565 int 1566 c_shift(const char **wp) 1567 { 1568 struct block *l = e->loc; 1569 int n; 1570 mksh_ari_t val; 1571 const char *arg; 1572 1573 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1574 return (1); 1575 arg = wp[builtin_opt.optind]; 1576 1577 if (arg) { 1578 evaluate(arg, &val, KSH_UNWIND_ERROR, false); 1579 n = val; 1580 } else 1581 n = 1; 1582 if (n < 0) { 1583 bi_errorf("%s: %s", arg, "bad number"); 1584 return (1); 1585 } 1586 if (l->argc < n) { 1587 bi_errorf("nothing to shift"); 1588 return (1); 1589 } 1590 l->argv[n] = l->argv[0]; 1591 l->argv += n; 1592 l->argc -= n; 1593 return (0); 1594 } 1595 1596 int 1597 c_umask(const char **wp) 1598 { 1599 int i, optc; 1600 const char *cp; 1601 bool symbolic = false; 1602 mode_t old_umask; 1603 1604 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1) 1605 switch (optc) { 1606 case 'S': 1607 symbolic = true; 1608 break; 1609 case '?': 1610 return (1); 1611 } 1612 cp = wp[builtin_opt.optind]; 1613 if (cp == NULL) { 1614 old_umask = umask((mode_t)0); 1615 umask(old_umask); 1616 if (symbolic) { 1617 char buf[18], *p; 1618 int j; 1619 1620 old_umask = ~old_umask; 1621 p = buf; 1622 for (i = 0; i < 3; i++) { 1623 *p++ = "ugo"[i]; 1624 *p++ = '='; 1625 for (j = 0; j < 3; j++) 1626 if (old_umask & (1 << (8 - (3*i + j)))) 1627 *p++ = "rwx"[j]; 1628 *p++ = ','; 1629 } 1630 p[-1] = '\0'; 1631 shprintf("%s\n", buf); 1632 } else 1633 shprintf("%#3.3o\n", (unsigned int)old_umask); 1634 } else { 1635 mode_t new_umask; 1636 1637 if (ksh_isdigit(*cp)) { 1638 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) 1639 new_umask = new_umask * 8 + (*cp - '0'); 1640 if (*cp) { 1641 bi_errorf("bad number"); 1642 return (1); 1643 } 1644 } else { 1645 /* symbolic format */ 1646 int positions, new_val; 1647 char op; 1648 1649 old_umask = umask((mode_t)0); 1650 /* in case of error */ 1651 umask(old_umask); 1652 old_umask = ~old_umask; 1653 new_umask = old_umask; 1654 positions = 0; 1655 while (*cp) { 1656 while (*cp && vstrchr("augo", *cp)) 1657 switch (*cp++) { 1658 case 'a': 1659 positions |= 0111; 1660 break; 1661 case 'u': 1662 positions |= 0100; 1663 break; 1664 case 'g': 1665 positions |= 0010; 1666 break; 1667 case 'o': 1668 positions |= 0001; 1669 break; 1670 } 1671 if (!positions) 1672 /* default is a */ 1673 positions = 0111; 1674 if (!vstrchr("=+-", op = *cp)) 1675 break; 1676 cp++; 1677 new_val = 0; 1678 while (*cp && vstrchr("rwxugoXs", *cp)) 1679 switch (*cp++) { 1680 case 'r': new_val |= 04; break; 1681 case 'w': new_val |= 02; break; 1682 case 'x': new_val |= 01; break; 1683 case 'u': 1684 new_val |= old_umask >> 6; 1685 break; 1686 case 'g': 1687 new_val |= old_umask >> 3; 1688 break; 1689 case 'o': 1690 new_val |= old_umask >> 0; 1691 break; 1692 case 'X': 1693 if (old_umask & 0111) 1694 new_val |= 01; 1695 break; 1696 case 's': 1697 /* ignored */ 1698 break; 1699 } 1700 new_val = (new_val & 07) * positions; 1701 switch (op) { 1702 case '-': 1703 new_umask &= ~new_val; 1704 break; 1705 case '=': 1706 new_umask = new_val | 1707 (new_umask & ~(positions * 07)); 1708 break; 1709 case '+': 1710 new_umask |= new_val; 1711 } 1712 if (*cp == ',') { 1713 positions = 0; 1714 cp++; 1715 } else if (!vstrchr("=+-", *cp)) 1716 break; 1717 } 1718 if (*cp) { 1719 bi_errorf("bad mask"); 1720 return (1); 1721 } 1722 new_umask = ~new_umask; 1723 } 1724 umask(new_umask); 1725 } 1726 return (0); 1727 } 1728 1729 int 1730 c_dot(const char **wp) 1731 { 1732 const char *file, *cp, **argv; 1733 int argc, i, errcode; 1734 1735 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1736 return (1); 1737 1738 if ((cp = wp[builtin_opt.optind]) == NULL) { 1739 bi_errorf("missing argument"); 1740 return (1); 1741 } 1742 if ((file = search_path(cp, path, R_OK, &errcode)) == NULL) { 1743 bi_errorf("%s: %s", cp, cstrerror(errcode)); 1744 return (1); 1745 } 1746 1747 /* Set positional parameters? */ 1748 if (wp[builtin_opt.optind + 1]) { 1749 argv = wp + builtin_opt.optind; 1750 /* preserve $0 */ 1751 argv[0] = e->loc->argv[0]; 1752 for (argc = 0; argv[argc + 1]; argc++) 1753 ; 1754 } else { 1755 argc = 0; 1756 argv = NULL; 1757 } 1758 if ((i = include(file, argc, argv, false)) < 0) { 1759 /* should not happen */ 1760 bi_errorf("%s: %s", cp, cstrerror(errno)); 1761 return (1); 1762 } 1763 return (i); 1764 } 1765 1766 int 1767 c_wait(const char **wp) 1768 { 1769 int rv = 0, sig; 1770 1771 if (ksh_getopt(wp, &builtin_opt, null) == '?') 1772 return (1); 1773 wp += builtin_opt.optind; 1774 if (*wp == NULL) { 1775 while (waitfor(NULL, &sig) >= 0) 1776 ; 1777 rv = sig; 1778 } else { 1779 for (; *wp; wp++) 1780 rv = waitfor(*wp, &sig); 1781 if (rv < 0) 1782 /* magic exit code: bad job-id */ 1783 rv = sig ? sig : 127; 1784 } 1785 return (rv); 1786 } 1787 1788 static char REPLY[] = "REPLY"; 1789 int 1790 c_read(const char **wp) 1791 { 1792 #define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS)) 1793 int c, fd = 0, rv = 0, lastparm = 0; 1794 bool savehist = false, intoarray = false, aschars = false; 1795 bool rawmode = false, expanding = false; 1796 enum { LINES, BYTES, UPTO, READALL } readmode = LINES; 1797 char delim = '\n'; 1798 size_t bytesleft = 128, bytesread; 1799 struct tbl *vp /* FU gcc */ = NULL, *vq; 1800 char *cp, *allocd = NULL, *xp; 1801 const char *ccp; 1802 XString xs; 1803 ptrdiff_t xsave = 0; 1804 mksh_ttyst tios; 1805 bool restore_tios = false; 1806 #if HAVE_SELECT 1807 bool hastimeout = false; 1808 struct timeval tv, tvlim; 1809 #define c_read_opts "Aad:N:n:prst:u," 1810 #else 1811 #define c_read_opts "Aad:N:n:prsu," 1812 #endif 1813 1814 while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1) 1815 switch (c) { 1816 case 'a': 1817 aschars = true; 1818 /* FALLTHROUGH */ 1819 case 'A': 1820 intoarray = true; 1821 break; 1822 case 'd': 1823 delim = builtin_opt.optarg[0]; 1824 break; 1825 case 'N': 1826 case 'n': 1827 readmode = c == 'N' ? BYTES : UPTO; 1828 if (!bi_getn(builtin_opt.optarg, &c)) 1829 return (2); 1830 if (c == -1) { 1831 readmode = READALL; 1832 bytesleft = 1024; 1833 } else 1834 bytesleft = (unsigned int)c; 1835 break; 1836 case 'p': 1837 if ((fd = coproc_getfd(R_OK, &ccp)) < 0) { 1838 bi_errorf("%s: %s", "-p", ccp); 1839 return (2); 1840 } 1841 break; 1842 case 'r': 1843 rawmode = true; 1844 break; 1845 case 's': 1846 savehist = true; 1847 break; 1848 #if HAVE_SELECT 1849 case 't': 1850 if (parse_usec(builtin_opt.optarg, &tv)) { 1851 bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno), 1852 builtin_opt.optarg); 1853 return (2); 1854 } 1855 hastimeout = true; 1856 break; 1857 #endif 1858 case 'u': 1859 if (!builtin_opt.optarg[0]) 1860 fd = 0; 1861 else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) { 1862 bi_errorf("%s: %s: %s", "-u", builtin_opt.optarg, ccp); 1863 return (2); 1864 } 1865 break; 1866 case '?': 1867 return (2); 1868 } 1869 wp += builtin_opt.optind; 1870 if (*wp == NULL) 1871 *--wp = REPLY; 1872 1873 if (intoarray && wp[1] != NULL) { 1874 bi_errorf("too many arguments"); 1875 return (2); 1876 } 1877 1878 if ((ccp = cstrchr(*wp, '?')) != NULL) { 1879 strdupx(allocd, *wp, ATEMP); 1880 allocd[ccp - *wp] = '\0'; 1881 *wp = allocd; 1882 if (isatty(fd)) { 1883 /* 1884 * AT&T ksh says it prints prompt on fd if it's open 1885 * for writing and is a tty, but it doesn't do it 1886 * (it also doesn't check the interactive flag, 1887 * as is indicated in the Korn Shell book). 1888 */ 1889 shf_puts(ccp + 1, shl_out); 1890 shf_flush(shl_out); 1891 } 1892 } 1893 1894 Xinit(xs, xp, bytesleft, ATEMP); 1895 1896 if (readmode == LINES) 1897 bytesleft = 1; 1898 else if (isatty(fd)) { 1899 x_mkraw(fd, &tios, true); 1900 restore_tios = true; 1901 } 1902 1903 #if HAVE_SELECT 1904 if (hastimeout) { 1905 mksh_TIME(tvlim); 1906 timeradd(&tvlim, &tv, &tvlim); 1907 } 1908 #endif 1909 1910 c_read_readloop: 1911 #if HAVE_SELECT 1912 if (hastimeout) { 1913 fd_set fdset; 1914 1915 FD_ZERO(&fdset); 1916 FD_SET((unsigned int)fd, &fdset); 1917 mksh_TIME(tv); 1918 timersub(&tvlim, &tv, &tv); 1919 if (tv.tv_sec < 0) { 1920 /* timeout expired globally */ 1921 rv = 1; 1922 goto c_read_out; 1923 } 1924 1925 switch (select(fd + 1, &fdset, NULL, NULL, &tv)) { 1926 case 1: 1927 break; 1928 case 0: 1929 /* timeout expired for this call */ 1930 rv = 1; 1931 goto c_read_out; 1932 default: 1933 bi_errorf("%s: %s", Tselect, cstrerror(errno)); 1934 rv = 2; 1935 goto c_read_out; 1936 } 1937 } 1938 #endif 1939 1940 bytesread = blocking_read(fd, xp, bytesleft); 1941 if (bytesread == (size_t)-1) { 1942 /* interrupted */ 1943 if (errno == EINTR && fatal_trap_check()) { 1944 /* 1945 * Was the offending signal one that would 1946 * normally kill a process? If so, pretend 1947 * the read was killed. 1948 */ 1949 rv = 2; 1950 goto c_read_out; 1951 } 1952 /* just ignore the signal */ 1953 goto c_read_readloop; 1954 } 1955 1956 switch (readmode) { 1957 case READALL: 1958 if (bytesread == 0) { 1959 /* end of file reached */ 1960 rv = 1; 1961 goto c_read_readdone; 1962 } 1963 xp += bytesread; 1964 XcheckN(xs, xp, bytesleft); 1965 break; 1966 1967 case UPTO: 1968 if (bytesread == 0) 1969 /* end of file reached */ 1970 rv = 1; 1971 xp += bytesread; 1972 goto c_read_readdone; 1973 1974 case BYTES: 1975 if (bytesread == 0) { 1976 /* end of file reached */ 1977 rv = 1; 1978 xp = Xstring(xs, xp); 1979 goto c_read_readdone; 1980 } 1981 xp += bytesread; 1982 if ((bytesleft -= bytesread) == 0) 1983 goto c_read_readdone; 1984 break; 1985 case LINES: 1986 if (bytesread == 0) { 1987 /* end of file reached */ 1988 rv = 1; 1989 goto c_read_readdone; 1990 } 1991 if ((c = *xp) == '\0' && !aschars && delim != '\0') { 1992 /* skip any read NULs unless delimiter */ 1993 break; 1994 } 1995 if (expanding) { 1996 expanding = false; 1997 if (c == delim) { 1998 if (Flag(FTALKING_I) && isatty(fd)) { 1999 /* 2000 * set prompt in case this is 2001 * called from .profile or $ENV 2002 */ 2003 set_prompt(PS2, NULL); 2004 pprompt(prompt, 0); 2005 } 2006 /* drop the backslash */ 2007 --xp; 2008 /* and the delimiter */ 2009 break; 2010 } 2011 } else if (c == delim) { 2012 goto c_read_readdone; 2013 } else if (!rawmode && c == '\\') { 2014 expanding = true; 2015 } 2016 Xcheck(xs, xp); 2017 ++xp; 2018 break; 2019 } 2020 goto c_read_readloop; 2021 2022 c_read_readdone: 2023 bytesread = Xlength(xs, xp); 2024 Xput(xs, xp, '\0'); 2025 2026 /*- 2027 * state: we finished reading the input and NUL terminated it 2028 * Xstring(xs, xp) -> xp-1 = input string without trailing delim 2029 * rv = 1 if EOF, 0 otherwise (errors handled already) 2030 */ 2031 2032 if (rv == 1) { 2033 /* clean up coprocess if needed, on EOF */ 2034 coproc_read_close(fd); 2035 if (readmode == READALL) 2036 /* EOF is no error here */ 2037 rv = 0; 2038 } 2039 2040 if (savehist) 2041 histsave(&source->line, Xstring(xs, xp), true, false); 2042 2043 ccp = cp = Xclose(xs, xp); 2044 expanding = false; 2045 XinitN(xs, 128, ATEMP); 2046 if (intoarray) { 2047 vp = global(*wp); 2048 if (vp->flag & RDONLY) { 2049 c_read_splitro: 2050 bi_errorf("read-only: %s", *wp); 2051 c_read_spliterr: 2052 rv = 2; 2053 afree(cp, ATEMP); 2054 goto c_read_out; 2055 } 2056 /* exporting an array is currently pointless */ 2057 unset(vp, 1); 2058 /* counter for array index */ 2059 c = 0; 2060 } 2061 if (!aschars) { 2062 /* skip initial IFS whitespace */ 2063 while (bytesread && is_ifsws(*ccp)) { 2064 ++ccp; 2065 --bytesread; 2066 } 2067 /* trim trailing IFS whitespace */ 2068 while (bytesread && is_ifsws(ccp[bytesread - 1])) { 2069 --bytesread; 2070 } 2071 } 2072 c_read_splitloop: 2073 xp = Xstring(xs, xp); 2074 /* generate next word */ 2075 if (!bytesread) { 2076 /* no more input */ 2077 if (intoarray) 2078 goto c_read_splitdone; 2079 /* zero out next parameters */ 2080 goto c_read_gotword; 2081 } 2082 if (aschars) { 2083 Xput(xs, xp, '1'); 2084 Xput(xs, xp, '#'); 2085 bytesleft = utf_ptradj(ccp); 2086 while (bytesleft && bytesread) { 2087 *xp++ = *ccp++; 2088 --bytesleft; 2089 --bytesread; 2090 } 2091 if (xp[-1] == '\0') { 2092 xp[-1] = '0'; 2093 xp[-3] = '2'; 2094 } 2095 goto c_read_gotword; 2096 } 2097 2098 if (!intoarray && wp[1] == NULL) 2099 lastparm = 1; 2100 2101 c_read_splitlast: 2102 /* copy until IFS character */ 2103 while (bytesread) { 2104 char ch; 2105 2106 ch = *ccp; 2107 if (expanding) { 2108 expanding = false; 2109 goto c_read_splitcopy; 2110 } else if (ctype(ch, C_IFS)) { 2111 break; 2112 } else if (!rawmode && ch == '\\') { 2113 expanding = true; 2114 } else { 2115 c_read_splitcopy: 2116 Xcheck(xs, xp); 2117 Xput(xs, xp, ch); 2118 } 2119 ++ccp; 2120 --bytesread; 2121 } 2122 xsave = Xsavepos(xs, xp); 2123 /* copy word delimiter: IFSWS+IFS,IFSWS */ 2124 while (bytesread) { 2125 char ch; 2126 2127 ch = *ccp; 2128 if (!ctype(ch, C_IFS)) 2129 break; 2130 Xcheck(xs, xp); 2131 Xput(xs, xp, ch); 2132 ++ccp; 2133 --bytesread; 2134 if (!ctype(ch, C_IFSWS)) 2135 break; 2136 } 2137 while (bytesread && is_ifsws(*ccp)) { 2138 Xcheck(xs, xp); 2139 Xput(xs, xp, *ccp); 2140 ++ccp; 2141 --bytesread; 2142 } 2143 /* if no more parameters, rinse and repeat */ 2144 if (lastparm && bytesread) { 2145 ++lastparm; 2146 goto c_read_splitlast; 2147 } 2148 /* get rid of the delimiter unless we pack the rest */ 2149 if (lastparm < 2) 2150 xp = Xrestpos(xs, xp, xsave); 2151 c_read_gotword: 2152 Xput(xs, xp, '\0'); 2153 if (intoarray) { 2154 vq = arraysearch(vp, c++); 2155 } else { 2156 vq = global(*wp); 2157 /* must be checked before exporting */ 2158 if (vq->flag & RDONLY) 2159 goto c_read_splitro; 2160 if (Flag(FEXPORT)) 2161 typeset(*wp, EXPORT, 0, 0, 0); 2162 } 2163 if (!setstr(vq, Xstring(xs, xp), KSH_RETURN_ERROR)) 2164 goto c_read_spliterr; 2165 if (aschars) { 2166 setint_v(vq, vq, false); 2167 /* protect from UTFMODE changes */ 2168 vq->type = 0; 2169 } 2170 if (intoarray || *++wp != NULL) 2171 goto c_read_splitloop; 2172 2173 c_read_splitdone: 2174 /* free up */ 2175 afree(cp, ATEMP); 2176 2177 c_read_out: 2178 afree(allocd, ATEMP); 2179 Xfree(xs, xp); 2180 if (restore_tios) 2181 mksh_tcset(fd, &tios); 2182 return (rv); 2183 #undef is_ifsws 2184 } 2185 2186 int 2187 c_eval(const char **wp) 2188 { 2189 struct source *s, *saves = source; 2190 unsigned char savef; 2191 int rv; 2192 2193 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2194 return (1); 2195 s = pushs(SWORDS, ATEMP); 2196 s->u.strv = wp + builtin_opt.optind; 2197 2198 /*- 2199 * The following code handles the case where the command is 2200 * empty due to failed command substitution, for example by 2201 * eval "$(false)" 2202 * This has historically returned 1 by AT&T ksh88. In this 2203 * case, shell() will not set or change exstat because the 2204 * compiled tree is empty, so it will use the value we pass 2205 * from subst_exstat, which is cleared in execute(), so it 2206 * should have been 0 if there were no substitutions. 2207 * 2208 * POSIX however says we don't do this, even though it is 2209 * traditionally done. AT&T ksh93 agrees with POSIX, so we 2210 * do. The following is an excerpt from SUSv4 [1003.2-2008]: 2211 * 2212 * 2.9.1: Simple Commands 2213 * ... If there is a command name, execution shall 2214 * continue as described in 2.9.1.1 [Command Search 2215 * and Execution]. If there is no command name, but 2216 * the command contained a command substitution, the 2217 * command shall complete with the exit status of the 2218 * last command substitution performed. 2219 * 2.9.1.1: Command Search and Execution 2220 * (1) a. If the command name matches the name of a 2221 * special built-in utility, that special built-in 2222 * utility shall be invoked. 2223 * 2.14.5: eval 2224 * If there are no arguments, or only null arguments, 2225 * eval shall return a zero exit status; ... 2226 */ 2227 /* AT&T ksh88: use subst_exstat */ 2228 /* exstat = subst_exstat; */ 2229 /* SUSv4: OR with a high value never written otherwise */ 2230 exstat |= 0x4000; 2231 2232 savef = Flag(FERREXIT); 2233 Flag(FERREXIT) |= 0x80; 2234 rv = shell(s, false); 2235 Flag(FERREXIT) = savef; 2236 source = saves; 2237 afree(s, ATEMP); 2238 if (exstat & 0x4000) 2239 /* detect old exstat, use 0 in that case */ 2240 rv = 0; 2241 return (rv); 2242 } 2243 2244 int 2245 c_trap(const char **wp) 2246 { 2247 int i; 2248 const char *s; 2249 Trap *p; 2250 2251 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2252 return (1); 2253 wp += builtin_opt.optind; 2254 2255 if (*wp == NULL) { 2256 for (p = sigtraps, i = NSIG+1; --i >= 0; p++) 2257 if (p->trap != NULL) { 2258 shf_puts("trap -- ", shl_stdout); 2259 print_value_quoted(shl_stdout, p->trap); 2260 shprintf(" %s\n", p->name); 2261 } 2262 return (0); 2263 } 2264 2265 /* 2266 * Use case sensitive lookup for first arg so the 2267 * command 'exit' isn't confused with the pseudo-signal 2268 * 'EXIT'. 2269 */ 2270 /* get command */ 2271 s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; 2272 if (s != NULL && s[0] == '-' && s[1] == '\0') 2273 s = NULL; 2274 2275 /* set/clear traps */ 2276 i = 0; 2277 while (*wp != NULL) 2278 if ((p = gettrap(*wp++, true)) == NULL) { 2279 warningf(true, "%s: %s '%s'", builtin_argv0, 2280 "bad signal", wp[-1]); 2281 ++i; 2282 } else 2283 settrap(p, s); 2284 return (i); 2285 } 2286 2287 int 2288 c_exitreturn(const char **wp) 2289 { 2290 int n, how = LEXIT; 2291 const char *arg; 2292 2293 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2294 goto c_exitreturn_err; 2295 arg = wp[builtin_opt.optind]; 2296 2297 if (arg) { 2298 if (!getn(arg, &n)) { 2299 exstat = 1; 2300 warningf(true, "%s: %s", arg, "bad number"); 2301 } else 2302 exstat = n & 0xFF; 2303 } else if (trap_exstat != -1) 2304 exstat = trap_exstat; 2305 if (wp[0][0] == 'r') { 2306 /* return */ 2307 struct env *ep; 2308 2309 /* 2310 * need to tell if this is exit or return so trap exit will 2311 * work right (POSIX) 2312 */ 2313 for (ep = e; ep; ep = ep->oenv) 2314 if (STOP_RETURN(ep->type)) { 2315 how = LRETURN; 2316 break; 2317 } 2318 } 2319 2320 if (how == LEXIT && !really_exit && j_stopped_running()) { 2321 really_exit = true; 2322 how = LSHELL; 2323 } 2324 2325 /* get rid of any i/o redirections */ 2326 quitenv(NULL); 2327 unwind(how); 2328 /* NOTREACHED */ 2329 2330 c_exitreturn_err: 2331 return (1); 2332 } 2333 2334 int 2335 c_brkcont(const char **wp) 2336 { 2337 unsigned int quit; 2338 int n; 2339 struct env *ep, *last_ep = NULL; 2340 const char *arg; 2341 2342 if (ksh_getopt(wp, &builtin_opt, null) == '?') 2343 goto c_brkcont_err; 2344 arg = wp[builtin_opt.optind]; 2345 2346 if (!arg) 2347 n = 1; 2348 else if (!bi_getn(arg, &n)) 2349 goto c_brkcont_err; 2350 if (n <= 0) { 2351 /* AT&T ksh does this for non-interactive shells only - weird */ 2352 bi_errorf("%s: %s", arg, "bad value"); 2353 goto c_brkcont_err; 2354 } 2355 quit = (unsigned int)n; 2356 2357 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ 2358 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) 2359 if (ep->type == E_LOOP) { 2360 if (--quit == 0) 2361 break; 2362 ep->flags |= EF_BRKCONT_PASS; 2363 last_ep = ep; 2364 } 2365 2366 if (quit) { 2367 /* 2368 * AT&T ksh doesn't print a message - just does what it 2369 * can. We print a message 'cause it helps in debugging 2370 * scripts, but don't generate an error (ie, keep going). 2371 */ 2372 if ((unsigned int)n == quit) { 2373 warningf(true, "%s: %s %s", wp[0], "can't", wp[0]); 2374 return (0); 2375 } 2376 /* 2377 * POSIX says if n is too big, the last enclosing loop 2378 * shall be used. Doesn't say to print an error but we 2379 * do anyway 'cause the user messed up. 2380 */ 2381 if (last_ep) 2382 last_ep->flags &= ~EF_BRKCONT_PASS; 2383 warningf(true, "%s: can only %s %u level(s)", 2384 wp[0], wp[0], (unsigned int)n - quit); 2385 } 2386 2387 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); 2388 /* NOTREACHED */ 2389 2390 c_brkcont_err: 2391 return (1); 2392 } 2393 2394 int 2395 c_set(const char **wp) 2396 { 2397 int argi; 2398 bool setargs; 2399 struct block *l = e->loc; 2400 const char **owp; 2401 2402 if (wp[1] == NULL) { 2403 static const char *args[] = { Tset, "-", NULL }; 2404 return (c_typeset(args)); 2405 } 2406 2407 argi = parse_args(wp, OF_SET, &setargs); 2408 if (argi < 0) 2409 return (1); 2410 /* set $# and $* */ 2411 if (setargs) { 2412 wp += argi - 1; 2413 owp = wp; 2414 /* save $0 */ 2415 wp[0] = l->argv[0]; 2416 while (*++wp != NULL) 2417 strdupx(*wp, *wp, &l->area); 2418 l->argc = wp - owp - 1; 2419 l->argv = alloc2(l->argc + 2, sizeof(char *), &l->area); 2420 for (wp = l->argv; (*wp++ = *owp++) != NULL; ) 2421 ; 2422 } 2423 /*- 2424 * POSIX says set exit status is 0, but old scripts that use 2425 * getopt(1) use the construct 2426 * set -- $(getopt ab:c "$@") 2427 * which assumes the exit value set will be that of the $() 2428 * (subst_exstat is cleared in execute() so that it will be 0 2429 * if there are no command substitutions). 2430 * Switched ksh (!posix !sh) to POSIX in mksh R39b. 2431 */ 2432 #ifdef MKSH_LEGACY_MODE 2433 return (subst_exstat); 2434 #else 2435 return (Flag(FSH) ? 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, (unsigned long)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 if (w == -1) { 3765 if (errno == EINTR) 3766 /* interrupted, try again */ 3767 continue; 3768 /* an error occured during writing */ 3769 eno = errno; 3770 bi_errorf("%s: %s", "<stdout>", 3771 cstrerror(eno)); 3772 rv = 1; 3773 if (fd != STDIN_FILENO) 3774 close(fd); 3775 goto out; 3776 } 3777 n -= w; 3778 cp += w; 3779 } 3780 } 3781 if (fd != STDIN_FILENO) 3782 close(fd); 3783 } while (*wp); 3784 3785 out: 3786 free_osfunc(buf); 3787 return (rv); 3788 } 3789 3790 #if HAVE_SELECT 3791 int 3792 c_sleep(const char **wp) 3793 { 3794 struct timeval tv; 3795 int rv = 1; 3796 3797 /* skip argv[0] */ 3798 ++wp; 3799 if (wp[0] && !strcmp(wp[0], "--")) 3800 /* skip "--" (options separator) */ 3801 ++wp; 3802 3803 if (!wp[0] || wp[1]) 3804 bi_errorf(Tsynerr); 3805 else if (parse_usec(wp[0], &tv)) 3806 bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno), wp[0]); 3807 else { 3808 #ifndef MKSH_NOPROSPECTOFWORK 3809 sigset_t omask, bmask; 3810 3811 /* block a number of signals from interrupting us, though */ 3812 (void)sigemptyset(&bmask); 3813 (void)sigaddset(&bmask, SIGPIPE); 3814 (void)sigaddset(&bmask, SIGCHLD); 3815 #ifdef SIGWINCH 3816 (void)sigaddset(&bmask, SIGWINCH); 3817 #endif 3818 #ifdef SIGINFO 3819 (void)sigaddset(&bmask, SIGINFO); 3820 #endif 3821 #ifdef SIGUSR1 3822 (void)sigaddset(&bmask, SIGUSR1); 3823 #endif 3824 #ifdef SIGUSR2 3825 (void)sigaddset(&bmask, SIGUSR2); 3826 #endif 3827 sigprocmask(SIG_BLOCK, &bmask, &omask); 3828 #endif 3829 if (select(1, NULL, NULL, NULL, &tv) == 0 || errno == EINTR) 3830 /* 3831 * strictly speaking only for SIGALRM, but the 3832 * execution may be interrupted by other signals 3833 */ 3834 rv = 0; 3835 else 3836 bi_errorf("%s: %s", Tselect, cstrerror(errno)); 3837 #ifndef MKSH_NOPROSPECTOFWORK 3838 /* this will re-schedule signal delivery */ 3839 sigprocmask(SIG_SETMASK, &omask, NULL); 3840 #endif 3841 } 3842 return (rv); 3843 } 3844 #endif 3845