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