-/* $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
#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"
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 *);
(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))
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);
}
/* check if path is something we want to find */
-static int
+int
search_access(const char *fn, int mode)
{
struct stat sb;
/* 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 */
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);
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;
/* 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)) {
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:
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 */
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));
* 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;
/* 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;
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);
/* 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
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);