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