logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 69683e73c1845797ec0e57c5e1f2ccfef76965ca
parent 5649c59141e9f117d371187e8819c9e9ebf77b3d
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 24 May 2025 21:29:39 +0200

cmd/chown: Add support for --reference

Diffstat:

Mcmd/chown.130++++++++++++++++++++++++++++--
Mcmd/chown.c56+++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest-cmd/chown.t5+++++
3 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/cmd/chown.1 b/cmd/chown.1 @@ -13,11 +13,21 @@ .Op Fl h | Fl R Op Fl HLP .Ar owner Ns Op : Ns Ar group .Ar file... +.Nm chown +.Op Fl v +.Op Fl h | Fl R Op Fl HLP +.Fl -reference Ar ref_file +.Ar file... .Nm chgrp .Op Fl v .Op Fl h | Fl R Op Fl HLP .Ar group .Ar file... +.Nm chgrp +.Op Fl v +.Op Fl h | Fl R Op Fl HLP +.Fl -reference Ar ref_file +.Ar file... .Sh DESCRIPTION .Nm chown sets the user ID given by @@ -38,7 +48,16 @@ The and .Ar group arguments can be either numeric IDs, or names. -Ownership refers to both user and group. +Unless specified, ownership refers to both user and group. +.Pp +If +.Fl -reference +is used instead +.Nm chown +sets both user and group ownership +and +.Nm chmod +sets only group ownership. .Sh OPTIONS .Bl -tag -width Ds .It Fl h @@ -66,6 +85,11 @@ is also specified, change ownership of symbolic links without dereferencing. .It Fl R Recurse into directories. +.It Fl -reference Ar ref_file +Copy ownership from +.Ar ref_file +into each +.Ar file . .It Fl v Verbose, print a message about each processed file, whether a change was made or not. .El @@ -81,6 +105,8 @@ specification. .Pp The .Fl v -option is an extension, also present in GNU coreutils. +and +.Fl -reference +options are extensions, also present in GNU coreutils. .Sh AUTHORS .An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me diff --git a/cmd/chown.c b/cmd/chown.c @@ -204,15 +204,19 @@ int main(int argc, char *argv[]) { argv0 = static_basename(argv[0]); + char *ref_file = NULL; enum chown_follow_symlinks follow_symlinks = CHOWN_FOLLOW_UNK_SYMLINKS; #ifdef HAS_GETOPT_LONG - // Strictly for GNUisms compatibility so no long-only options // clang-format off + enum long_opt_vals { + OPT_REFERENCE = 1, + }; static struct option opts[] = { {"no-dereference", no_argument, 0, 'h'}, {"recursive", no_argument, 0, 'R'}, + {"reference", required_argument, 0, OPT_REFERENCE}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}, }; @@ -244,6 +248,11 @@ main(int argc, char *argv[]) case 'v': opt_v = true; break; +#ifdef HAS_GETOPT_LONG + case OPT_REFERENCE: // GNU & NetBSD + ref_file = optarg; + break; +#endif case ':': fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt); usage(); @@ -263,6 +272,51 @@ main(int argc, char *argv[]) if(follow_symlinks == CHOWN_FOLLOW_UNK_SYMLINKS) follow_symlinks = opt_R ? CHOWN_FOLLOW_NO_SYMLINK : CHOWN_FOLLOW_ALL_SYMLINKS; + if(ref_file != NULL) + { + if(argc < 1) + { + fprintf(stderr, "%s: error: Expects >=1 arguments, %d given\n", argv0, argc); + usage(); + return 1; + } + + struct stat ref_stat; + if(stat(ref_file, &ref_stat) != 0) + { + fprintf(stderr, + "%s: error: Failed to get status from reference file '%s': %s\n", + argv0, + ref_file, + strerror(errno)); + return 1; + } + + if(strcmp(argv0, "chown") == 0) + { + user = ref_stat.st_uid; + group = ref_stat.st_gid; + } + else if(strcmp(argv0, "chgrp") == 0) + { + group = ref_stat.st_gid; + } + else + { + fprintf( + stderr, "%s: error: Unknown utility '%s' expected either chown or chgrp\n", argv0, argv0); + return 1; + } + + for(int i = 0; i < argc; i++) + { + int ret = do_fchownat(AT_FDCWD, argv[i], argv[i], follow_symlinks); + if(ret != 0) return ret; + } + + return 0; + } + if(argc < 2) { fprintf(stderr, "%s: error: Expects >=2 arguments, %d given\n", argv0, argc); diff --git a/test-cmd/chown.t b/test-cmd/chown.t @@ -59,5 +59,10 @@ chown: Ownership already set to \d+:\d+ for 'grp_unchanged' (re) $ rm grp_unchanged + $ touch ref_file ref_unchanged + $ chown -v --reference ref_file ref_unchanged + chown: Ownership already set to \d+:\d+ for 'ref_unchanged' (re) + $ rm ref_file ref_unchanged + $ find . .