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 $ */
7 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
8 * 2010, 2011, 2012, 2013
9 * Thorsten Glaser <tg@mirbsd.org>
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.
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.
30 #if HAVE_SYS_BSDTYPES_H
31 #include <sys/bsdtypes.h>
34 #include <sys/select.h>
41 __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
45 * use killpg if < -1 since -1 does special things
46 * for some non-killpg-endowed kills
48 #define mksh_kill(p,s) ((p) < -1 ? killpg(-(p), (s)) : kill((p), (s)))
50 /* cross fingers and hope kill is killpg-endowed */
51 #define mksh_kill kill
54 /* XXX conditions correct? */
55 #if !defined(RLIM_INFINITY) && !defined(MKSH_NO_LIMITS)
56 #define MKSH_NO_LIMITS 1
60 #define c_ulimit c_true
63 /* getn() that prints error */
65 bi_getn(const char *as, int *ai)
69 if (!(rv = getn(as, ai)))
70 bi_errorf("%s: %s", as, "bad number");
75 c_true(const char **wp MKSH_A_UNUSED)
81 c_false(const char **wp MKSH_A_UNUSED)
87 * A leading = means assignments before command are kept;
88 * a leading * means a POSIX special builtin;
89 * a leading + means a POSIX regular builtin
90 * (* and + should not be combined).
92 const struct builtin mkshbuiltins[] = {
96 {"*=break", c_brkcont},
97 {Tgbuiltin, c_builtin},
98 {"*=continue", c_brkcont},
101 {"*=exit", c_exitreturn},
103 {"*=return", c_exitreturn},
105 {"*=shift", c_shift},
112 {"ulimit", c_ulimit},
115 /* no =: AT&T manual wrong */
118 /* dash compatibility hack */
120 {"+command", c_command},
122 {Tsgexport, c_typeset},
124 {"+getopts", c_getopts},
125 {"=global", c_typeset},
130 #ifdef MKSH_PRINTF_BUILTIN
131 {"printf", c_printf},
134 {Tsgreadonly, c_typeset},
135 {T_typeset, c_typeset},
136 {Tpunalias, c_unalias},
137 {"whence", c_whence},
138 #ifndef MKSH_UNEMPLOYED
142 #ifndef MKSH_NO_CMDLINE_EDITING
149 {"realpath", c_realpath},
150 {"rename", c_rename},
155 /* alias to "true" for historical reasons */
156 {"domainname", c_true},
158 {NULL, (int (*)(const char **))NULL}
166 static const struct t_op {
196 static const struct t_op b_ops[] = {
214 static int test_oexpr(Test_env *, bool);
215 static int test_aexpr(Test_env *, bool);
216 static int test_nexpr(Test_env *, bool);
217 static int test_primary(Test_env *, bool);
218 static Test_op ptest_isa(Test_env *, Test_meta);
219 static const char *ptest_getopnd(Test_env *, Test_op, bool);
220 static void ptest_error(Test_env *, int, const char *);
221 static char *kill_fmt_entry(char *, size_t, unsigned int, const void *);
222 static void p_time(struct shf *, bool, long, int, int,
223 const char *, const char *);
226 c_pwd(const char **wp)
229 bool physical = tobool(Flag(FPHYSICAL));
230 char *p, *allocd = NULL;
232 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
243 wp += builtin_opt.optind;
246 bi_errorf("too many arguments");
249 p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) :
251 /* LINTED use of access */
252 if (p && access(p, R_OK) < 0)
254 if (!p && !(p = allocd = ksh_get_wd())) {
255 bi_errorf("%s: %s", "can't determine current directory",
260 afree(allocd, ATEMP);
264 static const char *s_ptr;
265 static int s_get(void);
266 static void s_put(int);
269 c_print(const char **wp)
271 #define PO_NL BIT(0) /* print newline */
272 #define PO_EXPAND BIT(1) /* expand backslash sequences */
273 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */
274 #define PO_HIST BIT(3) /* print to history instead of stdout */
275 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
277 int flags = PO_EXPAND | PO_NL;
278 const char *s, *emsg;
282 if (wp[0][0] == 'e') {
285 #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
288 * MidnightBSD /bin/sh needs a BSD echo, that is,
289 * one that supports -e but does not enable it by
296 #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
300 /* Debian Policy 10.4 compliant "echo" builtin */
301 if (*wp && !strcmp(*wp, "-n")) {
302 /* we recognise "-n" only as the first arg */
306 /* otherwise, we print everything as-is */
312 * a compromise between sysV and BSD echo commands:
313 * escape sequences are enabled by default, and -n,
314 * -e and -E are recognised if they appear in argu-
315 * ments with no illegal options (ie, echo -nq will
317 * Different from sysV echo since options are reco-
318 * gnised, different from BSD echo since escape se-
319 * quences are enabled by default.
322 while ((s = *wp) && *s == '-' && s[1]) {
329 nflags &= ~PO_EXPAND;
332 * bad option: don't use
333 * nflags, print argument
345 const char *opts = "Rnprsu,";
347 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
350 /* fake BSD echo command */
351 flags |= PO_PMINUSMINUS;
362 if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
363 bi_errorf("%s: %s", "-p", emsg);
374 if (!*(s = builtin_opt.optarg))
376 else if ((fd = check_fd(s, W_OK, &emsg)) < 0) {
377 bi_errorf("%s: %s: %s", "-u", s, emsg);
385 if (!(builtin_opt.info & GI_MINUSMINUS)) {
386 /* treat a lone - like -- */
387 if (wp[builtin_opt.optind] &&
388 ksh_isdash(wp[builtin_opt.optind]))
389 builtin_opt.optind++;
390 } else if (flags & PO_PMINUSMINUS)
391 builtin_opt.optind--;
392 wp += builtin_opt.optind;
395 Xinit(xs, xp, 128, ATEMP);
397 while (*wp != NULL) {
399 while ((c = *s++) != '\0') {
401 if ((flags & PO_EXPAND) && c == '\\') {
403 c = unbksl(false, s_get, s_put);
406 /* rejected by generic function */
407 switch ((c = *s++)) {
410 /* AT&T brain damage */
419 } else if ((unsigned int)c > 0xFF) {
420 /* generic function returned Unicode */
423 ts[utf_wctomb(ts, c - 0x100)] = 0;
424 for (c = 0; ts[c]; ++c)
437 if (flags & PO_HIST) {
439 histsave(&source->line, Xstring(xs, xp), true, false);
442 int len = Xlength(xs, xp);
446 * Ensure we aren't killed by a SIGPIPE while writing to
447 * a coprocess. AT&T ksh doesn't seem to do this (seems
448 * to just check that the co-process is alive which is
451 if (coproc.write >= 0 && coproc.write == fd) {
453 opipe = block_pipe();
455 for (s = Xstring(xs, xp); len > 0; ) {
456 if ((c = write(fd, s, len)) < 0) {
457 if (flags & PO_COPROC)
459 if (errno == EINTR) {
460 /* allow user to ^C out */
462 if (flags & PO_COPROC)
463 opipe = block_pipe();
471 if (flags & PO_COPROC)
485 s_put(int c MKSH_A_UNUSED)
491 c_whence(const char **wp)
495 bool pflag = false, vflag = false, Vflag = false;
496 int rv = 0, optc, fcflags;
497 bool iam_whence = wp[0][0] == 'w';
498 const char *opts = iam_whence ? "pv" : "pvV";
500 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
514 wp += builtin_opt.optind;
516 fcflags = FC_BI | FC_PATH | FC_FUNC;
518 /* Note that -p on its own is deal with in comexec() */
520 fcflags |= FC_DEFPATH;
522 * Convert command options to whence options - note that
523 * command -pV uses a different path search than whence -v
524 * or whence -pv. This should be considered a feature.
529 fcflags &= ~(FC_BI | FC_FUNC);
531 while ((vflag || rv == 0) && (id = *wp++) != NULL) {
535 if ((iam_whence || vflag) && !pflag)
536 tp = ktsearch(&keywords, id, h = hash(id));
538 tp = ktsearch(&aliases, id, h ? h : hash(id));
539 if (tp && !(tp->flag & ISSET))
543 tp = findcom(id, fcflags);
544 if (vflag || (tp->type != CALIAS && tp->type != CEXEC &&
545 tp->type != CTALIAS))
546 shf_puts(id, shl_stdout);
553 shf_puts(" is a", shl_stdout);
560 shf_puts(" reserved word", shl_stdout);
564 shprintf("n %s%s for ",
565 (tp->flag & EXPORT) ? "exported " : null,
567 if (!iam_whence && !vflag)
568 shprintf("%s %s=", Talias, id);
569 print_value_quoted(shl_stdout, tp->val.s);
573 if (tp->flag & EXPORT)
574 shf_puts("n exported", shl_stdout);
575 if (tp->flag & TRACE)
576 shf_puts(" traced", shl_stdout);
577 if (!(tp->flag & ISSET)) {
578 shf_puts(" undefined", shl_stdout);
580 shprintf(" (autoload from %s)",
583 shf_puts(T_function, shl_stdout);
589 (tp->flag & SPEC_BI) ? " special" : null,
594 if (tp->flag & ISSET) {
596 shf_puts(" is ", shl_stdout);
597 if (tp->type == CTALIAS)
598 shprintf("a tracked %s%s for ",
599 (tp->flag & EXPORT) ?
603 shf_puts(tp->val.s, shl_stdout);
606 shprintf(" %s\n", "not found");
611 shprintf("%s is *GOK*", id);
615 shf_putc('\n', shl_stdout);
620 /* Deal with command -vV - command -p dealt with in comexec() */
622 c_command(const char **wp)
625 * Let c_whence do the work. Note that c_command() must be
626 * a distinct function from c_whence() (tested in comexec()).
628 return (c_whence(wp));
631 /* typeset, global, export, and readonly */
632 static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
633 static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
636 c_typeset(const char **wp)
639 uint32_t fset = 0, fclr = 0, flag;
640 int thing = 0, field = 0, base = 0, i;
643 const char *fieldstr = NULL, *basestr = NULL;
644 bool localv = false, func = false, pflag = false, istset = true;
662 /* called with 'typeset -' */
671 /* see comment below regarding possible opions */
672 opts = istset ? "L#R#UZ#afi#lnprtux" : "p";
674 builtin_opt.flags |= GF_PLUSOPT;
676 * AT&T ksh seems to have 0-9 as options which are multiplied
677 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
678 * sets right justify in a field of 12). This allows options
679 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
680 * does not allow the number to be specified as a separate argument
681 * Here, the number must follow the RLZi option, but is optional
682 * (see the # kludge in ksh_getopt()).
684 while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) {
689 fieldstr = builtin_opt.optarg;
693 fieldstr = builtin_opt.optarg;
697 * AT&T ksh uses u, but this conflicts with
698 * upper/lower case. If this option is changed,
699 * need to change the -U below as well
705 fieldstr = builtin_opt.optarg;
709 * this is supposed to set (-a) or unset (+a) the
710 * indexed array attribute; it does nothing on an
711 * existing regular string or indexed array though
719 basestr = builtin_opt.optarg;
725 set_refflag = (builtin_opt.info & GI_PLUS) ?
726 SRF_DISABLE : SRF_ENABLE;
728 /* export, readonly: POSIX -p flag */
730 /* typeset: show values as well */
742 /* upper case / autoload */
750 set_refflag = SRF_NOP;
753 if (builtin_opt.info & GI_PLUS) {
764 if (fieldstr && !bi_getn(fieldstr, &field))
766 if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
767 bi_errorf("%s: %s", "bad integer base", basestr);
771 if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
772 (wp[builtin_opt.optind][0] == '-' ||
773 wp[builtin_opt.optind][0] == '+') &&
774 wp[builtin_opt.optind][1] == '\0') {
775 thing = wp[builtin_opt.optind][0];
776 builtin_opt.optind++;
779 if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
780 set_refflag != SRF_NOP)) {
781 bi_errorf("only -t, -u and -x options may be used with -f");
784 if (wp[builtin_opt.optind]) {
786 * Take care of exclusions.
787 * At this point, flags in fset are cleared in fclr and vice
788 * versa. This property should be preserved.
791 /* LCASEV has priority over UCASEV_AL */
794 /* LJUST has priority over RJUST */
796 if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) {
802 * Setting these attributes clears the others, unless they
803 * are also set in this command
805 if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
806 INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP)
807 fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
808 LCASEV | INTEGER | INT_U | INT_L);
811 /* set variables and attributes */
812 if (wp[builtin_opt.optind] &&
813 /* not "typeset -p varname" */
814 !(!func && pflag && !(fset | fclr))) {
820 for (i = builtin_opt.optind; wp[i]; i++) {
822 f = findfunc(wp[i], hash(wp[i]),
823 tobool(fset & UCASEV_AL));
825 /* AT&T ksh does ++rv: bogus */
833 fpFUNCTf(shl_stdout, 0,
834 tobool(f->flag & FKSH),
836 shf_putc('\n', shl_stdout);
838 } else if (!typeset(wp[i], fset, fclr, field, base)) {
839 bi_errorf("%s: %s", wp[i], "not identifier");
843 set_refflag = SRF_NOP;
847 set_refflag = SRF_NOP;
848 /* list variables and attributes */
850 /* no difference at this point.. */
853 for (l = e->loc; l; l = l->next) {
854 for (p = ktsort(&l->funs); (vp = *p++); ) {
855 if (flag && (vp->flag & flag) == 0)
858 fpFUNCTf(shl_stdout, 0,
859 tobool(vp->flag & FKSH),
860 vp->name, vp->val.t);
862 shf_puts(vp->name, shl_stdout);
863 shf_putc('\n', shl_stdout);
866 } else if (wp[builtin_opt.optind]) {
867 for (i = builtin_opt.optind; wp[i]; i++) {
868 varsearch(e->loc, &vp, wp[i], hash(wp[i]));
869 c_typeset_vardump(vp, flag, thing, pflag, istset);
872 c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset);
877 c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing,
878 bool pflag, bool istset)
880 struct tbl **blockvars, *vp;
883 c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset);
884 blockvars = ktsort(&l->vars);
885 while ((vp = *blockvars++))
886 c_typeset_vardump(vp, flag, thing, pflag, istset);
887 /*XXX doesn’t this leak? */
891 c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
902 * See if the parameter is set (for arrays, if any
905 for (tvp = vp; tvp; tvp = tvp->u.array)
906 if (tvp->flag & ISSET) {
912 * Check attributes - note that all array elements
913 * have (should have?) the same attributes, so checking
914 * the first is sufficient.
916 * Report an unset param only if the user has
917 * explicitly given it some attribute (like export);
918 * otherwise, after "echo $FOO", we would report FOO...
920 if (!any_set && !(vp->flag & USERATTRIB))
922 if (flag && (vp->flag & flag) == 0)
924 if (!(vp->flag & ARRAY))
925 /* optimise later conditionals */
929 * Ignore array elements that aren't set unless there
930 * are no set elements, in which case the first is
933 if (any_set && !(vp->flag & ISSET))
936 if (!thing && !flag) {
938 shprintf("%s %s %s\n", Tset, "-A", vp->name);
942 * AT&T ksh prints things like export, integer,
943 * leftadj, zerofill, etc., but POSIX says must
944 * be suitable for re-entry...
946 shprintf("%s %s", Ttypeset, "");
947 if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
948 shprintf("%s ", "-n");
949 if ((vp->flag & INTEGER))
950 shprintf("%s ", "-i");
951 if ((vp->flag & EXPORT))
952 shprintf("%s ", "-x");
953 if ((vp->flag & RDONLY))
954 shprintf("%s ", "-r");
955 if ((vp->flag & TRACE))
956 shprintf("%s ", "-t");
957 if ((vp->flag & LJUST))
958 shprintf("-L%d ", vp->u2.field);
959 if ((vp->flag & RJUST))
960 shprintf("-R%d ", vp->u2.field);
961 if ((vp->flag & ZEROFIL))
962 shprintf("%s ", "-Z");
963 if ((vp->flag & LCASEV))
964 shprintf("%s ", "-l");
965 if ((vp->flag & UCASEV_AL))
966 shprintf("%s ", "-u");
967 if ((vp->flag & INT_U))
968 shprintf("%s ", "-U");
970 shprintf("%s %s", istset ? Ttypeset :
971 (flag & EXPORT) ? Texport : Treadonly, "");
974 shprintf("%s[%lu]", vp->name, arrayindex(vp));
976 shf_puts(vp->name, shl_stdout);
977 if ((!thing && !flag && pflag) ||
978 (thing == '-' && (vp->flag & ISSET))) {
980 shf_putc('=', shl_stdout);
981 /* AT&T ksh can't have justified integers... */
982 if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER)
983 shf_puts(s, shl_stdout);
985 print_value_quoted(shl_stdout, s);
987 shf_putc('\n', shl_stdout);
990 * Only report first 'element' of an array with
995 } while ((vp = vp->u.array));
999 c_alias(const char **wp)
1001 struct table *t = &aliases;
1002 int rv = 0, prefix = 0;
1003 bool rflag = false, tflag, Uflag = false, pflag = false;
1007 builtin_opt.flags |= GF_PLUSOPT;
1008 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) {
1009 prefix = builtin_opt.info & GI_PLUS ? '+' : '-';
1013 t = NULL; /* fix "alias -dt" */
1029 * kludge for tracked alias initialization
1030 * (don't do a path search, just make an entry)
1045 wp += builtin_opt.optind;
1047 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp &&
1048 (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') {
1053 tflag = t == &taliases;
1055 /* "hash -r" means reset all the tracked aliases.. */
1057 static const char *args[] = {
1058 Tunalias, "-ta", NULL
1061 if (!tflag || *wp) {
1062 shprintf("%s: -r flag can only be used with -t"
1063 " and without arguments\n", Talias);
1066 ksh_getopt_reset(&builtin_opt, GF_ERROR);
1067 return (c_unalias(args));
1071 struct tbl *ap, **p;
1073 for (p = ktsort(t); (ap = *p++) != NULL; )
1074 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
1076 shprintf("%s ", Talias);
1077 shf_puts(ap->name, shl_stdout);
1078 if (prefix != '+') {
1079 shf_putc('=', shl_stdout);
1080 print_value_quoted(shl_stdout, ap->val.s);
1082 shf_putc('\n', shl_stdout);
1086 for (; *wp != NULL; wp++) {
1087 const char *alias = *wp, *val, *newval;
1088 char *xalias = NULL;
1092 if ((val = cstrchr(alias, '='))) {
1093 strndupx(xalias, alias, val++ - alias, ATEMP);
1097 if (val == NULL && !tflag && !xflag) {
1098 ap = ktsearch(t, alias, h);
1099 if (ap != NULL && (ap->flag&ISSET)) {
1101 shprintf("%s ", Talias);
1102 shf_puts(ap->name, shl_stdout);
1103 if (prefix != '+') {
1104 shf_putc('=', shl_stdout);
1105 print_value_quoted(shl_stdout, ap->val.s);
1107 shf_putc('\n', shl_stdout);
1109 shprintf("%s %s %s\n", alias, Talias,
1115 ap = ktenter(t, alias, h);
1116 ap->type = tflag ? CTALIAS : CALIAS;
1117 /* Are we setting the value or just some flags? */
1118 if ((val && !tflag) || (!val && tflag && !Uflag)) {
1119 if (ap->flag&ALLOC) {
1120 ap->flag &= ~(ALLOC|ISSET);
1121 afree(ap->val.s, APERM);
1123 /* ignore values for -t (AT&T ksh does this) */
1125 search_path(alias, path, X_OK, NULL) :
1128 strdupx(ap->val.s, newval, APERM);
1129 ap->flag |= ALLOC|ISSET;
1133 ap->flag |= DEFINED;
1138 afree(xalias, ATEMP);
1145 c_unalias(const char **wp)
1147 struct table *t = &aliases;
1152 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1)
1159 /* fix "unalias -dt" */
1175 wp += builtin_opt.optind;
1177 for (; *wp != NULL; wp++) {
1178 ap = ktsearch(t, *wp, hash(*wp));
1184 if (ap->flag&ALLOC) {
1185 ap->flag &= ~(ALLOC|ISSET);
1186 afree(ap->val.s, APERM);
1188 ap->flag &= ~(DEFINED|ISSET|EXPORT);
1194 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) {
1195 if (ap->flag&ALLOC) {
1196 ap->flag &= ~(ALLOC|ISSET);
1197 afree(ap->val.s, APERM);
1199 ap->flag &= ~(DEFINED|ISSET|EXPORT);
1207 c_let(const char **wp)
1213 /* AT&T ksh does this */
1214 bi_errorf("no arguments");
1216 for (wp++; *wp; wp++)
1217 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) {
1218 /* distinguish error from zero result */
1227 c_jobs(const char **wp)
1229 int optc, flag = 0, nflag = 0, rv = 0;
1231 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1)
1243 /* debugging: print zombies */
1249 wp += builtin_opt.optind;
1251 if (j_jobs(NULL, flag, nflag))
1255 if (j_jobs(*wp, flag, nflag))
1261 #ifndef MKSH_UNEMPLOYED
1263 c_fgbg(const char **wp)
1265 bool bg = strcmp(*wp, "bg") == 0;
1268 if (!Flag(FMONITOR)) {
1269 bi_errorf("job control not enabled");
1272 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1274 wp += builtin_opt.optind;
1277 rv = j_resume(*wp, bg);
1279 rv = j_resume("%%", bg);
1280 return (bg ? 0 : rv);
1284 /* format a single kill item */
1286 kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
1288 const struct kill_info *ki = (const struct kill_info *)arg;
1291 shf_snprintf(buf, buflen, "%*u %*s %s",
1293 ki->name_width, sigtraps[i].name,
1299 c_kill(const char **wp)
1306 /* assume old style options if -digits or -UPPERCASE */
1307 if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) ||
1308 ksh_isupper(p[1]))) {
1309 if (!(t = gettrap(p + 1, false))) {
1310 bi_errorf("bad signal '%s'", p + 1);
1313 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
1317 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1)
1323 if (!(t = gettrap(builtin_opt.optarg, true))) {
1324 bi_errorf("bad signal '%s'",
1325 builtin_opt.optarg);
1332 i = builtin_opt.optind;
1334 if ((lflag && t) || (!wp[i] && !lflag)) {
1336 shf_puts("usage:\tkill [-s signame | -signum | -signame]"
1337 " { job | pid | pgrp } ...\n"
1338 "\tkill -l [exit_status ...]\n", shl_out);
1346 for (; wp[i]; i++) {
1347 if (!bi_getn(wp[i], &n))
1349 if (n > 128 && n < 128 + NSIG)
1351 if (n > 0 && n < NSIG)
1352 shprintf("%s\n", sigtraps[n].name);
1354 shprintf("%d\n", n);
1357 ssize_t w, mess_cols, mess_octs;
1359 struct kill_info ki;
1361 for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10)
1363 ki.name_width = mess_cols = mess_octs = 0;
1364 for (j = 0; j < NSIG; j++) {
1365 w = strlen(sigtraps[j].name);
1366 if (w > ki.name_width)
1368 w = strlen(sigtraps[j].mess);
1371 w = utf_mbswidth(sigtraps[j].mess);
1376 print_columns(shl_stdout, (unsigned int)(NSIG - 1),
1377 kill_fmt_entry, (void *)&ki,
1378 ki.num_width + 1 + ki.name_width + 1 + mess_octs,
1379 ki.num_width + 1 + ki.name_width + 1 + mess_cols,
1385 sig = t ? t->signal : SIGTERM;
1386 for (; (p = wp[i]); i++) {
1390 } else if (!getn(p, &n)) {
1391 bi_errorf("%s: %s", p,
1392 "arguments must be jobs or process IDs");
1395 if (mksh_kill(n, sig) < 0) {
1396 bi_errorf("%s: %s", p, cstrerror(errno));
1405 getopts_reset(int val)
1408 ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT);
1409 user_opt.optind = user_opt.uoptind = val;
1414 c_getopts(const char **wp)
1417 const char *opts, *var;
1419 struct tbl *vq, *voptarg;
1421 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1423 wp += builtin_opt.optind;
1427 bi_errorf("missing %s argument", "options");
1433 bi_errorf("missing %s argument", "name");
1436 if (!*var || *skip_varname(var, true)) {
1437 bi_errorf("%s: %s", var, "is not an identifier");
1441 if (e->loc->next == NULL) {
1442 internal_warningf("%s: %s", "c_getopts", "no argv");
1445 /* Which arguments are we parsing... */
1447 wp = e->loc->next->argv;
1449 *--wp = e->loc->next->argv[0];
1451 /* Check that our saved state won't cause a core dump... */
1452 for (argc = 0; wp[argc]; argc++)
1454 if (user_opt.optind > argc ||
1456 user_opt.p > strlen(wp[user_opt.optind - 1]))) {
1457 bi_errorf("arguments changed since last call");
1461 user_opt.optarg = NULL;
1462 optc = ksh_getopt(wp, &user_opt, opts);
1464 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
1470 * POSIX says var is set to ? at end-of-options, AT&T ksh
1471 * sets it to null - we go with POSIX...
1473 buf[0] = optc < 0 ? '?' : optc;
1477 /* AT&T ksh93 in fact does change OPTIND for unknown options too */
1478 user_opt.uoptind = user_opt.optind;
1480 voptarg = global("OPTARG");
1481 /* AT&T ksh clears ro and int */
1482 voptarg->flag &= ~RDONLY;
1483 /* Paranoia: ensure no bizarre results. */
1484 if (voptarg->flag & INTEGER)
1485 typeset("OPTARG", 0, INTEGER, 0, 0);
1486 if (user_opt.optarg == NULL)
1489 /* This can't fail (have cleared readonly/integer) */
1490 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
1495 /* Error message already printed (integer, readonly) */
1496 if (!setstr(vq, buf, KSH_RETURN_ERROR))
1499 typeset(var, EXPORT, 0, 0, 0);
1501 return (optc < 0 ? 1 : rv);
1504 #ifndef MKSH_NO_CMDLINE_EDITING
1506 c_bind(const char **wp)
1516 while ((optc = ksh_getopt(wp, &builtin_opt,
1535 wp += builtin_opt.optind;
1539 rv = x_bind(NULL, NULL,
1545 for (; *wp != NULL; wp++) {
1546 if ((cp = cstrchr(*wp, '=')) == NULL)
1549 strdupx(up, *wp, ATEMP);
1550 up[cp++ - *wp] = '\0';
1552 if (x_bind(up ? up : *wp, cp,
1566 c_shift(const char **wp)
1568 struct block *l = e->loc;
1573 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1575 arg = wp[builtin_opt.optind];
1578 evaluate(arg, &val, KSH_UNWIND_ERROR, false);
1583 bi_errorf("%s: %s", arg, "bad number");
1587 bi_errorf("nothing to shift");
1590 l->argv[n] = l->argv[0];
1597 c_umask(const char **wp)
1601 bool symbolic = false;
1604 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
1612 cp = wp[builtin_opt.optind];
1614 old_umask = umask((mode_t)0);
1620 old_umask = ~old_umask;
1622 for (i = 0; i < 3; i++) {
1625 for (j = 0; j < 3; j++)
1626 if (old_umask & (1 << (8 - (3*i + j))))
1631 shprintf("%s\n", buf);
1633 shprintf("%#3.3o\n", (unsigned int)old_umask);
1637 if (ksh_isdigit(*cp)) {
1638 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
1639 new_umask = new_umask * 8 + (*cp - '0');
1641 bi_errorf("bad number");
1645 /* symbolic format */
1646 int positions, new_val;
1649 old_umask = umask((mode_t)0);
1650 /* in case of error */
1652 old_umask = ~old_umask;
1653 new_umask = old_umask;
1656 while (*cp && vstrchr("augo", *cp))
1674 if (!vstrchr("=+-", op = *cp))
1678 while (*cp && vstrchr("rwxugoXs", *cp))
1680 case 'r': new_val |= 04; break;
1681 case 'w': new_val |= 02; break;
1682 case 'x': new_val |= 01; break;
1684 new_val |= old_umask >> 6;
1687 new_val |= old_umask >> 3;
1690 new_val |= old_umask >> 0;
1693 if (old_umask & 0111)
1700 new_val = (new_val & 07) * positions;
1703 new_umask &= ~new_val;
1706 new_umask = new_val |
1707 (new_umask & ~(positions * 07));
1710 new_umask |= new_val;
1715 } else if (!vstrchr("=+-", *cp))
1719 bi_errorf("bad mask");
1722 new_umask = ~new_umask;
1730 c_dot(const char **wp)
1732 const char *file, *cp, **argv;
1733 int argc, i, errcode;
1735 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1738 if ((cp = wp[builtin_opt.optind]) == NULL) {
1739 bi_errorf("missing argument");
1742 if ((file = search_path(cp, path, R_OK, &errcode)) == NULL) {
1743 bi_errorf("%s: %s", cp, cstrerror(errcode));
1747 /* Set positional parameters? */
1748 if (wp[builtin_opt.optind + 1]) {
1749 argv = wp + builtin_opt.optind;
1751 argv[0] = e->loc->argv[0];
1752 for (argc = 0; argv[argc + 1]; argc++)
1758 if ((i = include(file, argc, argv, false)) < 0) {
1759 /* should not happen */
1760 bi_errorf("%s: %s", cp, cstrerror(errno));
1767 c_wait(const char **wp)
1771 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1773 wp += builtin_opt.optind;
1775 while (waitfor(NULL, &sig) >= 0)
1780 rv = waitfor(*wp, &sig);
1782 /* magic exit code: bad job-id */
1783 rv = sig ? sig : 127;
1788 static char REPLY[] = "REPLY";
1790 c_read(const char **wp)
1792 #define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
1793 int c, fd = 0, rv = 0, lastparm = 0;
1794 bool savehist = false, intoarray = false, aschars = false;
1795 bool rawmode = false, expanding = false;
1796 enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
1798 size_t bytesleft = 128, bytesread;
1799 struct tbl *vp /* FU gcc */ = NULL, *vq;
1800 char *cp, *allocd = NULL, *xp;
1803 ptrdiff_t xsave = 0;
1805 bool restore_tios = false;
1807 bool hastimeout = false;
1808 struct timeval tv, tvlim;
1809 #define c_read_opts "Aad:N:n:prst:u,"
1811 #define c_read_opts "Aad:N:n:prsu,"
1814 while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
1823 delim = builtin_opt.optarg[0];
1827 readmode = c == 'N' ? BYTES : UPTO;
1828 if (!bi_getn(builtin_opt.optarg, &c))
1834 bytesleft = (unsigned int)c;
1837 if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
1838 bi_errorf("%s: %s", "-p", ccp);
1850 if (parse_usec(builtin_opt.optarg, &tv)) {
1851 bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno),
1852 builtin_opt.optarg);
1859 if (!builtin_opt.optarg[0])
1861 else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
1862 bi_errorf("%s: %s: %s", "-u", builtin_opt.optarg, ccp);
1869 wp += builtin_opt.optind;
1873 if (intoarray && wp[1] != NULL) {
1874 bi_errorf("too many arguments");
1878 if ((ccp = cstrchr(*wp, '?')) != NULL) {
1879 strdupx(allocd, *wp, ATEMP);
1880 allocd[ccp - *wp] = '\0';
1884 * AT&T ksh says it prints prompt on fd if it's open
1885 * for writing and is a tty, but it doesn't do it
1886 * (it also doesn't check the interactive flag,
1887 * as is indicated in the Korn Shell book).
1889 shf_puts(ccp + 1, shl_out);
1894 Xinit(xs, xp, bytesleft, ATEMP);
1896 if (readmode == LINES)
1898 else if (isatty(fd)) {
1899 x_mkraw(fd, &tios, true);
1900 restore_tios = true;
1906 timeradd(&tvlim, &tv, &tvlim);
1916 FD_SET((unsigned int)fd, &fdset);
1918 timersub(&tvlim, &tv, &tv);
1919 if (tv.tv_sec < 0) {
1920 /* timeout expired globally */
1925 switch (select(fd + 1, &fdset, NULL, NULL, &tv)) {
1929 /* timeout expired for this call */
1933 bi_errorf("%s: %s", Tselect, cstrerror(errno));
1940 bytesread = blocking_read(fd, xp, bytesleft);
1941 if (bytesread == (size_t)-1) {
1943 if (errno == EINTR && fatal_trap_check()) {
1945 * Was the offending signal one that would
1946 * normally kill a process? If so, pretend
1947 * the read was killed.
1952 /* just ignore the signal */
1953 goto c_read_readloop;
1958 if (bytesread == 0) {
1959 /* end of file reached */
1961 goto c_read_readdone;
1964 XcheckN(xs, xp, bytesleft);
1969 /* end of file reached */
1972 goto c_read_readdone;
1975 if (bytesread == 0) {
1976 /* end of file reached */
1978 xp = Xstring(xs, xp);
1979 goto c_read_readdone;
1982 if ((bytesleft -= bytesread) == 0)
1983 goto c_read_readdone;
1986 if (bytesread == 0) {
1987 /* end of file reached */
1989 goto c_read_readdone;
1991 if ((c = *xp) == '\0' && !aschars && delim != '\0') {
1992 /* skip any read NULs unless delimiter */
1998 if (Flag(FTALKING_I) && isatty(fd)) {
2000 * set prompt in case this is
2001 * called from .profile or $ENV
2003 set_prompt(PS2, NULL);
2006 /* drop the backslash */
2008 /* and the delimiter */
2011 } else if (c == delim) {
2012 goto c_read_readdone;
2013 } else if (!rawmode && c == '\\') {
2020 goto c_read_readloop;
2023 bytesread = Xlength(xs, xp);
2027 * state: we finished reading the input and NUL terminated it
2028 * Xstring(xs, xp) -> xp-1 = input string without trailing delim
2029 * rv = 1 if EOF, 0 otherwise (errors handled already)
2033 /* clean up coprocess if needed, on EOF */
2034 coproc_read_close(fd);
2035 if (readmode == READALL)
2036 /* EOF is no error here */
2041 histsave(&source->line, Xstring(xs, xp), true, false);
2043 ccp = cp = Xclose(xs, xp);
2045 XinitN(xs, 128, ATEMP);
2048 if (vp->flag & RDONLY) {
2050 bi_errorf("read-only: %s", *wp);
2056 /* exporting an array is currently pointless */
2058 /* counter for array index */
2062 /* skip initial IFS whitespace */
2063 while (bytesread && is_ifsws(*ccp)) {
2067 /* trim trailing IFS whitespace */
2068 while (bytesread && is_ifsws(ccp[bytesread - 1])) {
2073 xp = Xstring(xs, xp);
2074 /* generate next word */
2078 goto c_read_splitdone;
2079 /* zero out next parameters */
2080 goto c_read_gotword;
2085 bytesleft = utf_ptradj(ccp);
2086 while (bytesleft && bytesread) {
2091 if (xp[-1] == '\0') {
2095 goto c_read_gotword;
2098 if (!intoarray && wp[1] == NULL)
2102 /* copy until IFS character */
2109 goto c_read_splitcopy;
2110 } else if (ctype(ch, C_IFS)) {
2112 } else if (!rawmode && ch == '\\') {
2122 xsave = Xsavepos(xs, xp);
2123 /* copy word delimiter: IFSWS+IFS,IFSWS */
2128 if (!ctype(ch, C_IFS))
2134 if (!ctype(ch, C_IFSWS))
2137 while (bytesread && is_ifsws(*ccp)) {
2143 /* if no more parameters, rinse and repeat */
2144 if (lastparm && bytesread) {
2146 goto c_read_splitlast;
2148 /* get rid of the delimiter unless we pack the rest */
2150 xp = Xrestpos(xs, xp, xsave);
2154 vq = arraysearch(vp, c++);
2157 /* must be checked before exporting */
2158 if (vq->flag & RDONLY)
2159 goto c_read_splitro;
2161 typeset(*wp, EXPORT, 0, 0, 0);
2163 if (!setstr(vq, Xstring(xs, xp), KSH_RETURN_ERROR))
2164 goto c_read_spliterr;
2166 setint_v(vq, vq, false);
2167 /* protect from UTFMODE changes */
2170 if (intoarray || *++wp != NULL)
2171 goto c_read_splitloop;
2178 afree(allocd, ATEMP);
2181 mksh_tcset(fd, &tios);
2187 c_eval(const char **wp)
2189 struct source *s, *saves = source;
2190 unsigned char savef;
2193 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2195 s = pushs(SWORDS, ATEMP);
2196 s->u.strv = wp + builtin_opt.optind;
2199 * The following code handles the case where the command is
2200 * empty due to failed command substitution, for example by
2202 * This has historically returned 1 by AT&T ksh88. In this
2203 * case, shell() will not set or change exstat because the
2204 * compiled tree is empty, so it will use the value we pass
2205 * from subst_exstat, which is cleared in execute(), so it
2206 * should have been 0 if there were no substitutions.
2208 * POSIX however says we don't do this, even though it is
2209 * traditionally done. AT&T ksh93 agrees with POSIX, so we
2210 * do. The following is an excerpt from SUSv4 [1003.2-2008]:
2212 * 2.9.1: Simple Commands
2213 * ... If there is a command name, execution shall
2214 * continue as described in 2.9.1.1 [Command Search
2215 * and Execution]. If there is no command name, but
2216 * the command contained a command substitution, the
2217 * command shall complete with the exit status of the
2218 * last command substitution performed.
2219 * 2.9.1.1: Command Search and Execution
2220 * (1) a. If the command name matches the name of a
2221 * special built-in utility, that special built-in
2222 * utility shall be invoked.
2224 * If there are no arguments, or only null arguments,
2225 * eval shall return a zero exit status; ...
2227 /* AT&T ksh88: use subst_exstat */
2228 /* exstat = subst_exstat; */
2229 /* SUSv4: OR with a high value never written otherwise */
2232 savef = Flag(FERREXIT);
2233 Flag(FERREXIT) |= 0x80;
2234 rv = shell(s, false);
2235 Flag(FERREXIT) = savef;
2238 if (exstat & 0x4000)
2239 /* detect old exstat, use 0 in that case */
2245 c_trap(const char **wp)
2251 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2253 wp += builtin_opt.optind;
2256 for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
2257 if (p->trap != NULL) {
2258 shf_puts("trap -- ", shl_stdout);
2259 print_value_quoted(shl_stdout, p->trap);
2260 shprintf(" %s\n", p->name);
2266 * Use case sensitive lookup for first arg so the
2267 * command 'exit' isn't confused with the pseudo-signal
2271 s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL;
2272 if (s != NULL && s[0] == '-' && s[1] == '\0')
2275 /* set/clear traps */
2278 if ((p = gettrap(*wp++, true)) == NULL) {
2279 warningf(true, "%s: %s '%s'", builtin_argv0,
2280 "bad signal", wp[-1]);
2288 c_exitreturn(const char **wp)
2293 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2294 goto c_exitreturn_err;
2295 arg = wp[builtin_opt.optind];
2298 if (!getn(arg, &n)) {
2300 warningf(true, "%s: %s", arg, "bad number");
2303 } else if (trap_exstat != -1)
2304 exstat = trap_exstat;
2305 if (wp[0][0] == 'r') {
2310 * need to tell if this is exit or return so trap exit will
2311 * work right (POSIX)
2313 for (ep = e; ep; ep = ep->oenv)
2314 if (STOP_RETURN(ep->type)) {
2320 if (how == LEXIT && !really_exit && j_stopped_running()) {
2325 /* get rid of any i/o redirections */
2335 c_brkcont(const char **wp)
2339 struct env *ep, *last_ep = NULL;
2342 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2344 arg = wp[builtin_opt.optind];
2348 else if (!bi_getn(arg, &n))
2351 /* AT&T ksh does this for non-interactive shells only - weird */
2352 bi_errorf("%s: %s", arg, "bad value");
2355 quit = (unsigned int)n;
2357 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
2358 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
2359 if (ep->type == E_LOOP) {
2362 ep->flags |= EF_BRKCONT_PASS;
2368 * AT&T ksh doesn't print a message - just does what it
2369 * can. We print a message 'cause it helps in debugging
2370 * scripts, but don't generate an error (ie, keep going).
2372 if ((unsigned int)n == quit) {
2373 warningf(true, "%s: %s %s", wp[0], "can't", wp[0]);
2377 * POSIX says if n is too big, the last enclosing loop
2378 * shall be used. Doesn't say to print an error but we
2379 * do anyway 'cause the user messed up.
2382 last_ep->flags &= ~EF_BRKCONT_PASS;
2383 warningf(true, "%s: can only %s %u level(s)",
2384 wp[0], wp[0], (unsigned int)n - quit);
2387 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
2395 c_set(const char **wp)
2399 struct block *l = e->loc;
2402 if (wp[1] == NULL) {
2403 static const char *args[] = { Tset, "-", NULL };
2404 return (c_typeset(args));
2407 argi = parse_args(wp, OF_SET, &setargs);
2416 while (*++wp != NULL)
2417 strdupx(*wp, *wp, &l->area);
2418 l->argc = wp - owp - 1;
2419 l->argv = alloc2(l->argc + 2, sizeof(char *), &l->area);
2420 for (wp = l->argv; (*wp++ = *owp++) != NULL; )
2424 * POSIX says set exit status is 0, but old scripts that use
2425 * getopt(1) use the construct
2426 * set -- $(getopt ab:c "$@")
2427 * which assumes the exit value set will be that of the $()
2428 * (subst_exstat is cleared in execute() so that it will be 0
2429 * if there are no command substitutions).
2430 * Switched ksh (!posix !sh) to POSIX in mksh R39b.
2432 #ifdef MKSH_LEGACY_MODE
2433 return (subst_exstat);
2435 return (Flag(FSH) ? subst_exstat : 0);
2440 c_unset(const char **wp)
2444 bool unset_var = true;
2446 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
2455 /*XXX not reached due to GF_ERROR */
2458 wp += builtin_opt.optind;
2459 for (; (id = *wp) != NULL; wp++)
2461 /* unset variable */
2467 if (n > 3 && id[n-3] == '[' && id[n-2] == '*' &&
2469 strndupx(cp, id, n - 3, ATEMP);
2473 optc = vstrchr(id, '[') ? 0 : 1;
2478 if ((vp->flag&RDONLY)) {
2479 warningf(true, "read-only: %s", vp->name);
2484 /* unset function */
2490 p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width,
2491 const char *prefix, const char *suffix)
2495 shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width,
2496 tv_sec, tv_usec, suffix);
2498 shf_fprintf(shf, "%s%*ldm%d.%02ds%s", prefix, width,
2499 tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix);
2503 c_times(const char **wp MKSH_A_UNUSED)
2505 struct rusage usage;
2507 getrusage(RUSAGE_SELF, &usage);
2508 p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2509 usage.ru_utime.tv_usec, 0, null, " ");
2510 p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2511 usage.ru_stime.tv_usec, 0, null, "\n");
2513 getrusage(RUSAGE_CHILDREN, &usage);
2514 p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2515 usage.ru_utime.tv_usec, 0, null, " ");
2516 p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2517 usage.ru_stime.tv_usec, 0, null, "\n");
2523 * time pipeline (really a statement, not a built-in command)
2526 timex(struct op *t, int f, volatile int *xerrok)
2528 #define TF_NOARGS BIT(0)
2529 #define TF_NOREAL BIT(1) /* don't report real time */
2530 #define TF_POSIX BIT(2) /* report in POSIX format */
2532 struct rusage ru0, ru1, cru0, cru1;
2533 struct timeval usrtime, systime, tv0, tv1;
2536 getrusage(RUSAGE_SELF, &ru0);
2537 getrusage(RUSAGE_CHILDREN, &cru0);
2540 * Two ways of getting cpu usage of a command: just use t0
2541 * and t1 (which will get cpu usage from other jobs that
2542 * finish while we are executing t->left), or get the
2543 * cpu usage of t->left. AT&T ksh does the former, while
2544 * pdksh tries to do the later (the j_usrtime hack doesn't
2545 * really work as it only counts the last job).
2547 timerclear(&j_usrtime);
2548 timerclear(&j_systime);
2549 rv = execute(t->left, f | XTIME, xerrok);
2550 if (t->left->type == TCOM)
2551 tf |= t->left->str[0];
2553 getrusage(RUSAGE_SELF, &ru1);
2554 getrusage(RUSAGE_CHILDREN, &cru1);
2558 if (tf & TF_NOARGS) {
2559 /* ksh93 - report shell times (shell+kids) */
2561 timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime);
2562 timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime);
2564 timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime);
2565 timeradd(&usrtime, &j_usrtime, &usrtime);
2566 timersub(&ru1.ru_stime, &ru0.ru_stime, &systime);
2567 timeradd(&systime, &j_systime, &systime);
2570 if (!(tf & TF_NOREAL)) {
2571 timersub(&tv1, &tv0, &tv1);
2573 p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec,
2576 p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec,
2580 p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec,
2583 p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec,
2586 p_time(shl_out, true, systime.tv_sec, systime.tv_usec,
2589 p_time(shl_out, false, systime.tv_sec, systime.tv_usec,
2590 5, null, " system\n");
2597 timex_hook(struct op *t, char **volatile *app)
2603 ksh_getopt_reset(&opt, 0);
2604 /* start at the start */
2606 while ((optc = ksh_getopt((const char **)wp, &opt, ":p")) != -1)
2609 t->str[0] |= TF_POSIX;
2612 errorf("time: -%s %s", opt.optarg,
2615 errorf("time: -%s %s", opt.optarg,
2616 "requires an argument");
2618 /* Copy command words down over options. */
2619 if (opt.optind != 0) {
2620 for (i = 0; i < opt.optind; i++)
2621 afree(wp[i], ATEMP);
2622 for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
2626 t->str[0] |= TF_NOARGS;
2630 /* exec with no args - args case is taken care of in comexec() */
2632 c_exec(const char **wp MKSH_A_UNUSED)
2636 /* make sure redirects stay in place */
2637 if (e->savefd != NULL) {
2638 for (i = 0; i < NUFILE; i++) {
2639 if (e->savefd[i] > 0)
2640 close(e->savefd[i]);
2641 #ifndef MKSH_LEGACY_MODE
2643 * keep all file descriptors > 2 private for ksh,
2644 * but not for POSIX or legacy/kludge sh
2646 if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
2648 fcntl(i, F_SETFD, FD_CLOEXEC);
2658 c_mknod(const char **wp)
2660 int argc, optc, rv = 0;
2661 bool ismkfifo = false;
2664 mode_t mode = 0, oldmode = 0;
2666 while ((optc = ksh_getopt(wp, &builtin_opt, "m:")) != -1) {
2669 set = setmode(builtin_opt.optarg);
2671 bi_errorf("invalid file mode");
2674 mode = getmode(set, (mode_t)(DEFFILEMODE));
2675 free_ossetmode(set);
2681 argv = &wp[builtin_opt.optind];
2682 if (argv[0] == NULL)
2684 for (argc = 0; argv[argc]; argc++)
2686 if (argc == 2 && argv[1][0] == 'p')
2688 else if (argc != 4 || (argv[1][0] != 'b' && argv[1][0] != 'c'))
2692 oldmode = umask((mode_t)0);
2696 mode |= (argv[1][0] == 'b') ? S_IFBLK :
2697 (argv[1][0] == 'c') ? S_IFCHR : 0;
2700 unsigned long majnum, minnum;
2704 majnum = strtoul(argv[2], &c, 0);
2705 if ((c == argv[2]) || (*c != '\0')) {
2706 bi_errorf("non-numeric %s %s '%s'", "device", "major", argv[2]);
2709 minnum = strtoul(argv[3], &c, 0);
2710 if ((c == argv[3]) || (*c != '\0')) {
2711 bi_errorf("non-numeric %s %s '%s'", "device", "minor", argv[3]);
2714 dv = makedev(majnum, minnum);
2715 if ((unsigned long)(major(dv)) != majnum) {
2716 bi_errorf("%s %s too large: %lu", "device", "major", majnum);
2719 if ((unsigned long)(minor(dv)) != minnum) {
2720 bi_errorf("%s %s too large: %lu", "device", "minor", minnum);
2723 if (mknod(argv[0], mode, dv))
2724 goto c_mknod_failed;
2725 } else if (mkfifo(argv[0], mode)) {
2727 bi_errorf("%s: %s", argv[0], cstrerror(errno));
2736 bi_errorf("%s: %s", "usage", "mknod [-m mode] name b|c major minor");
2737 bi_errorf("%s: %s", "usage", "mknod [-m mode] name p");
2743 test(1) roughly accepts the following grammar:
2744 oexpr ::= aexpr | aexpr "-o" oexpr ;
2745 aexpr ::= nexpr | nexpr "-a" aexpr ;
2746 nexpr ::= primary | "!" nexpr ;
2747 primary ::= unary-operator operand
2748 | operand binary-operator operand
2753 unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
2754 "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
2755 "-L"|"-h"|"-S"|"-H";
2757 binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
2759 "<"|">" # rules used for [[ ... ]] expressions
2761 operand ::= <anything>
2764 /* POSIX says > 1 for errors */
2765 #define T_ERR_EXIT 2
2768 c_test(const char **wp)
2770 int argc, rv, invert = 0;
2773 const char *lhs, **swp;
2777 te.getopnd = ptest_getopnd;
2778 te.eval = test_eval;
2779 te.error = ptest_error;
2781 for (argc = 0; wp[argc]; argc++)
2784 mkssert(wp[0] != NULL);
2786 if (strcmp(wp[0], "[") == 0) {
2787 if (strcmp(wp[--argc], "]") != 0) {
2788 bi_errorf("missing ]");
2789 return (T_ERR_EXIT);
2794 te.wp_end = wp + argc;
2797 * Attempt to conform to POSIX special cases. This is pretty
2798 * dumb code straight-forward from the 2008 spec, but unless
2799 * the old pdksh code doesn't live from so many assumptions.
2800 * It does, though, inline some calls to '(*te.funcname)()'.
2811 if (ptest_isa(&te, TM_NOT)) {
2815 if ((op = ptest_isa(&te, TM_UNOP))) {
2817 rv = test_eval(&te, op, *te.pos.wp++, NULL, true);
2819 return ((invert & 1) ? rv : !rv);
2821 /* let the parser deal with anything else */
2826 /* use inside knowledge of ptest_getopnd inlined below */
2828 if ((op = ptest_isa(&te, TM_BINOP))) {
2829 /* test lhs op rhs */
2830 rv = test_eval(&te, op, lhs, *te.pos.wp++, true);
2833 /* back up to lhs */
2835 if (ptest_isa(&te, TM_NOT)) {
2839 if (ptest_isa(&te, TM_OPAREN)) {
2841 /* skip operand, without evaluation */
2843 /* check for closing parenthesis */
2844 op = ptest_isa(&te, TM_CPAREN);
2845 /* back up to operand */
2847 /* if there was a closing paren, handle it */
2850 /* backing up is done before calling the parser */
2852 /* let the parser deal with it */
2855 if (ptest_isa(&te, TM_NOT)) {
2859 if (ptest_isa(&te, TM_OPAREN)) {
2861 /* skip two operands, without evaluation */
2864 /* check for closing parenthesis */
2865 op = ptest_isa(&te, TM_CPAREN);
2866 /* back up to first operand */
2868 /* if there was a closing paren, handle it */
2871 /* backing up is done before calling the parser */
2873 /* defer this to the parser */
2877 /* "The results are unspecified." */
2879 return (test_parse(&te));
2883 * Generic test routines.
2887 test_isop(Test_meta meta, const char *s)
2890 const struct t_op *tbl;
2892 tbl = meta == TM_UNOP ? u_ops : b_ops;
2895 for (; tbl->op_text[0]; tbl++)
2896 if (sc1 == tbl->op_text[1] && !strcmp(s, tbl->op_text))
2897 return (tbl->op_num);
2903 test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
2916 /* Binary operators */
2930 /* consistency check, but does not happen in practice */
2932 te->flags |= TEF_ERROR;
2937 /* for completeness of switch */
2950 return (*opnd1 != '\0');
2954 return (*opnd1 == '\0');
2958 if ((i = *opnd1) == '!' || i == '?')
2960 if ((k = option(opnd1)) == (size_t)-1)
2962 return (i == '?' ? 1 : i == '!' ? !Flag(k) : Flag(k));
2966 /* LINTED use of access */
2967 return (access(opnd1, R_OK) == 0);
2971 /* LINTED use of access */
2972 return (access(opnd1, W_OK) == 0);
2976 return (ksh_access(opnd1, X_OK) == 0);
2982 return (stat(opnd1, &b1) == 0);
2986 return (stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
2990 return (stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode));
2994 return (stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode));
2998 return (stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode));
3002 return (stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode));
3006 #ifdef MKSH__NO_SYMLINK
3009 return (lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode));
3014 return (stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode));
3016 /* -H => HP context dependent files (directories) */
3023 * Append a + to filename and check to see if result is
3024 * a setuid directory. CDF stuff in general is hookey,
3025 * since it breaks for, e.g., the following sequence:
3026 * echo hi >foo+; mkdir foo; echo bye >foo/default;
3027 * chmod u+s foo (foo+ refers to the file with hi in it,
3028 * there is no way to get at the file with bye in it;
3029 * please correct me if I'm wrong about this).
3032 nv = shf_smprintf("%s+", opnd1);
3033 i = (stat(nv, &b1) == 0 && S_ISCDF(b1.st_mode));
3043 return (stat(opnd1, &b1) == 0 &&
3044 (b1.st_mode & S_ISUID) == S_ISUID);
3048 return (stat(opnd1, &b1) == 0 &&
3049 (b1.st_mode & S_ISGID) == S_ISGID);
3054 return (stat(opnd1, &b1) == 0 &&
3055 (b1.st_mode & S_ISVTX) == S_ISVTX);
3062 return (stat(opnd1, &b1) == 0 && (off_t)b1.st_size > (off_t)0);
3066 if (opnd1 && !bi_getn(opnd1, &i)) {
3067 te->flags |= TEF_ERROR;
3070 i = isatty(opnd1 ? i : 0);
3075 return (stat(opnd1, &b1) == 0 && (uid_t)b1.st_uid == ksheuid);
3079 return (stat(opnd1, &b1) == 0 && (gid_t)b1.st_gid == getegid());
3087 if (te->flags & TEF_DBRACKET)
3088 return (gmatchx(opnd1, opnd2, false));
3089 return (strcmp(opnd1, opnd2) == 0);
3093 if (te->flags & TEF_DBRACKET)
3094 return (!gmatchx(opnd1, opnd2, false));
3095 return (strcmp(opnd1, opnd2) != 0);
3099 return (strcmp(opnd1, opnd2) < 0);
3103 return (strcmp(opnd1, opnd2) > 0);
3117 if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) ||
3118 !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) {
3119 /* error already printed.. */
3120 te->flags |= TEF_ERROR;
3145 * ksh88/ksh93 succeed if file2 can't be stated
3146 * (subtly different from 'does not exist').
3148 return (stat(opnd1, &b1) == 0 &&
3149 (((s = stat(opnd2, &b2)) == 0 &&
3150 b1.st_mtime > b2.st_mtime) || s < 0));
3155 * ksh88/ksh93 succeed if file1 can't be stated
3156 * (subtly different from 'does not exist').
3158 return (stat(opnd2, &b2) == 0 &&
3159 (((s = stat(opnd1, &b1)) == 0 &&
3160 b1.st_mtime < b2.st_mtime) || s < 0));
3164 return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
3165 b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
3167 /* all other cases */
3170 /* throw the error */
3173 (*te->error)(te, 0, "internal error: unknown op");
3178 test_parse(Test_env *te)
3182 rv = test_oexpr(te, 1);
3184 if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
3185 (*te->error)(te, 0, "unexpected operator/operand");
3187 return ((te->flags & TEF_ERROR) ? T_ERR_EXIT : !rv);
3191 test_oexpr(Test_env *te, bool do_eval)
3195 if ((rv = test_aexpr(te, do_eval)))
3197 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
3198 return (test_oexpr(te, do_eval) || rv);
3203 test_aexpr(Test_env *te, bool do_eval)
3207 if (!(rv = test_nexpr(te, do_eval)))
3209 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
3210 return (test_aexpr(te, do_eval) && rv);
3215 test_nexpr(Test_env *te, bool do_eval)
3217 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
3218 return (!test_nexpr(te, do_eval));
3219 return (test_primary(te, do_eval));
3223 test_primary(Test_env *te, bool do_eval)
3225 const char *opnd1, *opnd2;
3229 if (te->flags & TEF_ERROR)
3231 if ((*te->isa)(te, TM_OPAREN)) {
3232 rv = test_oexpr(te, do_eval);
3233 if (te->flags & TEF_ERROR)
3235 if (!(*te->isa)(te, TM_CPAREN)) {
3236 (*te->error)(te, 0, "missing )");
3242 * Binary should have precedence over unary in this case
3243 * so that something like test \( -f = -f \) is accepted
3245 if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end &&
3246 !test_isop(TM_BINOP, te->pos.wp[1]))) {
3247 if ((op = (*te->isa)(te, TM_UNOP))) {
3248 /* unary expression */
3249 opnd1 = (*te->getopnd)(te, op, do_eval);
3251 (*te->error)(te, -1, "missing argument");
3255 return ((*te->eval)(te, op, opnd1, NULL, do_eval));
3258 opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
3260 (*te->error)(te, 0, "expression expected");
3263 if ((op = (*te->isa)(te, TM_BINOP))) {
3264 /* binary expression */
3265 opnd2 = (*te->getopnd)(te, op, do_eval);
3267 (*te->error)(te, -1, "missing second argument");
3271 return ((*te->eval)(te, op, opnd1, opnd2, do_eval));
3273 return ((*te->eval)(te, TO_STNZE, opnd1, NULL, do_eval));
3277 * Plain test (test and [ .. ]) specific routines.
3281 * Test if the current token is a whatever. Accepts the current token if
3282 * it is. Returns 0 if it is not, non-zero if it is (in the case of
3283 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
3286 ptest_isa(Test_env *te, Test_meta meta)
3288 /* Order important - indexed by Test_meta values */
3289 static const char * const tokens[] = {
3290 "-o", "-a", "!", "(", ")"
3294 if (te->pos.wp >= te->wp_end)
3295 return (meta == TM_END ? TO_NONNULL : TO_NONOP);
3297 if (meta == TM_UNOP || meta == TM_BINOP)
3298 rv = test_isop(meta, *te->pos.wp);
3299 else if (meta == TM_END)
3302 rv = !strcmp(*te->pos.wp, tokens[(int)meta]) ?
3303 TO_NONNULL : TO_NONOP;
3305 /* Accept the token? */
3313 ptest_getopnd(Test_env *te, Test_op op, bool do_eval MKSH_A_UNUSED)
3315 if (te->pos.wp >= te->wp_end)
3316 return (op == TO_FILTT ? "1" : NULL);
3317 return (*te->pos.wp++);
3321 ptest_error(Test_env *te, int ofs, const char *msg)
3325 te->flags |= TEF_ERROR;
3326 if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs]))
3327 bi_errorf("%s: %s", op, msg);
3329 bi_errorf("%s", msg);
3332 #ifndef MKSH_NO_LIMITS
3338 int resource; /* resource to get/set */
3339 unsigned int factor; /* multiply by to get rlim_{cur,max} values */
3343 static void print_ulimit(const struct limits *, int);
3344 static int set_ulimit(const struct limits *, const char *, int);
3346 /* Magic to divine the 'm' and 'v' limits */
3349 #if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
3350 !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
3351 #define ULIMIT_V_IS_AS
3352 #elif defined(RLIMIT_VMEM)
3353 #if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
3354 #define ULIMIT_V_IS_AS
3356 #define ULIMIT_V_IS_VMEM
3362 #ifdef ULIMIT_V_IS_VMEM
3363 #define ULIMIT_M_IS_RSS
3364 #elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
3365 #define ULIMIT_M_IS_VMEM
3367 #define ULIMIT_M_IS_RSS
3369 #if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)
3370 #undef ULIMIT_M_IS_RSS
3374 #if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
3375 #define ULIMIT_V_IS_VMEM
3378 #if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
3379 (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
3380 #define ULIMIT_M_IS_VMEM
3383 #if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
3384 (RLIMIT_VMEM == RLIMIT_AS)
3385 #undef ULIMIT_M_IS_VMEM
3390 c_ulimit(const char **wp)
3392 static const struct limits limits[] = {
3393 /* do not use options -H, -S or -a or change the order */
3395 { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
3398 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
3401 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
3404 { "data(KiB)", RLIMIT_DATA, 1024, 'd' },
3407 { "stack(KiB)", RLIMIT_STACK, 1024, 's' },
3409 #ifdef RLIMIT_MEMLOCK
3410 { "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
3412 #ifdef RLIMIT_NOFILE
3413 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
3416 { "processes", RLIMIT_NPROC, 1, 'p' },
3419 { "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
3422 { "flocks", RLIMIT_LOCKS, -1, 'L' },
3425 { "humantime(seconds)", RLIMIT_TIME, 1, 'T' },
3427 #ifdef RLIMIT_NOVMON
3428 { "vnodemonitors", RLIMIT_NOVMON, 1, 'V' },
3430 #ifdef RLIMIT_SIGPENDING
3431 { "sigpending", RLIMIT_SIGPENDING, 1, 'i' },
3433 #ifdef RLIMIT_MSGQUEUE
3434 { "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' },
3436 #ifdef RLIMIT_AIO_MEM
3437 { "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' },
3439 #ifdef RLIMIT_AIO_OPS
3440 { "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' },
3442 #ifdef RLIMIT_TCACHE
3443 { "cachedthreads", RLIMIT_TCACHE, 1, 'C' },
3445 #ifdef RLIMIT_SBSIZE
3446 { "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' },
3448 #ifdef RLIMIT_PTHREAD
3449 { "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' },
3452 { "maxnice", RLIMIT_NICE, 1, 'e' },
3454 #ifdef RLIMIT_RTPRIO
3455 { "maxrtprio", RLIMIT_RTPRIO, 1, 'r' },
3457 #if defined(ULIMIT_M_IS_RSS)
3458 { "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' },
3459 #elif defined(ULIMIT_M_IS_VMEM)
3460 { "memory(KiB)", RLIMIT_VMEM, 1024, 'm' },
3462 #if defined(ULIMIT_V_IS_VMEM)
3463 { "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' },
3464 #elif defined(ULIMIT_V_IS_AS)
3465 { "address-space(KiB)", RLIMIT_AS, 1024, 'v' },
3469 static const char opts[] = "a"
3470 #ifdef RLIMIT_SBSIZE
3473 #ifdef RLIMIT_TCACHE
3489 #ifdef RLIMIT_SIGPENDING
3495 #ifdef RLIMIT_MEMLOCK
3498 #ifdef RLIMIT_AIO_MEM
3501 #if defined(ULIMIT_M_IS_RSS) || defined(ULIMIT_M_IS_VMEM)
3504 #ifdef RLIMIT_NOFILE
3507 #ifdef RLIMIT_AIO_OPS
3510 #ifdef RLIMIT_PTHREAD
3516 #ifdef RLIMIT_MSGQUEUE
3519 #ifdef RLIMIT_RTPRIO
3532 #ifdef RLIMIT_NOVMON
3535 #if defined(ULIMIT_V_IS_VMEM) || defined(ULIMIT_V_IS_AS)
3542 int how = SOFT | HARD, optc, what = 'f';
3544 const struct limits *l;
3546 while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
3558 bi_errorf("usage: ulimit [-%s] [value]", opts);
3564 for (l = limits; l->name && l->option != what; l++)
3567 internal_warningf("ulimit: %c", what);
3571 if (wp[builtin_opt.optind]) {
3572 if (all || wp[builtin_opt.optind + 1]) {
3573 bi_errorf("too many arguments");
3576 return (set_ulimit(l, wp[builtin_opt.optind], how));
3579 print_ulimit(l, how);
3580 else for (l = limits; l->name; l++) {
3581 shprintf("%-20s ", l->name);
3582 print_ulimit(l, how);
3588 set_ulimit(const struct limits *l, const char *v, int how)
3590 rlim_t val = (rlim_t)0;
3591 struct rlimit limit;
3593 if (strcmp(v, "unlimited") == 0)
3594 val = (rlim_t)RLIM_INFINITY;
3598 if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
3601 * Avoid problems caused by typos that evaluate misses due
3602 * to evaluating unset parameters to 0...
3603 * If this causes problems, will have to add parameter to
3604 * evaluate() to control if unset params are 0 or an error.
3606 if (!rval && !ksh_isdigit(v[0])) {
3607 bi_errorf("invalid %s limit: %s", l->name, v);
3610 val = (rlim_t)((rlim_t)rval * l->factor);
3613 if (getrlimit(l->resource, &limit) < 0) {
3614 /* some can't be read, e.g. Linux RLIMIT_LOCKS */
3615 limit.rlim_cur = RLIM_INFINITY;
3616 limit.rlim_max = RLIM_INFINITY;
3619 limit.rlim_cur = val;
3621 limit.rlim_max = val;
3622 if (!setrlimit(l->resource, &limit))
3625 bi_errorf("%s exceeds allowable %s limit", v, l->name);
3627 bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
3632 print_ulimit(const struct limits *l, int how)
3634 rlim_t val = (rlim_t)0;
3635 struct rlimit limit;
3637 if (getrlimit(l->resource, &limit)) {
3638 shf_puts("unknown\n", shl_stdout);
3642 val = limit.rlim_cur;
3643 else if (how & HARD)
3644 val = limit.rlim_max;
3645 if (val == (rlim_t)RLIM_INFINITY)
3646 shf_puts("unlimited\n", shl_stdout);
3648 shprintf("%lu\n", (unsigned long)(val / l->factor));
3653 c_rename(const char **wp)
3659 if (wp[0] && !strcmp(wp[0], "--"))
3660 /* skip "--" (options separator) */
3663 /* check for exactly two arguments */
3664 if (wp[0] == NULL /* first argument */ ||
3665 wp[1] == NULL /* second argument */ ||
3666 wp[2] != NULL /* no further args please */)
3668 else if ((rv = rename(wp[0], wp[1])) != 0) {
3670 bi_errorf("%s: %s", "failed", cstrerror(rv));
3677 c_realpath(const char **wp)
3684 if (wp[0] && !strcmp(wp[0], "--"))
3685 /* skip "--" (options separator) */
3688 /* check for exactly one argument */
3689 if (wp[0] == NULL || wp[1] != NULL)
3691 else if ((buf = do_realpath(wp[0])) == NULL) {
3693 bi_errorf("%s: %s", wp[0], cstrerror(rv));
3694 if ((unsigned int)rv > 255)
3697 shprintf("%s\n", buf);
3706 c_cat(const char **wp)
3708 int fd = STDIN_FILENO, rv, eno;
3710 const char *fn = "<stdin>";
3712 #define MKSH_CAT_BUFSIZ 4096
3714 /* parse options: POSIX demands we support "-u" as no-op */
3715 while ((rv = ksh_getopt(wp, &builtin_opt, "u")) != -1) {
3718 /* we already operate unbuffered */
3725 wp += builtin_opt.optind;
3728 if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
3729 bi_errorf(Toomem, (unsigned long)MKSH_CAT_BUFSIZ);
3736 if (fn[0] == '-' && fn[1] == '\0')
3738 else if ((fd = open(fn, O_RDONLY)) < 0) {
3740 bi_errorf("%s: %s", fn, cstrerror(eno));
3745 while (/* CONSTCOND */ 1) {
3746 n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ);
3748 /* give the user a chance to ^C out */
3752 /* interrupted, try again */
3755 /* an error occured during reading */
3756 bi_errorf("%s: %s", fn, cstrerror(eno));
3760 /* end of file reached */
3763 w = write(STDOUT_FILENO, cp, n);
3766 /* interrupted, try again */
3768 /* an error occured during writing */
3770 bi_errorf("%s: %s", "<stdout>",
3773 if (fd != STDIN_FILENO)
3781 if (fd != STDIN_FILENO)
3792 c_sleep(const char **wp)
3799 if (wp[0] && !strcmp(wp[0], "--"))
3800 /* skip "--" (options separator) */
3803 if (!wp[0] || wp[1])
3805 else if (parse_usec(wp[0], &tv))
3806 bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno), wp[0]);
3808 #ifndef MKSH_NOPROSPECTOFWORK
3809 sigset_t omask, bmask;
3811 /* block a number of signals from interrupting us, though */
3812 (void)sigemptyset(&bmask);
3813 (void)sigaddset(&bmask, SIGPIPE);
3814 (void)sigaddset(&bmask, SIGCHLD);
3816 (void)sigaddset(&bmask, SIGWINCH);
3819 (void)sigaddset(&bmask, SIGINFO);
3822 (void)sigaddset(&bmask, SIGUSR1);
3825 (void)sigaddset(&bmask, SIGUSR2);
3827 sigprocmask(SIG_BLOCK, &bmask, &omask);
3829 if (select(1, NULL, NULL, NULL, &tv) == 0 || errno == EINTR)
3831 * strictly speaking only for SIGALRM, but the
3832 * execution may be interrupted by other signals
3836 bi_errorf("%s: %s", Tselect, cstrerror(errno));
3837 #ifndef MKSH_NOPROSPECTOFWORK
3838 /* this will re-schedule signal delivery */
3839 sigprocmask(SIG_SETMASK, &omask, NULL);