git: fb15a9f90b29 - stable/12 - ar: provide error exit status upon failure

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Sat, 09 Oct 2021 00:30:17 UTC
The branch stable/12 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=fb15a9f90b29da471892ad1e0a1bb7173a7da858

commit fb15a9f90b29da471892ad1e0a1bb7173a7da858
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2021-08-03 18:30:06 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2021-10-09 00:29:30 +0000

    ar: provide error exit status upon failure
    
    Previously ar and ranlib returned with exit status 0 (success) in the
    case of a missing file or other error.  Update to use error handling
    similar to that added by ELF Tool Chain after that project forked
    FreeBSD's ar.
    
    PR:             PR257599 [exp-run]
    Reported by:    Shawn Webb, gehmehgeh (on HardenedBSD IRC)
    Reviewed by:    markj
    Obtained from:  elftoolchain
    MFC after:      2 months
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D31402
    
    (cherry picked from commit 38911b3c2c7dbb9a097b44856472ebbbedde71fc)
---
 usr.bin/ar/acplex.l  |  4 ++--
 usr.bin/ar/acpyacc.y |  6 ++---
 usr.bin/ar/ar.c      | 62 ++++++++++++++++++++++++++++------------------------
 usr.bin/ar/ar.h      | 20 ++++++++---------
 usr.bin/ar/read.c    | 36 +++++++++++++++++++-----------
 usr.bin/ar/write.c   | 49 ++++++++++++++++++++++++-----------------
 6 files changed, 100 insertions(+), 77 deletions(-)

diff --git a/usr.bin/ar/acplex.l b/usr.bin/ar/acplex.l
index f9b7deba0dda..8eb47e6a8d0e 100644
--- a/usr.bin/ar/acplex.l
+++ b/usr.bin/ar/acplex.l
@@ -33,8 +33,8 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 
 #include "y.tab.h"
 
@@ -72,7 +72,7 @@ SAVE|save		{ return (SAVE); }
 [-_A-Za-z0-9/:$.\\]+	{
 	yylval.str = strdup(yytext);
 	if (yylval.str == NULL)
-		errc(EX_SOFTWARE, errno, "strdup failed");
+		errc(EXIT_FAILURE, errno, "strdup failed");
 	return (FNAME);
 }
 
diff --git a/usr.bin/ar/acpyacc.y b/usr.bin/ar/acpyacc.y
index 113b3818bff1..5d4eb9fb6b37 100644
--- a/usr.bin/ar/acpyacc.y
+++ b/usr.bin/ar/acpyacc.y
@@ -191,7 +191,7 @@ directory_cmd
 	;
 
 end_cmd
-	: END { arscp_end(EX_OK); }
+	: END { arscp_end(EXIT_SUCCESS); }
 	;
 
 extract_cmd
@@ -655,9 +655,9 @@ ar_mode_script(struct bsdar *ar)
 	interactive = isatty(fileno(stdin));
 	while(yyparse()) {
 		if (!interactive)
-			arscp_end(1);
+			arscp_end(EXIT_FAILURE);
 	}
 
 	/* Script ends without END */
-	arscp_end(EX_OK);
+	arscp_end(EXIT_SUCCESS);
 }
diff --git a/usr.bin/ar/ar.c b/usr.bin/ar/ar.c
index 8e02471e1623..b131163342a6 100644
--- a/usr.bin/ar/ar.c
+++ b/usr.bin/ar/ar.c
@@ -72,7 +72,6 @@ __FBSDID("$FreeBSD$");
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 
 #include "ar.h"
 
@@ -102,10 +101,11 @@ main(int argc, char **argv)
 	struct bsdar	*bsdar, bsdar_storage;
 	char		*p;
 	size_t		 len;
-	int		 i, opt, Dflag, Uflag;
+	int		 exitcode, i, opt, Dflag, Uflag;
 
 	bsdar = &bsdar_storage;
 	memset(bsdar, 0, sizeof(*bsdar));
+	exitcode = EXIT_SUCCESS;
 	Dflag = 0;
 	Uflag = 0;
 
@@ -151,9 +151,10 @@ main(int argc, char **argv)
 			bsdar->options |= AR_D;
 		bsdar->options |= AR_S;
 		while ((bsdar->filename = *argv++) != NULL)
-			ar_mode_s(bsdar);
+			if (ar_mode_s(bsdar))
+				exitcode = EXIT_FAILURE;
 
-		exit(EX_OK);
+		exit(exitcode);
 	} else {
 		if (argc < 2)
 			bsdar_usage();
@@ -161,7 +162,7 @@ main(int argc, char **argv)
 		if (*argv[1] != '-') {
 			len = strlen(argv[1]) + 2;
 			if ((p = malloc(len)) == NULL)
-				bsdar_errc(bsdar, EX_SOFTWARE, errno,
+				bsdar_errc(bsdar, EXIT_FAILURE, errno,
 				    "malloc failed");
 			*p = '-';
 			(void)strlcpy(p + 1, argv[1], len - 1);
@@ -262,23 +263,23 @@ main(int argc, char **argv)
 		bsdar_usage();
 
 	if (bsdar->options & AR_A && bsdar->options & AR_B)
-		bsdar_errc(bsdar, EX_USAGE, 0,
+		bsdar_errc(bsdar, EXIT_FAILURE, 0,
 		    "only one of -a and -[bi] options allowed");
 
 	if (bsdar->options & AR_J && bsdar->options & AR_Z)
-		bsdar_errc(bsdar, EX_USAGE, 0,
+		bsdar_errc(bsdar, EXIT_FAILURE, 0,
 		    "only one of -j and -z options allowed");
 
 	if (bsdar->options & AR_S && bsdar->options & AR_SS)
-		bsdar_errc(bsdar, EX_USAGE, 0,
+		bsdar_errc(bsdar, EXIT_FAILURE, 0,
 		    "only one of -s and -S options allowed");
 
 	if (bsdar->options & (AR_A | AR_B)) {
 		if (*argv == NULL)
-			bsdar_errc(bsdar, EX_USAGE, 0,
+			bsdar_errc(bsdar, EXIT_FAILURE, 0,
 			    "no position operand specified");
 		if ((bsdar->posarg = basename(*argv)) == NULL)
-			bsdar_errc(bsdar, EX_SOFTWARE, errno,
+			bsdar_errc(bsdar, EXIT_FAILURE, errno,
 			    "basename failed");
 		argc--;
 		argv++;
@@ -310,7 +311,7 @@ main(int argc, char **argv)
 
 	if (bsdar->mode == 'M') {
 		ar_mode_script(bsdar);
-		exit(EX_OK);
+		exit(EXIT_SUCCESS);
 	}
 
 	if ((bsdar->filename = *argv) == NULL)
@@ -321,44 +322,47 @@ main(int argc, char **argv)
 
 	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
 	    bsdar->options & AR_S) {
-		ar_mode_s(bsdar);
+		exitcode = ar_mode_s(bsdar);
 		if (!bsdar->mode)
-			exit(EX_OK);
+			exit(exitcode);
 	}
 
 	switch(bsdar->mode) {
 	case 'd':
-		ar_mode_d(bsdar);
+		exitcode = ar_mode_d(bsdar);
 		break;
 	case 'm':
-		ar_mode_m(bsdar);
+		exitcode = ar_mode_m(bsdar);
 		break;
 	case 'p':
-		ar_mode_p(bsdar);
+		exitcode = ar_mode_p(bsdar);
 		break;
 	case 'q':
-		ar_mode_q(bsdar);
+		exitcode = ar_mode_q(bsdar);
 		break;
 	case 'r':
-		ar_mode_r(bsdar);
+		exitcode = ar_mode_r(bsdar);
 		break;
 	case 't':
-		ar_mode_t(bsdar);
+		exitcode = ar_mode_t(bsdar);
 		break;
 	case 'x':
-		ar_mode_x(bsdar);
+		exitcode = ar_mode_x(bsdar);
 		break;
 	default:
 		bsdar_usage();
 		/* NOTREACHED */
 	}
 
-	for (i = 0; i < bsdar->argc; i++)
-		if (bsdar->argv[i] != NULL)
+	for (i = 0; i < bsdar->argc; i++) {
+		if (bsdar->argv[i] != NULL) {
 			bsdar_warnc(bsdar, 0, "%s: not found in archive",
 			    bsdar->argv[i]);
+			exitcode = EXIT_FAILURE;
+		}
+	}
 
-	exit(EX_OK);
+	exit(exitcode);
 }
 
 static void
@@ -366,7 +370,7 @@ set_mode(struct bsdar *bsdar, char opt)
 {
 
 	if (bsdar->mode != '\0' && bsdar->mode != opt)
-		bsdar_errc(bsdar, EX_USAGE, 0,
+		bsdar_errc(bsdar, EXIT_FAILURE, 0,
 		    "Can't specify both -%c and -%c", opt, bsdar->mode);
 	bsdar->mode = opt;
 }
@@ -376,7 +380,7 @@ only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
 {
 
 	if (strchr(valid_modes, bsdar->mode) == NULL)
-		bsdar_errc(bsdar, EX_USAGE, 0,
+		bsdar_errc(bsdar, EXIT_FAILURE, 0,
 		    "Option %s is not permitted in mode -%c", opt, bsdar->mode);
 }
 
@@ -395,7 +399,7 @@ bsdar_usage(void)
 	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
 	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
 	(void)fprintf(stderr, "\tar -V\n");
-	exit(EX_USAGE);
+	exit(EXIT_FAILURE);
 }
 
 static void
@@ -404,19 +408,19 @@ ranlib_usage(void)
 
 	(void)fprintf(stderr, "usage:	ranlib [-DtU] archive ...\n");
 	(void)fprintf(stderr, "\tranlib -V\n");
-	exit(EX_USAGE);
+	exit(EXIT_FAILURE);
 }
 
 static void
 bsdar_version(void)
 {
 	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version_string());
-	exit(EX_OK);
+	exit(EXIT_SUCCESS);
 }
 
 static void
 ranlib_version(void)
 {
 	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version_string());
-	exit(EX_OK);
+	exit(EXIT_SUCCESS);
 }
diff --git a/usr.bin/ar/ar.h b/usr.bin/ar/ar.h
index 733724748221..21b3a669a943 100644
--- a/usr.bin/ar/ar.h
+++ b/usr.bin/ar/ar.h
@@ -54,7 +54,7 @@
  */
 #define	AC(CALL) do {							\
 	if ((CALL))							\
-		bsdar_errc(bsdar, EX_SOFTWARE, archive_errno(a), "%s",	\
+		bsdar_errc(bsdar, EXIT_FAILURE, archive_errno(a), "%s",	\
 		    archive_error_string(a));				\
 } while (0)
 
@@ -117,13 +117,13 @@ struct bsdar {
 void	bsdar_errc(struct bsdar *, int _eval, int _code,
 	    const char *fmt, ...) __dead2;
 void	bsdar_warnc(struct bsdar *, int _code, const char *fmt, ...);
-void	ar_mode_d(struct bsdar *bsdar);
-void	ar_mode_m(struct bsdar *bsdar);
-void	ar_mode_p(struct bsdar *bsdar);
-void	ar_mode_q(struct bsdar *bsdar);
-void	ar_mode_r(struct bsdar *bsdar);
-void	ar_mode_s(struct bsdar *bsdar);
-void	ar_mode_t(struct bsdar *bsdar);
-void	ar_mode_x(struct bsdar *bsdar);
-void	ar_mode_A(struct bsdar *bsdar);
+int	ar_mode_d(struct bsdar *bsdar);
+int	ar_mode_m(struct bsdar *bsdar);
+int	ar_mode_p(struct bsdar *bsdar);
+int	ar_mode_q(struct bsdar *bsdar);
+int	ar_mode_r(struct bsdar *bsdar);
+int	ar_mode_s(struct bsdar *bsdar);
+int	ar_mode_t(struct bsdar *bsdar);
+int	ar_mode_x(struct bsdar *bsdar);
+int	ar_mode_A(struct bsdar *bsdar);
 void	ar_mode_script(struct bsdar *ar);
diff --git a/usr.bin/ar/read.c b/usr.bin/ar/read.c
index 7791fc155850..04130b859c32 100644
--- a/usr.bin/ar/read.c
+++ b/usr.bin/ar/read.c
@@ -37,38 +37,38 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <libgen.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 
 #include "ar.h"
 
-static void read_archive(struct bsdar *bsdar, char mode);
+static int read_archive(struct bsdar *bsdar, char mode);
 
-void
+int
 ar_mode_p(struct bsdar *bsdar)
 {
 
-	read_archive(bsdar, 'p');
+	return (read_archive(bsdar, 'p'));
 }
 
-void
+int
 ar_mode_t(struct bsdar *bsdar)
 {
 
-	read_archive(bsdar, 't');
+	return (read_archive(bsdar, 't'));
 }
 
-void
+int
 ar_mode_x(struct bsdar *bsdar)
 {
 
-	read_archive(bsdar, 'x');
+	return (read_archive(bsdar, 'x'));
 }
 
 /*
  * Handle read modes: 'x', 't' and 'p'.
  */
-static void
+static int
 read_archive(struct bsdar *bsdar, char mode)
 {
 	struct archive		 *a;
@@ -85,13 +85,15 @@ read_archive(struct bsdar *bsdar, char mode)
 	char			**av;
 	char			  buf[25];
 	char			  find;
-	int			  flags, r, i;
+	int			  exitcode, flags, r, i;
 
 	if ((a = archive_read_new()) == NULL)
-		bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed");
+		bsdar_errc(bsdar, EXIT_FAILURE, 0, "archive_read_new failed");
 	archive_read_support_format_ar(a);
 	AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ));
 
+	exitcode = EXIT_SUCCESS;
+
 	for (;;) {
 		r = archive_read_next_header(a, &entry);
 		if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
@@ -120,7 +122,7 @@ read_archive(struct bsdar *bsdar, char mode)
 				if (*av == NULL)
 					continue;
 				if ((bname = basename(*av)) == NULL)
-					bsdar_errc(bsdar, EX_SOFTWARE, errno,
+					bsdar_errc(bsdar, EXIT_FAILURE, errno,
 					    "basename failed");
 				if (strcmp(bname, name) != 0)
 					continue;
@@ -206,11 +208,19 @@ read_archive(struct bsdar *bsdar, char mode)
 				r = archive_read_extract(a, entry, flags);
 			}
 
-			if (r)
+			if (r) {
 				bsdar_warnc(bsdar, archive_errno(a), "%s",
 				    archive_error_string(a));
+				exitcode = EXIT_FAILURE;
+			}
 		}
 	}
+
+	if (r == ARCHIVE_FATAL)
+		exitcode = EXIT_FAILURE;
+
 	AC(archive_read_close(a));
 	AC(archive_read_free(a));
+
+	return (exitcode);
 }
diff --git a/usr.bin/ar/write.c b/usr.bin/ar/write.c
index f515b2b4eb1e..676a30f923b7 100644
--- a/usr.bin/ar/write.c
+++ b/usr.bin/ar/write.c
@@ -67,52 +67,52 @@ static void	insert_obj(struct bsdar *bsdar, struct ar_obj *obj,
 static void	prefault_buffer(const char *buf, size_t s);
 static void	read_objs(struct bsdar *bsdar, const char *archive,
 		    int checkargv);
-static void	write_archive(struct bsdar *bsdar, char mode);
+static int	write_archive(struct bsdar *bsdar, char mode);
 static void	write_cleanup(struct bsdar *bsdar);
 static void	write_data(struct bsdar *bsdar, struct archive *a,
 		    const void *buf, size_t s);
 static void	write_objs(struct bsdar *bsdar);
 
-void
+int
 ar_mode_d(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 'd');
+	return (write_archive(bsdar, 'd'));
 }
 
-void
+int
 ar_mode_m(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 'm');
+	return (write_archive(bsdar, 'm'));
 }
 
-void
+int
 ar_mode_q(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 'q');
+	return (write_archive(bsdar, 'q'));
 }
 
-void
+int
 ar_mode_r(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 'r');
+	return (write_archive(bsdar, 'r'));
 }
 
-void
+int
 ar_mode_s(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 's');
+	return (write_archive(bsdar, 's'));
 }
 
-void
+int
 ar_mode_A(struct bsdar *bsdar)
 {
 
-	write_archive(bsdar, 'A');
+	return (write_archive(bsdar, 'A'));
 }
 
 /*
@@ -378,16 +378,17 @@ read_objs(struct bsdar *bsdar, const char *archive, int checkargv)
 /*
  * Determine the constitution of resulting archive.
  */
-static void
+static int
 write_archive(struct bsdar *bsdar, char mode)
 {
 	struct ar_obj		 *nobj, *obj, *obj_temp, *pos;
 	struct stat		  sb;
 	const char		 *bname;
 	char			**av;
-	int			  i;
+	int			  exitcode, i;
 
 	TAILQ_INIT(&bsdar->v_obj);
+	exitcode = EXIT_SUCCESS;
 	nobj = NULL;
 	pos = NULL;
 	memset(&sb, 0, sizeof(sb));
@@ -400,14 +401,14 @@ write_archive(struct bsdar *bsdar, char mode)
 		if (errno != ENOENT) {
 			bsdar_warnc(bsdar, 0, "stat %s failed",
 			    bsdar->filename);
-			return;
+			return (EXIT_FAILURE);
 		}
 
 		/* We do not create archive in mode 'd', 'm' and 's'.  */
 		if (mode != 'r' && mode != 'q') {
 			bsdar_warnc(bsdar, 0, "%s: no such file",
 			    bsdar->filename);
-			return;
+			return (EXIT_FAILURE);
 		}
 
 		/* Issue a warning if -c is not specified when creating. */
@@ -491,8 +492,10 @@ write_archive(struct bsdar *bsdar, char mode)
 				 */
 				nobj = create_obj_from_file(bsdar, *av,
 				    obj->mtime);
-				if (nobj == NULL)
+				if (nobj == NULL) {
+					exitcode = EXIT_FAILURE;
 					goto skip_obj;
+				}
 			}
 
 			if (bsdar->options & AR_V)
@@ -526,8 +529,12 @@ new_archive:
 		av = &bsdar->argv[i];
 		if (*av != NULL && (mode == 'r' || mode == 'q')) {
 			nobj = create_obj_from_file(bsdar, *av, 0);
-			if (nobj != NULL)
-				insert_obj(bsdar, nobj, pos);
+			if (nobj == NULL) {
+				exitcode = EXIT_FAILURE;
+				*av = NULL;
+				continue;
+			}
+			insert_obj(bsdar, nobj, pos);
 			if (bsdar->options & AR_V && nobj != NULL)
 				(void)fprintf(stdout, "a - %s\n", *av);
 			*av = NULL;
@@ -537,6 +544,8 @@ new_archive:
 write_objs:
 	write_objs(bsdar);
 	write_cleanup(bsdar);
+
+	return (exitcode);
 }
 
 /*