diff options
Diffstat (limited to 'src/funcs.c')
| -rw-r--r-- | src/funcs.c | 315 |
1 files changed, 185 insertions, 130 deletions
diff --git a/src/funcs.c b/src/funcs.c index 0d2aec3..ab6e3b7 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -1,12 +1,12 @@ -/* $OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $ */ -/* $OpenBSD: c_sh.c,v 1.45 2014/08/27 08:26:04 jmc Exp $ */ +/* $OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $ */ +/* $OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $ */ /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ /* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */ /*- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - * 2010, 2011, 2012, 2013, 2014, 2015 - * Thorsten Glaser <tg@mirbsd.org> + * 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * mirabilos <m@mirbsd.org> * * Provided that these terms and disclaimer and all copyright notices * are retained or reproduced in an accompanying document, permission @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.280 2015/07/09 20:52:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.293 2016/01/20 21:34:11 tg Exp $"); #if HAVE_KILLPG /* @@ -103,7 +103,7 @@ const struct builtin mkshbuiltins[] = { {"cd", c_cd}, /* dash compatibility hack */ {"chdir", c_cd}, - {"command", c_command}, + {Tcommand, c_command}, {"*=continue", c_brkcont}, {"echo", c_print}, {"*=eval", c_eval}, @@ -127,6 +127,7 @@ const struct builtin mkshbuiltins[] = { {"*=return", c_exitreturn}, {Tsgset, c_set}, {"*=shift", c_shift}, + {"=source", c_dot}, #if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID {"suspend", c_suspend}, #endif @@ -277,20 +278,18 @@ static void s_put(int); int c_print(const char **wp) { -#define PO_NL BIT(0) /* print newline */ -#define PO_EXPAND BIT(1) /* expand backslash sequences */ -#define PO_PMINUSMINUS BIT(2) /* print a -- argument */ -#define PO_HIST BIT(3) /* print to history instead of stdout */ -#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ int fd = 1, c; - int flags = PO_EXPAND | PO_NL; - const char *s, *emsg; + const char *s; XString xs; char *xp; + /* print newline; expand backslash sequences */ + bool po_nl = true, po_exp = true; + /* print to history instead of file descriptor / stdout */ + bool po_hist = false; if (wp[0][0] == 'e') { - /* echo builtin */ - wp++; + /* "echo" builtin */ + ++wp; #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT if (Flag(FSH)) { /* @@ -298,7 +297,7 @@ c_print(const char **wp) * one that supports -e but does not enable it by * default */ - flags = PO_NL; + po_exp = false; } #endif if (Flag(FPOSIX) || @@ -308,14 +307,14 @@ c_print(const char **wp) Flag(FAS_BUILTIN)) { /* Debian Policy 10.4 compliant "echo" builtin */ if (*wp && !strcmp(*wp, "-n")) { - /* we recognise "-n" only as the first arg */ - flags = 0; - wp++; - } else - /* otherwise, we print everything as-is */ - flags = PO_NL; + /* recognise "-n" only as the first arg */ + po_nl = false; + ++wp; + } + /* print everything as-is */ + po_exp = false; } else { - int nflags = flags; + bool new_exp = po_exp, new_nl = po_nl; /** * a compromise between sysV and BSD echo commands: @@ -328,62 +327,65 @@ c_print(const char **wp) * quences are enabled by default. */ - while ((s = *wp) && *s == '-' && s[1]) { - while (*++s) - if (*s == 'n') - nflags &= ~PO_NL; - else if (*s == 'e') - nflags |= PO_EXPAND; - else if (*s == 'E') - nflags &= ~PO_EXPAND; - else - /* - * bad option: don't use - * nflags, print argument - */ - break; - - if (*s) - break; - wp++; - flags = nflags; + print_tradparse_arg: + if ((s = *wp) && *s++ == '-' && *s) { + print_tradparse_ch: + switch ((c = *s++)) { + case 'E': + new_exp = false; + goto print_tradparse_ch; + case 'e': + new_exp = true; + goto print_tradparse_ch; + case 'n': + new_nl = false; + goto print_tradparse_ch; + case '\0': + po_exp = new_exp; + po_nl = new_nl; + ++wp; + goto print_tradparse_arg; + } } } } else { - int optc; - const char *opts = "Rnprsu,"; - - while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) - switch (optc) { - case 'R': - /* fake BSD echo command */ - flags |= PO_PMINUSMINUS; - flags &= ~PO_EXPAND; - opts = "ne"; - break; + /* "print" builtin */ + const char *opts = "npRrsu,"; + const char *emsg; + /* print a "--" argument */ + bool po_pminusminus = false; + + while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1) + switch (c) { case 'e': - flags |= PO_EXPAND; + po_exp = true; break; case 'n': - flags &= ~PO_NL; + po_nl = false; break; case 'p': if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { - bi_errorf("%s: %s", "-p", emsg); + bi_errorf("-p: %s", emsg); return (1); } break; + case 'R': + /* fake BSD echo command */ + po_pminusminus = true; + po_exp = false; + opts = "en"; + break; case 'r': - flags &= ~PO_EXPAND; + po_exp = false; break; case 's': - flags |= PO_HIST; + po_hist = true; break; case 'u': if (!*(s = builtin_opt.optarg)) fd = 0; else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { - bi_errorf("%s: %s: %s", "-u", s, emsg); + bi_errorf("-u%s: %s", s, emsg); return (1); } break; @@ -392,22 +394,23 @@ c_print(const char **wp) } if (!(builtin_opt.info & GI_MINUSMINUS)) { - /* treat a lone - like -- */ + /* treat a lone "-" like "--" */ if (wp[builtin_opt.optind] && ksh_isdash(wp[builtin_opt.optind])) builtin_opt.optind++; - } else if (flags & PO_PMINUSMINUS) - builtin_opt.optind--; + } else if (po_pminusminus) + builtin_opt.optind--; wp += builtin_opt.optind; } Xinit(xs, xp, 128, ATEMP); - while (*wp != NULL) { + if (*wp != NULL) { + print_read_arg: s = *wp; while ((c = *s++) != '\0') { Xcheck(xs, xp); - if ((flags & PO_EXPAND) && c == '\\') { + if (po_exp && c == '\\') { s_ptr = s; c = unbksl(false, s_get, s_put); s = s_ptr; @@ -415,11 +418,11 @@ c_print(const char **wp) /* rejected by generic function */ switch ((c = *s++)) { case 'c': - flags &= ~PO_NL; + po_nl = false; /* AT&T brain damage */ continue; case '\0': - s--; + --s; c = '\\'; break; default: @@ -430,25 +433,31 @@ c_print(const char **wp) char ts[4]; ts[utf_wctomb(ts, c - 0x100)] = 0; - for (c = 0; ts[c]; ++c) + c = 0; + do { Xput(xs, xp, ts[c]); + } while (ts[++c]); continue; } } Xput(xs, xp, c); } - if (*++wp != NULL) + if (*++wp != NULL) { Xput(xs, xp, ' '); + goto print_read_arg; + } } - if (flags & PO_NL) + if (po_nl) Xput(xs, xp, '\n'); - if (flags & PO_HIST) { + c = 0; + if (po_hist) { Xput(xs, xp, '\0'); histsave(&source->line, Xstring(xs, xp), HIST_STORE, false); Xfree(xs, xp); } else { - int len = Xlength(xs, xp); + size_t len = Xlength(xs, xp); + bool po_coproc = false; int opipe = 0; /* @@ -458,30 +467,36 @@ c_print(const char **wp) * not enough). */ if (coproc.write >= 0 && coproc.write == fd) { - flags |= PO_COPROC; + po_coproc = true; opipe = block_pipe(); } - for (s = Xstring(xs, xp); len > 0; ) { - if ((c = write(fd, s, len)) < 0) { - if (flags & PO_COPROC) - restore_pipe(opipe); + + s = Xstring(xs, xp); + while (len > 0) { + ssize_t nwritten; + + if ((nwritten = write(fd, s, len)) < 0) { if (errno == EINTR) { - /* allow user to ^C out */ + if (po_coproc) + restore_pipe(opipe); + /* give the user a chance to ^C out */ intrcheck(); - if (flags & PO_COPROC) + /* interrupted, try again */ + if (po_coproc) opipe = block_pipe(); continue; } - return (1); + c = 1; + break; } - s += c; - len -= c; + s += nwritten; + len -= nwritten; } - if (flags & PO_COPROC) + if (po_coproc) restore_pipe(opipe); } - return (0); + return (c); } static int @@ -1305,7 +1320,8 @@ c_fgbg(const char **wp) rv = j_resume(*wp, bg); else rv = j_resume("%%", bg); - return (bg ? 0 : rv); + /* fg returns $? of the job unless POSIX */ + return ((bg | Flag(FPOSIX)) ? 0 : rv); } #endif @@ -1374,7 +1390,7 @@ c_kill(const char **wp) for (; wp[i]; i++) { if (!bi_getn(wp[i], &n)) return (1); -#if (ksh_NSIG < 128) +#if (ksh_NSIG <= 128) if (n > 128 && n < 128 + ksh_NSIG) n -= 128; #endif @@ -1383,9 +1399,16 @@ c_kill(const char **wp) else shprintf("%d\n", n); } + } else if (Flag(FPOSIX)) { + n = 1; + while (n < ksh_NSIG) { + shf_puts(sigtraps[n].name, shl_stdout); + shf_putc(++n == ksh_NSIG ? '\n' : ' ', + shl_stdout); + } } else { ssize_t w, mess_cols = 0, mess_octs = 0; - int j = ksh_NSIG; + int j = ksh_NSIG - 1; struct kill_info ki = { 0, 0 }; do { @@ -1436,7 +1459,8 @@ void getopts_reset(int val) { if (val >= 1) { - ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT); + ksh_getopt_reset(&user_opt, GF_NONAME | + (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); user_opt.optind = user_opt.uoptind = val; } } @@ -1777,7 +1801,11 @@ c_dot(const char **wp) bi_errorf("missing argument"); return (1); } - if ((file = search_path(cp, path, R_OK, &errcode)) == NULL) { + file = search_path(cp, path, R_OK, &errcode); + if (!file && errcode == ENOENT && wp[0][0] == 's' && + search_access(cp, R_OK) == 0) + file = cp; + if (!file) { bi_errorf("%s: %s", cp, cstrerror(errcode)); return (1); } @@ -1835,13 +1863,15 @@ c_read(const char **wp) enum { LINES, BYTES, UPTO, READALL } readmode = LINES; char delim = '\n'; size_t bytesleft = 128, bytesread; - struct tbl *vp /* FU gcc */ = NULL, *vq; + struct tbl *vp /* FU gcc */ = NULL, *vq = NULL; char *cp, *allocd = NULL, *xp; const char *ccp; XString xs; size_t xsave = 0; mksh_ttyst tios; bool restore_tios = false; + /* to catch read -aN2 foo[i] */ + bool subarray = false; #if HAVE_SELECT bool hastimeout = false; struct timeval tv, tvlim; @@ -2086,6 +2116,7 @@ c_read(const char **wp) XinitN(xs, 128, ATEMP); if (intoarray) { vp = global(*wp); + subarray = last_lookup_was_array; if (vp->flag & RDONLY) { c_read_splitro: bi_errorf("read-only: %s", *wp); @@ -2094,10 +2125,10 @@ c_read(const char **wp) afree(cp, ATEMP); goto c_read_out; } - /* exporting an array is currently pointless */ - unset(vp, 1); /* counter for array index */ - c = 0; + c = subarray ? arrayindex(vp) : 0; + /* exporting an array is currently pointless */ + unset(vp, subarray ? 0 : 1); } if (!aschars) { /* skip initial IFS whitespace */ @@ -2199,7 +2230,18 @@ c_read(const char **wp) c_read_gotword: Xput(xs, xp, '\0'); if (intoarray) { - vq = arraysearch(vp, c++); + if (subarray) { + /* array element passed, accept first read */ + if (vq) { + bi_errorf("nested arrays not yet supported"); + goto c_read_spliterr; + } + vq = vp; + if (c) + /* [0] doesn't */ + vq->flag |= AINDEX; + } else + vq = arraysearch(vp, c++); } else { vq = global(*wp); /* must be checked before exporting */ @@ -2293,7 +2335,7 @@ int c_trap(const char **wp) { Trap *p = sigtraps; - int i = ksh_NSIG + 1; + int i = ksh_NSIG; const char *s; if (ksh_getopt(wp, &builtin_opt, null) == '?') @@ -2308,7 +2350,7 @@ c_trap(const char **wp) shprintf(" %s\n", p->name); } ++p; - } while (--i); + } while (i--); return (0); } @@ -2339,16 +2381,14 @@ int c_exitreturn(const char **wp) { int n, how = LEXIT; - const char *arg; - if (ksh_getopt(wp, &builtin_opt, null) == '?') - goto c_exitreturn_err; - arg = wp[builtin_opt.optind]; - - if (arg) - exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1; - else if (trap_exstat != -1) + if (wp[1]) { + if (wp[2]) + goto c_exitreturn_err; + exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1; + } else if (trap_exstat != -1) exstat = trap_exstat; + if (wp[0][0] == 'r') { /* return */ struct env *ep; @@ -2369,12 +2409,13 @@ c_exitreturn(const char **wp) how = LSHELL; } - /* get rid of any i/o redirections */ + /* get rid of any I/O redirections */ quitenv(NULL); unwind(how); /* NOTREACHED */ c_exitreturn_err: + bi_errorf("too many arguments"); return (1); } @@ -2542,7 +2583,7 @@ p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width, shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width, tv_sec, tv_usec, suffix); else - shf_fprintf(shf, "%s%*ldm%d.%02ds%s", prefix, width, + shf_fprintf(shf, "%s%*ldm%02d.%02ds%s", prefix, width, tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix); } @@ -2840,7 +2881,7 @@ c_test(const char **wp) /* * Attempt to conform to POSIX special cases. This is pretty - * dumb code straight-forward from the 2008 spec, but unless + * dumb code straight-forward from the 2008 spec, but unlike * the old pdksh code doesn't live from so many assumptions. * It does, though, inline some calls to '(*te.funcname)()'. */ @@ -2861,6 +2902,8 @@ c_test(const char **wp) ptest_unary: rv = test_eval(&te, op, *te.pos.wp++, NULL, true); ptest_out: + if (te.flags & TEF_ERROR) + return (T_ERR_EXIT); return ((invert & 1) ? rv : !rv); } /* let the parser deal with anything else */ @@ -3638,10 +3681,11 @@ c_realpath(const char **wp) int c_cat(const char **wp) { - int fd = STDIN_FILENO, rv, eno; + int fd = STDIN_FILENO, rv; ssize_t n, w; const char *fn = "<stdin>"; char *buf, *cp; + int opipe = 0; #define MKSH_CAT_BUFSIZ 4096 /* parse options: POSIX demands we support "-u" as no-op */ @@ -3663,54 +3707,64 @@ c_cat(const char **wp) return (1); } + /* catch SIGPIPE */ + opipe = block_pipe(); + do { if (*wp) { fn = *wp++; if (ksh_isdash(fn)) fd = STDIN_FILENO; else if ((fd = binopen2(fn, O_RDONLY)) < 0) { - eno = errno; - bi_errorf("%s: %s", fn, cstrerror(eno)); + bi_errorf("%s: %s", fn, cstrerror(errno)); rv = 1; continue; } } while (/* CONSTCOND */ 1) { - n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ); - eno = errno; - /* give the user a chance to ^C out */ - intrcheck(); - if (n == -1) { - if (eno == EINTR) { + if ((n = blocking_read(fd, (cp = buf), + MKSH_CAT_BUFSIZ)) == -1) { + if (errno == EINTR) { + restore_pipe(opipe); + /* give the user a chance to ^C out */ + intrcheck(); /* interrupted, try again */ + opipe = block_pipe(); continue; } /* an error occured during reading */ - bi_errorf("%s: %s", fn, cstrerror(eno)); + bi_errorf("%s: %s", fn, cstrerror(errno)); rv = 1; break; } else if (n == 0) /* end of file reached */ break; while (n) { - w = write(STDOUT_FILENO, cp, n); - eno = errno; - /* give the user a chance to ^C out */ - intrcheck(); - if (w == -1) { - if (eno == EINTR) - /* interrupted, try again */ - continue; + if ((w = write(STDOUT_FILENO, cp, n)) != -1) { + n -= w; + cp += w; + continue; + } + if (errno == EINTR) { + restore_pipe(opipe); + /* give the user a chance to ^C out */ + intrcheck(); + /* interrupted, try again */ + opipe = block_pipe(); + continue; + } + if (errno == EPIPE) { + /* fake receiving signel */ + rv = ksh_sigmask(SIGPIPE); + } else { /* an error occured during writing */ bi_errorf("%s: %s", "<stdout>", - cstrerror(eno)); + cstrerror(errno)); rv = 1; - if (fd != STDIN_FILENO) - close(fd); - goto out; } - n -= w; - cp += w; + if (fd != STDIN_FILENO) + close(fd); + goto out; } } if (fd != STDIN_FILENO) @@ -3718,6 +3772,7 @@ c_cat(const char **wp) } while (*wp); out: + restore_pipe(opipe); free_osfunc(buf); return (rv); } |
