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>
