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