Module Name:    src
Committed By:   kre
Date:           Tue Nov 16 11:28:29 UTC 2021

Modified Files:
        src/bin/sh: exec.c sh.1

Log Message:
PR bin/56491

Make "hash" exit(!=0) (ie: exit(1)) if it writes an error message to
stderr as required by POSIX (it was writing "not found" errors, yet
still doing exit(0)).

Whether, when doing "hash foobar", and "foobar" is not found as a command
(not a built-in, not a function, and not found via a PATH search), that
should be considered an error differs between shells.  All of the ksh
descendant shells say "no", write no error message in this case, and
exit(0) if no other errors occur.   Other shells (essentially all) do
consider it an error, write a message to stderr, and exit(1) when this happens.

POSIX isn't clear, the bug report:
     https://austingroupbugs.net/view.php?id=1460
which is not yet resolved, suggests that the outcome will be that
this is to be unspecified.   Given the diversity, there might be no
other choice.

Have a foot in both camps - default to the "other shell" behaviour,
but add a -e option (no errors ... applies only to these "not found"
errors) to generate the ksh behaviour.   Without other errors (like an
unknown option, etc) "hash -e anyname" will always exit(0).

See the PR for details on how it all works now, or read the updated man page.

While here, when hash is in its other mode (reporting what is in the
table) check for I/O errors on stdout, and exit(1) (with an error
message!) if any occurred.   This does not apply to output generated
by the -v option when command names are given (that output is incidental).

In sh.1 document all of this.   Also add documentation for a bunch of
other options the hash command has had for years, but which were never
documented.   And while there, clean up some other sections I noticed
needed improving (either formatting or content or both).


To generate a diff of this commit:
cvs rdiff -u -r1.56 -r1.57 src/bin/sh/exec.c
cvs rdiff -u -r1.236 -r1.237 src/bin/sh/sh.1

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/exec.c
diff -u src/bin/sh/exec.c:1.56 src/bin/sh/exec.c:1.57
--- src/bin/sh/exec.c:1.56	Sun Oct 10 08:19:02 2021
+++ src/bin/sh/exec.c	Tue Nov 16 11:28:29 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec.c,v 1.56 2021/10/10 08:19:02 rillig Exp $	*/
+/*	$NetBSD: exec.c,v 1.57 2021/11/16 11:28:29 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)exec.c	8.4 (Berkeley) 6/8/95";
 #else
-__RCSID("$NetBSD: exec.c,v 1.56 2021/10/10 08:19:02 rillig Exp $");
+__RCSID("$NetBSD: exec.c,v 1.57 2021/11/16 11:28:29 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -360,18 +360,25 @@ hashcmd(int argc, char **argv)
 	struct cmdentry entry;
 	char *name;
 	int allopt=0, bopt=0, fopt=0, ropt=0, sopt=0, uopt=0, verbose=0;
+	int errs=1, emsg=DO_ERR;
+	int status = 0;
 
-	while ((c = nextopt("bcfrsuv")) != '\0')
+	while ((c = nextopt("bcefqrsuv")) != '\0')
 		switch (c) {
 		case 'b':	bopt = 1;	break;
 		case 'c':	uopt = 1;	break;	/* c == u */
+		case 'e':	errs = 0;	break;
 		case 'f':	fopt = 1;	break;
+		case 'q':	emsg = 0;	break;
 		case 'r':	ropt = 1;	break;
 		case 's':	sopt = 1;	break;
 		case 'u':	uopt = 1;	break;
 		case 'v':	verbose = 1;	break;
 		}
 
+	if (!errs)
+		emsg ^= DO_ERR;
+
 	if (ropt)
 		clearcmdentry(0);
 
@@ -406,6 +413,11 @@ hashcmd(int argc, char **argv)
 					printentry(cmdp, verbose);
 			}
 		}
+		flushout(out1);
+		if (io_err(out1)) {
+			out2str("hash: I/O error writing to standard output\n");
+			return 1;
+		}
 		return 0;
 	}
 
@@ -433,7 +445,9 @@ hashcmd(int argc, char **argv)
 				break;
 			}
 		}
-		find_command(name, &entry, DO_ERR, pathval());
+		find_command(name, &entry, emsg, pathval());
+		if (errs && entry.cmdtype == CMDUNKNOWN)
+			status = 1;
 		if (verbose) {
 			if (entry.cmdtype != CMDUNKNOWN) {	/* if no error msg */
 				cmdp = cmdlookup(name, 0);
@@ -443,7 +457,7 @@ hashcmd(int argc, char **argv)
 			flushall();
 		}
 	}
-	return 0;
+	return status;
 }
 
 STATIC void

Index: src/bin/sh/sh.1
diff -u src/bin/sh/sh.1:1.236 src/bin/sh/sh.1:1.237
--- src/bin/sh/sh.1:1.236	Sun Oct 31 02:12:08 2021
+++ src/bin/sh/sh.1	Tue Nov 16 11:28:29 2021
@@ -1,4 +1,4 @@
-.\"	$NetBSD: sh.1,v 1.236 2021/10/31 02:12:08 kre Exp $
+.\"	$NetBSD: sh.1,v 1.237 2021/11/16 11:28:29 kre Exp $
 .\" Copyright (c) 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
@@ -2356,7 +2356,7 @@ last, in the character class.
 .\"
 .Ss Built-ins
 .\"
-This section lists the built-in commands which are built-in because they
+This section lists the built-in commands which are built in because they
 need to perform some operation that can't be performed by a separate
 process.
 Or just because they traditionally are.
@@ -2366,11 +2366,16 @@ be built in for efficiency (e.g.
 .Xr echo 1 ,
 .Xr test 1 ,
 etc).
+Most built-in commands will exit with status 2 if used incorrectly
+(bad options, excess or insufficient number of args, etc).
+Otherwise, unless stated differently, the built-in commands exit with status 0,
+unless some error occurs, which would be reported to standard error.
 .Bl -tag -width 5n -compact
 .Pp
 .It Ic \&: Op Ar arg ...
 A null command that returns a 0 (true) exit value.
-Any arguments or redirects are evaluated, then ignored.
+Any arguments or redirects are evaluated just as for any other command,
+then ignored.
 .\"
 .Pp
 .It Ic \&. Ar file
@@ -2427,18 +2432,24 @@ have a shell function with the same name
 .It Fl p
 search for command using a
 .Ev PATH
-that guarantees to find all the standard utilities.
+that guarantees to find all the standard utilities,
+but not necessarily any others.
 .It Fl V
-Do not execute the command but
-search for the command and print the resolution of the
-command search.
+Do not execute the
+.Ar command
+but search for the
+.Ar command
+and print the resolution of the command search.
 This is the same as the
 .Ic type
 built-in.
 .It Fl v
-Do not execute the command but
-search for the command and print the absolute pathname
-of utilities, the name for built-ins or the expansion of aliases.
+Do not execute the
+.Ar command
+but search for the
+.Ar command
+and print the absolute pathname of utilities,
+the name for built-ins or the expansion of aliases.
 .El
 .\"
 .Pp
@@ -2450,7 +2461,7 @@ If
 is specified, then the new directory name is generated by replacing
 the first occurrence of the string
 .Ar directory
-in the current directory name with
+in the current working directory name with
 .Ar replace .
 Otherwise if
 .Ar directory
@@ -2465,11 +2476,14 @@ appears in the environment of the
 .Ic cd
 command or the shell variable
 .Ev CDPATH
-is set and the directory name does not begin with a slash,
+is set and the
+.Ar directory
+name does not begin with a slash,
 and its first (or only) component isn't dot or dot dot,
 then the directories listed in
 .Ev CDPATH
-will be searched for the specified directory.
+will be searched for the specified
+.Ar directory .
 The format of
 .Ev CDPATH
 is the same as that of
@@ -2520,8 +2534,8 @@ Some shells also support a
 .Fl L
 option, which instructs the shell to update
 .Ev PWD
-with the logical path and to change the current directory
-accordingly.
+with the logical path using string manipulation,
+and then to change the current directory accordingly.
 This is not supported.
 .Pp
 In an interactive shell, or if the
@@ -2529,7 +2543,7 @@ In an interactive shell, or if the
 option is set, the
 .Ic cd
 command will print out the name of the
-directory that it actually switched to
+directory that it actually switched to;
 .Po that is, the pathname passed to the successful
 .Xr chdir 2
 .No system call Pc
@@ -2542,7 +2556,7 @@ The destination may be different because
 a non-empty element of the
 .Ev CDPATH
 mechanism was used,
-.\" or because a symbolic link was crossed.   XXX Definitively not.
+.\" or because a symbolic link was crossed.  XXX Definitively not (not even -L)
 or because the
 .Ar replace
 argument was used,
@@ -2553,8 +2567,13 @@ parameter was specified as
 .\"
 .Pp
 .It Ic eval Ar string ...
-Concatenate all the arguments with spaces.
-Then re-parse and execute the command.
+Concatenate all the
+.Ar string
+arguments with intervening spaces.
+Then parse and execute the command resulting.
+The exit status from
+.Ic eval
+is the exit status of the command executed, or 0 if there was none.
 .\"
 .Pp
 .It Ic exec Op Ar command Op Ar arg ...
@@ -2590,9 +2609,9 @@ redirect the descriptor to (or from) its
 either when invoking a command for which the descriptor is wanted open,
 or by using
 .Ic exec
-(perhaps the same
+.Po perhaps the same
 .Ic exec
-as opened it, after the open)
+.No as opened it, after the open Pc
 to leave the descriptor open in the shell
 and pass it to all commands invoked subsequently.
 Alternatively, see the
@@ -2624,7 +2643,8 @@ Variables can also be un-exported using 
 built in command.
 With
 .Fl x
-(exclude) the specified names are marked not to be exported,
+.Pq exclude
+the specified names are marked not to be exported,
 and any that had been exported, will be un-exported.
 Later attempts to export the variable will be refused.
 Note this does not prevent explicitly exporting a variable
@@ -2633,11 +2653,14 @@ command invocation by a variable assignm
 provided the variable is not also read-only.
 That is
 .Bd -literal -offset indent
-export -x FOO # FOO will now not be exported by default
+export -x FOO # FOO will now not be able to be exported
 export FOO    # this command will fail (non-fatally)
+.Ed
+But with
+.Bd -literal -offset indent -compact
 FOO=some_value my_command
 .Ed
-.Pp
+.Nm
 still passes the value
 .Pq Li FOO=some_value
 to
@@ -2964,29 +2987,145 @@ cmd \-a \-carg \-\- file file
 .Ed
 .\"
 .Pp
-.It Ic hash Oo Fl rv Oc Op Ar command ...
+.It Ic hash Oo Fl befqrsuv Oc Op Ar command ...
 The shell maintains a hash table which remembers the
-locations of commands.
-With no arguments whatsoever,
+locations and types of commands.
+With the
+.Fl r
+option given,
 the
 .Ic hash
-command prints out the contents of this table.
-Entries which have not been looked at since the last
+command begins by clearing all commands,
+except special built-in commands and functions,
+from this table.
+Commands, other than functions, are added to the table as
+described below, or as they are encountered
+through normal execution, or for functions,
+when they are defined.
+Functions are removed with the
+.Ic unset
+built-in command.
+Special built-in commands are added at shell startup,
+and never removed.
+Utilities can also be removed when
+.Ev PATH
+is altered.
+.Pp
+With no
+.Ar command
+arguments
+the
+.Ic hash
+command then prints out the contents of this table.
+Note that this is a hash table, the order of the
+contents is unpredictable, and meaningless.
+.Pp
+The
+.Fl b ,
+.Fl f ,
+.Fl s ,
+and
+.Fl u
+oprions control which entries are printed.
+With
+.Fl f
+functions are printed; with
+.Fl b
+or
+.Fl s
+regular, or special, built-in commands are listed;
+and with
+.Fl u
+normal utilities (those commands found in the filesystem
+by searching
+.Ev PATH )
+are printed.
+For compatibility with some older versions of the
+.Ic hash
+command,
+.Fl c
+is accepted as an alternative of
+.Fl u .
+.Pp
+Some normal command entries which have not been verified since the last
 .Ic cd
 command are marked with an asterisk; it is possible for these entries
 to be invalid.
 .Pp
-With arguments, the
+The
+.Fl v
+option causes more verbose output to be included, indicating the
+type of the command, rather than simply its name.
+For functions, the body of the function is included.
+.Pp
+If none of the above options is given, the default is to
+show normal commands only.
+With
+.Fl v
+and no other options, the whole table (all types) will be shown.
+.Pp
+Unless there is an error writing the output, the
+.Ic hash
+command will exit with status 0 in this usage.
+.Pp
+With
+.Ar command
+arguments, the
 .Ic hash
 command removes the specified commands from the hash table (unless
-they are functions) and then locates them.
+they are functions or special built-in commands) and then locates
+and reinstalls them.
 With the
 .Fl v
-option, hash prints the locations of the commands as it finds them.
+option,
+.Ic hash
+prints the locations of the commands as it finds them.
 The
-.Fl r
-option causes the hash command to delete all the entries in the hash table
-except for functions.
+.Fl bfsu
+options control which types of commands will be affected.
+If any of those options is given, and a command found to
+already be in the hash table is not one of the designated types,
+that entry, and the
+.Ar command
+argument, will simply be silently skipped.
+If none of those flags is given, any command type can be affected.
+.Pp
+If a
+.Ar command
+is not located, then unless
+.Fl q
+was given, a
+.Dq not found
+error message will be printed.
+.Pp
+The
+.Fl e
+option implies
+.Fl q
+if that option was not given, and also causes the exit status
+of the
+.Ic hash
+command to ignore the unfound
+.Ar command .
+Otherwise if any
+.Ar command
+is not found, the
+.Ic hash
+command will exit with status 1.
+.Pp
+To allow a method to premit backwards compatability with the way
+that the
+.Ic hash
+command worked before
+.Nx 10
+if both the
+.Fl e
+and
+.Fl q
+options are given, then an error message will be printed about
+.Ar command Ns No s
+unable to be found, but the exit status will remain 0.
+This is not considered useful.
 .\"
 .Pp
 .It Ic inputrc Ar file
@@ -3310,9 +3449,6 @@ is checked to see if it refers to the cu
 the value is printed.
 Otherwise the current directory name is found using
 .Xr getcwd 3 .
-The environment variable
-.Ev PWD
-is set to the printed value.
 .Pp
 The default is
 .Ic pwd

Reply via email to