Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Apr 2026 08:19:48 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 394f6b1b0a65 - main - ident: Clean up
Message-ID:  <69e884a4.24ad8.3e50202e@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by des:

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

commit 394f6b1b0a658755a9420906fb7a459c3d9501a5
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-04-22 08:19:35 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-04-22 08:19:35 +0000

    ident: Clean up
    
    * Use libcasper instead of reinventing it.
    
    * Add long option support.
    
    * Drop pointless use of temporary locales.
    
    * Consistently check for stdio errors.
    
    * Clean up the code.
    
    * Clean up and expand the tests.
    
    MFC after:      1 week
    Reviewed by:    ngie
    Differential Revision:  https://reviews.freebsd.org/D56505
---
 usr.bin/ident/Makefile            |   6 ++
 usr.bin/ident/ident.1             |  11 +--
 usr.bin/ident/ident.c             | 146 ++++++++++++++++++++------------------
 usr.bin/ident/tests/ident_test.sh |  94 +++++++++++++++++++++---
 4 files changed, 172 insertions(+), 85 deletions(-)

diff --git a/usr.bin/ident/Makefile b/usr.bin/ident/Makefile
index 8695ae3e6003..5c1a75f5a56e 100644
--- a/usr.bin/ident/Makefile
+++ b/usr.bin/ident/Makefile
@@ -2,6 +2,12 @@
 
 PROG=	ident
 
+.if ${MK_CASPER} != "no"
+LIBADD+=	casper
+LIBADD+=	cap_fileargs
+CFLAGS+=	-DWITH_CASPER
+.endif
+
 HAS_TESTS=
 SUBDIR.${MK_TESTS}+= tests
 
diff --git a/usr.bin/ident/ident.1 b/usr.bin/ident/ident.1
index c17279720517..3583b319d80b 100644
--- a/usr.bin/ident/ident.1
+++ b/usr.bin/ident/ident.1
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 25, 2015
+.Dd April 18, 2026
 .Dt IDENT 1
 .Os
 .Sh NAME
@@ -52,15 +52,18 @@ and a space.
 .Pp
 These options are supported:
 .Bl -tag -width "XXX"
-.It Fl q
+.It Fl q , Fl -quiet
 Quiet mode: suppress warnings if no pattern found.
-.It Fl V
+.It Fl V , Fl -version
 Do nothing, added for compatibility with GNU ident.
 .El
 .Sh EXIT STATUS
 .Ex -std ident
 .Sh AUTHORS
+.An -nosplit
 This version of the
 .Nm
 utility was written by
-.An Baptiste Daroussin Aq Mt bapt@FreeBSD.org .
+.An Baptiste Daroussin Aq Mt bapt@FreeBSD.org
+and
+.An Dag-Erling Sm\(/orrgav Aq Mt des@FreeBSD.org .
diff --git a/usr.bin/ident/ident.c b/usr.bin/ident/ident.c
index 96190723dbf7..eefb8b3a48de 100644
--- a/usr.bin/ident/ident.c
+++ b/usr.bin/ident/ident.c
@@ -1,4 +1,5 @@
 /*-
+ * Copyright (c) 2026 Dag-Erling Smørgrav <des@FreeBSD.org>
  * Copyright (c) 2015-2021 Baptiste Daroussin <bapt@FreeBSD.org>
  * Copyright (c) 2015 Xin LI <delphij@FreeBSD.org>
  *
@@ -24,20 +25,24 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/capsicum.h>
 #include <sys/types.h>
+#include <sys/capsicum.h>
 #include <sys/sbuf.h>
 
 #include <capsicum_helpers.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#include <getopt.h>
+#include <locale.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <xlocale.h>
+
+#include <libcasper.h>
+#include <casper/cap_fileargs.h>
 
 typedef enum {
 	/* state	condition to transit to next state */
@@ -56,20 +61,20 @@ scan(FILE *fp, const char *name, bool quiet)
 	bool hasid = false;
 	bool subversion = false;
 	analyzer_states state = INIT;
-	FILE* buffp;
+	FILE *buffp;
 	char *buf;
 	size_t sz;
-	locale_t l;
 
-	l = newlocale(LC_ALL_MASK, "C", NULL);
 	sz = 0;
 	buf = NULL;
-	buffp = open_memstream(&buf, &sz);
-	if (buffp == NULL)
-		err(EXIT_FAILURE, "open_memstream()");
+	if ((buffp = open_memstream(&buf, &sz)) == NULL)
+		goto bufferr;
 
-	if (name != NULL)
+	if (name != NULL) {
 		printf("%s:\n", name);
+		if (fflush(stdout) == EOF)
+			err(EXIT_FAILURE, "stdout");
+	}
 
 	while ((c = fgetc(fp)) != EOF) {
 		switch (state) {
@@ -83,13 +88,14 @@ scan(FILE *fp, const char *name, bool quiet)
 			}
 			break;
 		case DELIM_SEEN:
-			if (isalpha_l(c, l)) {
+			if (isalpha(c)) {
 				/* Transit to KEYWORD if we see letter */
 				if (buf != NULL)
 					memset(buf, 0, sz);
-				rewind(buffp);
-				fputc('$', buffp);
-				fputc(c, buffp);
+				if (fseek(buffp, 0, SEEK_SET) != 0 ||
+				    fputc('$', buffp) == EOF ||
+				    fputc(c, buffp) == EOF)
+					goto bufferr;
 				state = KEYWORD;
 
 				continue;
@@ -102,9 +108,10 @@ scan(FILE *fp, const char *name, bool quiet)
 			}
 			break;
 		case KEYWORD:
-			fputc(c, buffp);
+			if (fputc(c, buffp) == EOF)
+				goto bufferr;
 
-			if (isalpha_l(c, l)) {
+			if (isalpha(c)) {
 				/*
 				 * Stay in KEYWORD if additional letter is seen
 				 */
@@ -132,7 +139,8 @@ scan(FILE *fp, const char *name, bool quiet)
 			break;
 		case PUNC_SEEN:
 		case PUNC_SEEN_SVN:
-			fputc(c, buffp);
+			if (fputc(c, buffp) == EOF)
+				goto bufferr;
 
 			switch (c) {
 			case ':':
@@ -166,13 +174,15 @@ scan(FILE *fp, const char *name, bool quiet)
 			}
 			break;
 		case TEXT:
-			fputc(c, buffp);
+			if (fputc(c, buffp) == EOF)
+				goto bufferr;
 
-			if (iscntrl_l(c, l)) {
+			if (iscntrl(c)) {
 				/* Control characters are not allowed in this state */
 				state = INIT;
 			} else if (c == '$') {
-				fflush(buffp);
+				if (fflush(buffp) == EOF)
+					goto bufferr;
 				/*
 				 * valid ident should end with a space.
 				 *
@@ -182,9 +192,11 @@ scan(FILE *fp, const char *name, bool quiet)
 				 * subversion mode.  No length check is enforced
 				 * because GNU RCS ident(1) does not do it either.
 				 */
-				c = buf[strlen(buf) -2 ];
+				c = buf[strlen(buf) - 2];
 				if (c == ' ' || (subversion && c == '#')) {
 					printf("     %s\n", buf);
+					if (fflush(stdout) == EOF)
+						err(EXIT_FAILURE, "stdout");
 					hasid = true;
 				}
 				state = INIT;
@@ -193,32 +205,49 @@ scan(FILE *fp, const char *name, bool quiet)
 			break;
 		}
 	}
-	fclose(buffp);
+	if (fclose(buffp) == EOF)
+		goto bufferr;
 	free(buf);
-	freelocale(l);
 
 	if (!hasid) {
-		if (!quiet)
+		if (!quiet) {
 			fprintf(stderr, "%s warning: no id keywords in %s\n",
 			    getprogname(), name ? name : "standard input");
-
+		}
 		return (EXIT_FAILURE);
 	}
 
 	return (EXIT_SUCCESS);
+bufferr:
+	err(EXIT_FAILURE, "buffer");
 }
 
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: %s [-q] [-V] [file...]", getprogname());
+	exit(EXIT_FAILURE);
+}
+
+static struct option longopts[] = {
+	{ "quiet",	no_argument,	NULL,	'q' },
+	{ "version",	no_argument,	NULL,	'V' },
+	{ NULL,		0,		NULL,	0 }
+};
+
 int
 main(int argc, char **argv)
 {
+	fileargs_t *fa;
+	cap_rights_t rights;
 	bool quiet = false;
-	int ch, i, *fds, fd;
-	int ret = EXIT_SUCCESS;
-	size_t nfds;
+	int i, opt, ret;
 	FILE *fp;
 
-	while ((ch = getopt(argc, argv, "qV")) != -1) {
-		switch (ch) {
+	setlocale(LC_CTYPE, "C");
+
+	while ((opt = getopt_long(argc, argv, "+qV", longopts, NULL)) != -1) {
+		switch (opt) {
 		case 'q':
 			quiet = true;
 			break;
@@ -226,61 +255,36 @@ main(int argc, char **argv)
 			/* Do nothing, compat with GNU rcs's ident */
 			return (EXIT_SUCCESS);
 		default:
-			errx(EXIT_FAILURE, "usage: %s [-q] [-V] [file...]",
-			    getprogname());
+			usage();
 		}
 	}
 
 	argc -= optind;
 	argv += optind;
 
-	if (caph_limit_stdio() < 0)
-		err(EXIT_FAILURE, "unable to limit stdio");
+	cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_FCNTL);
+	fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights, FA_OPEN);
+	if (fa == NULL)
+		err(EXIT_FAILURE, "Unable to initialize casper");
+	caph_cache_catpages();
+	if (caph_limit_stdio() != 0)
+		err(EXIT_FAILURE, "Unable to limit stdio");
+	if (caph_enter_casper() != 0)
+		err(EXIT_FAILURE, "Unable to enter capability mode");
 
 	if (argc == 0) {
-		nfds = 1;
-		fds = malloc(sizeof(*fds));
-		if (fds == NULL)
-			err(EXIT_FAILURE, "unable to allocate fds array");
-		fds[0] = STDIN_FILENO;
+		ret = scan(stdin, NULL, quiet);
 	} else {
-		nfds = argc;
-		fds = malloc(sizeof(*fds) * nfds);
-		if (fds == NULL)
-			err(EXIT_FAILURE, "unable to allocate fds array");
-
+		ret = EXIT_SUCCESS;
 		for (i = 0; i < argc; i++) {
-			fds[i] = fd = open(argv[i], O_RDONLY);
-			if (fd < 0) {
-				warn("%s", argv[i]);
+			if ((fp = fileargs_fopen(fa, argv[i], "r")) == NULL)
+				err(EXIT_FAILURE, "%s", argv[i]);
+			if (scan(fp, argv[i], quiet) != EXIT_SUCCESS)
 				ret = EXIT_FAILURE;
-				continue;
-			}
-			if (caph_limit_stream(fd, CAPH_READ) < 0)
-				err(EXIT_FAILURE,
-				    "unable to limit fcntls/rights for %s",
-				    argv[i]);
-		}
-	}
-
-	/* Enter Capsicum sandbox. */
-	if (caph_enter() < 0)
-		err(EXIT_FAILURE, "unable to enter capability mode");
-
-	for (i = 0; i < (int)nfds; i++) {
-		if (fds[i] < 0)
-			continue;
-
-		fp = fdopen(fds[i], "r");
-		if (fp == NULL) {
-			warn("%s", argv[i]);
-			ret = EXIT_FAILURE;
-			continue;
+			(void)fclose(fp);
 		}
-		if (scan(fp, argc == 0 ? NULL : argv[i], quiet) != EXIT_SUCCESS)
-			ret = EXIT_FAILURE;
-		fclose(fp);
 	}
 
+	fileargs_free(fa);
 	return (ret);
 }
diff --git a/usr.bin/ident/tests/ident_test.sh b/usr.bin/ident/tests/ident_test.sh
index 5422a9708d65..9dcc45a1625f 100755
--- a/usr.bin/ident/tests/ident_test.sh
+++ b/usr.bin/ident/tests/ident_test.sh
@@ -1,15 +1,89 @@
+#
+# Copyright (c) 2026 Dag-Erling Smørgrav <des@FreeBSD.org>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
 
-atf_test_case ident
-ident_body() {
-	atf_check -o file:$(atf_get_srcdir)/test.out \
-		ident < $(atf_get_srcdir)/test.in
-	atf_check -o match:'Foo.*' -s exit:1 \
-		-e inline:"ident warning: no id keywords in $(atf_get_srcdir)/testnoid\n" \
-		ident $(atf_get_srcdir)/test.in $(atf_get_srcdir)/testnoid
-	atf_check -o match:'Foo.*' -s exit:1 \
-		ident -q $(atf_get_srcdir)/test.in $(atf_get_srcdir)/testnoid
+atf_test_case stdin
+stdin_head()
+{
+	atf_set "descr" "Read from stdin"
+}
+stdin_body()
+{
+	local dir=$(atf_get_srcdir)
+	atf_check -o file:"${dir}/test.out" \
+		ident < "${dir}/test.in"
+}
+
+atf_test_case file
+file_head()
+{
+	atf_set "descr" "Read from a file"
+}
+file_body()
+{
+	local dir=$(atf_get_srcdir)
+	echo "${dir}/test.in:" >out
+	cat "${dir}/test.out" >>out
+	atf_check -o file:out ident "${dir}/test.in"
+}
+
+atf_test_case noid
+noid_head()
+{
+	atf_set "descr" "No id keywords in input"
+}
+noid_body()
+{
+	local dir=$(atf_get_srcdir)
+	atf_check \
+	    -s exit:1 \
+	    -o inline:"${dir}/testnoid:\n" \
+	    -e inline:"ident warning: no id keywords in ${dir}/testnoid\n" \
+	    ident "${dir}/testnoid"
+}
+
+atf_test_case multi
+multi_head()
+{
+	atf_set "descr" "Multiple inputs"
+}
+multi_body()
+{
+	local dir=$(atf_get_srcdir)
+	echo "${dir}/test.in:" >out
+	cat "${dir}/test.out" >>out
+	echo "${dir}/testnoid:" >>out
+	atf_check \
+	    -s exit:1 \
+	    -o file:out \
+	    -e inline:"ident warning: no id keywords in ${dir}/testnoid\n" \
+	    ident "${file}"
 }
+
+atf_test_case stdout
+stdout_head()
+{
+	atf_set "descr" "Failure to write to stdout"
+}
+stdout_body()
+{
+	local dir=$(atf_get_srcdir)
+	(
+		trap "" PIPE
+		sleep 1
+		ident "${dir}"/test.in 2>stderr
+		echo $? >result
+	) | true
+	atf_check -o inline:"1\n" cat result
+	atf_check -o match:"stdout" cat stderr
+}
+
 atf_init_test_cases()
 {
-	atf_add_test_case ident
+	atf_add_test_case stdin
+	atf_add_test_case file
+	atf_add_test_case noid
+	atf_add_test_case stdout
 }


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69e884a4.24ad8.3e50202e>