OSDN Git Service

Upgrade to mksh R52b.
[android-x86/external-mksh.git] / src / exec.c
index 6a743a2..9361c19 100644 (file)
@@ -1,9 +1,9 @@
-/*     $OpenBSD: exec.c,v 1.51 2015/04/18 18:28:36 deraadt Exp $       */
+/*     $OpenBSD: exec.c,v 1.52 2015/09/10 22:48:58 nicm Exp $  */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
  *              2011, 2012, 2013, 2014, 2015
- *     Thorsten Glaser <tg@mirbsd.org>
+ *     mirabilos <m@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  * are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.160 2015/07/10 19:36:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.170 2015/12/31 21:03:47 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@@ -39,7 +39,6 @@ static const char *do_selectargs(const char **, bool);
 static Test_op dbteste_isa(Test_env *, Test_meta);
 static const char *dbteste_getopnd(Test_env *, Test_op, bool);
 static void dbteste_error(Test_env *, int, const char *);
-static int search_access(const char *, int);
 /* XXX: horrible kludge to fit within the framework */
 static void plain_fmt_entry(char *, size_t, unsigned int, const void *);
 static void select_fmt_entry(char *, size_t, unsigned int, const void *);
@@ -1000,6 +999,7 @@ scriptexec(struct op *tp, const char **ap)
                    (m == /* ECOFF_SH */   0x0500 || m == 0x0005) ||
                    (m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
                    (m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
+                   (m == /* ksh93 */ 0x0B13) || (m == /* LZIP */ 0x4C5A) ||
                    (m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
                    buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
                    (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
@@ -1065,14 +1065,6 @@ define(const char *name, struct op *t)
 
        nhash = hash(name);
 
-#ifdef MKSH_LEGACY_MODE
-       if (t != NULL && !tobool(t->u.ksh_func)) {
-               /* drop same-name aliases for POSIX functions */
-               if ((tp = ktsearch(&aliases, name, nhash)))
-                       ktdelete(tp);
-       }
-#endif
-
        while (/* CONSTCOND */ 1) {
                tp = findfunc(name, nhash, true);
 
@@ -1257,7 +1249,7 @@ flushcom(bool all)
 }
 
 /* check if path is something we want to find */
-static int
+int
 search_access(const char *fn, int mode)
 {
        struct stat sb;
@@ -1266,9 +1258,13 @@ search_access(const char *fn, int mode)
                /* file does not exist */
                return (ENOENT);
        /* LINTED use of access */
-       if (access(fn, mode) < 0)
+       if (access(fn, mode) < 0) {
                /* file exists, but we can't access it */
-               return (errno);
+               int eno;
+
+               eno = errno;
+               return (eno ? eno : EACCES);
+       }
        if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
            !(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
                /* access(2) may say root can execute everything */
@@ -1344,7 +1340,9 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
        if (!tp)
                internal_errorf("%s: %s", where, wp[0]);
        builtin_argv0 = wp[0];
-       builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI));
+       builtin_spec = tobool(!resetspec &&
+           /*XXX odd use of KEEPASN */
+           ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
        shf_reopen(1, SHF_WR, shl_stdout);
        shl_stdout_ok = true;
        ksh_getopt_reset(&builtin_opt, GF_ERROR);
@@ -1363,9 +1361,9 @@ static int
 iosetup(struct ioword *iop, struct tbl *tp)
 {
        int u = -1;
-       char *cp = iop->name;
+       char *cp = iop->ioname;
        int iotype = iop->ioflag & IOTYPE;
-       bool do_open = true, do_close = false;
+       bool do_open = true, do_close = false, do_fstat = false;
        int flags = 0;
        struct ioword iotmp;
        struct stat statb;
@@ -1375,7 +1373,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
 
        /* Used for tracing and error messages to print expanded cp */
        iotmp = *iop;
-       iotmp.name = (iotype == IOHERE) ? NULL : cp;
+       iotmp.ioname = (iotype == IOHERE) ? NULL : cp;
        iotmp.ioflag |= IONAMEXP;
 
        if (Flag(FXTRACE)) {
@@ -1394,14 +1392,27 @@ iosetup(struct ioword *iop, struct tbl *tp)
                break;
 
        case IOWRITE:
-               flags = O_WRONLY | O_CREAT | O_TRUNC;
-               /*
-                * The stat() is here to allow redirections to
-                * things like /dev/null without error.
-                */
-               if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
-                   (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
-                       flags |= O_EXCL;
+               if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
+                       /* >file under set -C */
+                       if (stat(cp, &statb)) {
+                               /* nonexistent file */
+                               flags = O_WRONLY | O_CREAT | O_EXCL;
+                       } else if (S_ISREG(statb.st_mode)) {
+                               /* regular file, refuse clobbering */
+                               goto clobber_refused;
+                       } else {
+                               /*
+                                * allow redirections to things
+                                * like /dev/null without error
+                                */
+                               flags = O_WRONLY;
+                               /* but check again after opening */
+                               do_fstat = true;
+                       }
+               } else {
+                       /* >|file or set +C */
+                       flags = O_WRONLY | O_CREAT | O_TRUNC;
+               }
                break;
 
        case IORDWR:
@@ -1446,6 +1457,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
                        return (-1);
                }
                u = binopen3(cp, flags, 0666);
+               if (do_fstat && u >= 0) {
+                       /* prevent race conditions */
+                       if (fstat(u, &statb) || S_ISREG(statb.st_mode)) {
+                               close(u);
+ clobber_refused:
+                               u = -1;
+                               errno = EEXIST;
+                       }
+               }
        }
        if (u < 0) {
                /* herein() may already have printed message */
@@ -1482,7 +1502,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
                        char *sp;
 
                        eno = errno;
-                       warningf(true, "%s %s %s",
+                       warningf(true, "%s %s: %s",
                            "can't finish (dup) redirection",
                            (sp = snptreef(NULL, 32, "%R", &iotmp)),
                            cstrerror(eno));
@@ -1518,9 +1538,9 @@ iosetup(struct ioword *iop, struct tbl *tp)
  * unquoted, the string is expanded first.
  */
 static int
-hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
+hereinval(struct ioword *iop, int sub, char **resbuf, struct shf *shf)
 {
-       const char * volatile ccp = content;
+       const char * volatile ccp = iop->heredoc;
        struct source *s, *osource;
 
        osource = source;
@@ -1531,7 +1551,9 @@ hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
                /* special to iosetup(): don't print error */
                return (-2);
        }
-       if (sub) {
+       if (iop->ioflag & IOHERESTR) {
+               ccp = evalstr(iop->delim, DOHERESTR | DOSCALAR | DOHEREDOC);
+       } else if (sub) {
                /* do substitutions on the content of heredoc */
                s = pushs(SSTRING, ATEMP);
                s->start = s->str = ccp;
@@ -1560,7 +1582,7 @@ herein(struct ioword *iop, char **resbuf)
        int i;
 
        /* ksh -c 'cat <<EOF' can cause this... */
-       if (iop->heredoc == NULL) {
+       if (iop->heredoc == NULL && !(iop->ioflag & IOHERESTR)) {
                warningf(true, "%s missing", "here document");
                /* special to iosetup(): don't print error */
                return (-2);
@@ -1571,7 +1593,7 @@ herein(struct ioword *iop, char **resbuf)
 
        /* skip all the fd setup if we just want the value */
        if (resbuf != NULL)
-               return (hereinval(iop->heredoc, i, resbuf, NULL));
+               return (hereinval(iop, i, resbuf, NULL));
 
        /*
         * Create temp file to hold content (done before newenv
@@ -1588,7 +1610,7 @@ herein(struct ioword *iop, char **resbuf)
                return (-2);
        }
 
-       if (hereinval(iop->heredoc, i, NULL, shf) == -2) {
+       if (hereinval(iop, i, NULL, shf) == -2) {
                close(fd);
                /* special to iosetup(): don't print error */
                return (-2);