git: 8bf37c868f45 - main - getfacl: implement --skip-base (-s)

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Mon, 21 Apr 2025 03:58:06 UTC
The branch main has been updated by kevans:

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

commit 8bf37c868f45e73345b791f9abc6c5a07a1629db
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-04-21 03:57:45 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-04-21 03:57:45 +0000

    getfacl: implement --skip-base (-s)
    
    This skips files that only have a trivial ACL, which is useful for
    callers that want to examine files with more unique ACLs.
    
    While we're here, don't issue the file name/ownership header if we're
    just going to error out on the file; this adds extra noise for little
    gain.
    
    Reviewed by:    markj, olce
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D40603
---
 bin/getfacl/getfacl.1 |  5 ++++
 bin/getfacl/getfacl.c | 65 +++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/bin/getfacl/getfacl.1 b/bin/getfacl/getfacl.1
index b2b6294c46de..475c86e275bc 100644
--- a/bin/getfacl/getfacl.1
+++ b/bin/getfacl/getfacl.1
@@ -75,6 +75,11 @@ Ignored for POSIX.1e ACLs.
 Do not write commented information about file name and ownership.
 This is
 useful when dealing with filenames with unprintable characters.
+.It Fl s , Fl -skip-base
+Skip files that only have a trivial ACL, as defined by
+.Xr acl_is_trivial_np 3 .
+Notably, files with POSIX.1e ACLs that only represent the owner, group and other
+to match the mode of the file will be skipped.
 .It Fl v
 For NFSv4 ACLs, display access mask and flags in a verbose form.
 Ignored for POSIX.1e ACLs.
diff --git a/bin/getfacl/getfacl.c b/bin/getfacl/getfacl.c
index 2b98f923d618..5f55819c81a1 100644
--- a/bin/getfacl/getfacl.c
+++ b/bin/getfacl/getfacl.c
@@ -52,6 +52,7 @@ static const struct option long_options[] =
 	{ "default",		no_argument,	NULL,	'd' },
 	{ "numeric",		no_argument,	NULL,	'n' },
 	{ "omit-header",	no_argument,	NULL,	'q' },
+	{ "skip-base",		no_argument,	NULL,	's' },
 	{ NULL,			no_argument,	NULL,	0 },
 };
 
@@ -90,7 +91,7 @@ getgname(gid_t gid)
 
 static int
 print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
-    int qflag, int vflag)
+    int qflag, int vflag, int sflag)
 {
 	struct stat	sb;
 	acl_t	acl;
@@ -122,25 +123,49 @@ print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
 		return (-1);
 	}
 
+	if (hflag)
+		acl = acl_get_link_np(path, type);
+	else
+		acl = acl_get_file(path, type);
+
+	if (!acl && errno != EOPNOTSUPP) {
+		warn("%s", path);
+		return(-1);
+	}
+
+	if (sflag) {
+		int trivial;
+
+		/*
+		 * With the -s flag, we shouldn't synthesize a trivial ACL if
+		 * they aren't supported as we do below.
+		 */
+		if (!acl)
+			return(0);
+
+		/*
+		 * We also shouldn't render anything for this path if it's a
+		 * trivial ACL.  If we error out, we'll issue a warning but
+		 * proceed with this file to err on the side of caution.
+		 */
+		error = acl_is_trivial_np(acl, &trivial);
+		if (error != 0) {
+			warn("%s: acl_is_trivial_np failed", path);
+		} else if (trivial) {
+			(void)acl_free(acl);
+			return(0);
+		}
+	}
+
 	if (more_than_one)
 		printf("\n");
 	else
 		more_than_one++;
-
 	if (!qflag)
 		printf("# file: %s\n# owner: %s\n# group: %s\n", path,
 		    getuname(sb.st_uid), getgname(sb.st_gid));
 
-	if (hflag)
-		acl = acl_get_link_np(path, type);
-	else
-		acl = acl_get_file(path, type);
 	if (!acl) {
-		if (errno != EOPNOTSUPP) {
-			warn("%s", path);
-			return(-1);
-		}
-		errno = 0;
 		if (type == ACL_TYPE_DEFAULT)
 			return(0);
 		acl = acl_from_mode_np(sb.st_mode);
@@ -176,7 +201,7 @@ print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
 
 static int
 print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
-    int qflag, int vflag)
+    int qflag, int vflag, int sflag)
 {
 	char	*p, pathname[PATH_MAX];
 	int	carried_error = 0;
@@ -185,7 +210,7 @@ print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
 		if ((p = strchr(pathname, '\n')) != NULL)
 			*p = '\0';
 		if (print_acl(pathname, type, hflag, iflag, nflag,
-		    qflag, vflag) == -1) {
+		    qflag, vflag, sflag) == -1) {
 			carried_error = -1;
 		}
 	}
@@ -199,14 +224,15 @@ main(int argc, char *argv[])
 	acl_type_t	type = ACL_TYPE_ACCESS;
 	int	carried_error = 0;
 	int	ch, error, i;
-	int	hflag, iflag, qflag, nflag, vflag;
+	int	hflag, iflag, qflag, nflag, sflag, vflag;
 
 	hflag = 0;
 	iflag = 0;
 	qflag = 0;
 	nflag = 0;
+	sflag = 0;
 	vflag = 0;
-	while ((ch = getopt_long(argc, argv, "+dhinqv", long_options,
+	while ((ch = getopt_long(argc, argv, "+dhinqsv", long_options,
 	    NULL)) != -1)
 		switch(ch) {
 		case 'd':
@@ -224,6 +250,9 @@ main(int argc, char *argv[])
 		case 'q':
 			qflag = 1;
 			break;
+		case 's':
+			sflag = 1;
+			break;
 		case 'v':
 			vflag = 1;
 			break;
@@ -236,19 +265,19 @@ main(int argc, char *argv[])
 
 	if (argc == 0) {
 		error = print_acl_from_stdin(type, hflag, iflag, nflag,
-		    qflag, vflag);
+		    qflag, vflag, sflag);
 		return(error ? 1 : 0);
 	}
 
 	for (i = 0; i < argc; i++) {
 		if (!strcmp(argv[i], "-")) {
 			error = print_acl_from_stdin(type, hflag, iflag, nflag,
-			    qflag, vflag);
+			    qflag, vflag, sflag);
 			if (error == -1)
 				carried_error = -1;
 		} else {
 			error = print_acl(argv[i], type, hflag, iflag, nflag,
-			    qflag, vflag);
+			    qflag, vflag, sflag);
 			if (error == -1)
 				carried_error = -1;
 		}