Sat Aug 25 11:45:40 2018 UTC ()
Pull up following revision(s) (requested by kre in ticket #982):

	bin/sh/eval.c: revision 1.157

PR bin/42184 PR bin/52687  (detailing the same bug).

Fix "command not found" handling so that the error message
goes to stderr (after any redirections are applied).

More importantly, in

	foo > /tmp/junk

/tmp/junk should be created, before any attempt is made
to execute (the assumed non-existing) "foo".

All this was always true for any command (not found command)
containing a / in its name

	foo/bar >/tmp/junk  2>>/tmp/errs

would have created /tmp/junk, then complained (in /tmp/errs)
about foo/bar not being found.   Now that happens for ordinary
commands as well.

The fix (which I found when I saw differences between our
code and FreeBSD's, where, for the benefit of PR 42184,
this has been fixed, sometime in the past 9 years) is
frighteningly simple.   Simply do not short circuit execution
(or print any error) when the initial lookup fails to
find the command - it will fail anyway when we actually
try running it.   The cost is a (seemingly unnecessary,
except that it really is) fork in this case.

This is what I had been planning, but I expected it would
be much more difficult than it turned out....

XXX pullup-8


(martin)
diff -r1.140.2.3 -r1.140.2.4 src/bin/sh/eval.c

cvs diff -r1.140.2.3 -r1.140.2.4 src/bin/sh/eval.c (expand / switch to unified diff)

--- src/bin/sh/eval.c 2018/07/13 14:29:15 1.140.2.3
+++ src/bin/sh/eval.c 2018/08/25 11:45:40 1.140.2.4
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: eval.c,v 1.140.2.3 2018/07/13 14:29:15 martin Exp $ */ 1/* $NetBSD: eval.c,v 1.140.2.4 2018/08/25 11:45:40 martin Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1993 4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -27,27 +27,27 @@ @@ -27,27 +27,27 @@
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; 38static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
39#else 39#else
40__RCSID("$NetBSD: eval.c,v 1.140.2.3 2018/07/13 14:29:15 martin Exp $"); 40__RCSID("$NetBSD: eval.c,v 1.140.2.4 2018/08/25 11:45:40 martin Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <stdbool.h> 44#include <stdbool.h>
45#include <stdlib.h> 45#include <stdlib.h>
46#include <signal.h> 46#include <signal.h>
47#include <stdio.h> 47#include <stdio.h>
48#include <string.h> 48#include <string.h>
49#include <errno.h> 49#include <errno.h>
50#include <limits.h> 50#include <limits.h>
51#include <unistd.h> 51#include <unistd.h>
52#include <sys/fcntl.h> 52#include <sys/fcntl.h>
53#include <sys/stat.h> 53#include <sys/stat.h>
@@ -893,73 +893,83 @@ evalcommand(union node *cmd, int flgs, s @@ -893,73 +893,83 @@ evalcommand(union node *cmd, int flgs, s
893 for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next) 893 for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next)
894 if (outredir(&errout, rn, sep)) 894 if (outredir(&errout, rn, sep))
895 sep = ' '; 895 sep = ' ';
896 outc('\n', &errout); 896 outc('\n', &errout);
897 flushout(&errout); 897 flushout(&errout);
898 } 898 }
899 899
900 /* Now locate the command. */ 900 /* Now locate the command. */
901 if (argc == 0) { 901 if (argc == 0) {
902 cmdentry.cmdtype = CMDSPLBLTIN; 902 cmdentry.cmdtype = CMDSPLBLTIN;
903 cmdentry.u.bltin = bltincmd; 903 cmdentry.u.bltin = bltincmd;
904 } else { 904 } else {
905 static const char PATH[] = "PATH="; 905 static const char PATH[] = "PATH=";
906 int cmd_flags = DO_ERR; 906 int cmd_flags = 0;
907 907
908 /* 908 /*
909 * Modify the command lookup path, if a PATH= assignment 909 * Modify the command lookup path, if a PATH= assignment
910 * is present 910 * is present
911 */ 911 */
912 for (sp = varlist.list; sp; sp = sp->next) 912 for (sp = varlist.list; sp; sp = sp->next)
913 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) 913 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
914 path = sp->text + sizeof(PATH) - 1; 914 path = sp->text + sizeof(PATH) - 1;
915 915
916 do { 916 do {
917 int argsused, use_syspath; 917 int argsused, use_syspath;
918 918
919 find_command(argv[0], &cmdentry, cmd_flags, path); 919 find_command(argv[0], &cmdentry, cmd_flags, path);
 920#if 0
 921 /*
 922 * This short circuits all of the processing that
 923 * should be done (including processing the
 924 * redirects), so just don't ...
 925 *
 926 * (eventually this whole #if'd block will vanish)
 927 */
920 if (cmdentry.cmdtype == CMDUNKNOWN) { 928 if (cmdentry.cmdtype == CMDUNKNOWN) {
921 exitstatus = 127; 929 exitstatus = 127;
922 flushout(&errout); 930 flushout(&errout);
923 goto out; 931 goto out;
924 } 932 }
 933#endif
925 934
926 /* implement the 'command' builtin here */ 935 /* implement the 'command' builtin here */
927 if (cmdentry.cmdtype != CMDBUILTIN || 936 if (cmdentry.cmdtype != CMDBUILTIN ||
928 cmdentry.u.bltin != bltincmd) 937 cmdentry.u.bltin != bltincmd)
929 break; 938 break;
930 cmd_flags |= DO_NOFUNC; 939 cmd_flags |= DO_NOFUNC;
931 argsused = parse_command_args(argc, argv, &use_syspath); 940 argsused = parse_command_args(argc, argv, &use_syspath);
932 if (argsused == 0) { 941 if (argsused == 0) {
933 /* use 'type' builting to display info */ 942 /* use 'type' builting to display info */
934 cmdentry.u.bltin = typecmd; 943 cmdentry.u.bltin = typecmd;
935 break; 944 break;
936 } 945 }
937 argc -= argsused; 946 argc -= argsused;
938 argv += argsused; 947 argv += argsused;
939 if (use_syspath) 948 if (use_syspath)
940 path = syspath() + 5; 949 path = syspath() + 5;
941 } while (argc != 0); 950 } while (argc != 0);
942 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) 951 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
943 /* posix mandates that 'command <splbltin>' act as if 952 /* posix mandates that 'command <splbltin>' act as if
944 <splbltin> was a normal builtin */ 953 <splbltin> was a normal builtin */
945 cmdentry.cmdtype = CMDBUILTIN; 954 cmdentry.cmdtype = CMDBUILTIN;
946 } 955 }
947 956
948 /* Fork off a child process if necessary. */ 957 /* Fork off a child process if necessary. */
949 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0) 958 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0)
950 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 959 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
951 || ((flags & EV_BACKCMD) != 0 960 && (flags & EV_EXIT) == 0)
952 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) 961 || ((flags & EV_BACKCMD) != 0 &&
 962 ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
953 || cmdentry.u.bltin == dotcmd 963 || cmdentry.u.bltin == dotcmd
954 || cmdentry.u.bltin == evalcmd))) { 964 || cmdentry.u.bltin == evalcmd))) {
955 INTOFF; 965 INTOFF;
956 jp = makejob(cmd, 1); 966 jp = makejob(cmd, 1);
957 mode = cmd->ncmd.backgnd; 967 mode = cmd->ncmd.backgnd;
958 if (mode) 968 if (mode)
959 flags &= ~EV_MORE; 969 flags &= ~EV_MORE;
960 if (flags & EV_BACKCMD) { 970 if (flags & EV_BACKCMD) {
961 mode = FORK_NOJOB; 971 mode = FORK_NOJOB;
962 if (sh_pipe(pip) < 0) 972 if (sh_pipe(pip) < 0)
963 error("Pipe call failed"); 973 error("Pipe call failed");
964 } 974 }
965#ifdef DO_SHAREDVFORK 975#ifdef DO_SHAREDVFORK