logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git
commit: 8a7eb04bf04ebec1f6ccfe04c64a3452e9409d3b
parent 6b6c36f666e0ac60772872fd49111c823dce2af0
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat,  7 Sep 2024 11:27:08 +0200

cmd/chmod: fix handling of -w,+x as a mode

Diffstat:

Mcmd/chmod.17+++++++
Mcmd/chmod.c47++++++++++++++++++++++-------------------------
Mtest-cmd/chmod.sh18++++++++++++++++--
3 files changed, 45 insertions(+), 27 deletions(-)

diff --git a/cmd/chmod.1 b/cmd/chmod.1 @@ -26,6 +26,13 @@ can be either an octal natural number between 0 and 7777 (ie. 0644 for rw-r--r-- see .Sx SYMBOLIC OPERATIONS section for more information. +.Pp +If +.Ar mode +starts with a dash (or is user-provided), it should be broken from options with a preceeding double-dash +.Pq -- +like so: +.Dl chmod -v -- -w,+r foobar .Sh OPTIONS .Bl -tag -width Ds .It Fl c diff --git a/cmd/chmod.c b/cmd/chmod.c @@ -180,13 +180,28 @@ main(int argc, char *argv[]) {0, 0, 0, 0}, }; // clang-format on +#endif + + while(true) + { + if(optind >= argc || !argv[optind]) break; - // Need + as first character to get POSIX-style option parsing - while((c = getopt_long(argc, argv, "+:cRv", opts, NULL)) != -1) + if(argv[optind][0] == '-' && strchr("rwxugoa", argv[optind][1])) + { + fprintf(stderr, + "chmod: Portability Warning: Pass -- before a mode with a leading dash(-) to " + "separate it from options\n"); + break; + } + +#ifdef HAS_GETOPT_LONG + // Need + as first character to get POSIX-style option parsing + c = getopt_long(argc, argv, "+:cRv", opts, NULL); #else - while((c = getopt(argc, argv, ":cRv")) != -1) + c = getopt(argc, argv, ":cRv"); #endif - { + if(c == -1) break; + switch(c) { case 'c': // GNU @@ -203,29 +218,11 @@ main(int argc, char *argv[]) usage(); return 1; case '?': // GNU - switch(optopt) - { - case 'r': - case 'w': - case 'x': - case 'u': - case 'g': - case 'o': - case 'a': - fprintf(stderr, - "chmod: Portability Warning: Pass -- before a mode with a leading dash(-) to " - "separate it from options\n"); - optind--; - goto getopt_out; - - default: - fprintf(stderr, "chmod: Error: Unrecognised option: '-%c'\n", optopt); - usage(); - return 1; - } + fprintf(stderr, "chmod: Error: Unrecognised option: '-%c'\n", optopt); + usage(); + return 1; } } -getopt_out: argc -= optind; argv += optind; diff --git a/test-cmd/chmod.sh b/test-cmd/chmod.sh @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MPL-2.0 target="$(dirname "$0")/../cmd/chmod" -plans=7 +plans=11 . "$(dirname "$0")/tap.sh" tmpfile="${TMPDIR-/tmp}/test_chmod_$(date +%s)" @@ -28,4 +28,18 @@ t '0777' "-v 0777 $tmpfile" "chmod: Permissions changed from 00444/-r--r--r-- to t --exit=1 'invalid 0888' "-v 0888 $tmpfile" "chmod: Failed parsing mode '0888': contains digit outside of [0-7] " -rm "$tmpfile" || exit 1 +t 'mode:-w,+x' "-v -w,+x $tmpfile" "chmod: Portability Warning: Pass -- before a mode with a leading dash(-) to separate it from options +chmod: Permissions changed from 00777/-rwxrwxrwx to 00577/-r-xrwxrwx for '${tmpfile}' +" + +t 'mode:-r' "-v -r $tmpfile" "chmod: Portability Warning: Pass -- before a mode with a leading dash(-) to separate it from options +chmod: Permissions changed from 00577/-r-xrwxrwx to 00133/---x-wx-wx for '${tmpfile}' +" + +t '__mode:-x,+w' "-v -- -x,+w $tmpfile" "chmod: Permissions changed from 00133/---x-wx-wx to 00222/--w--w--w- for '${tmpfile}' +" + +t '__mode:-w' "-v -- -w $tmpfile" "chmod: Permissions changed from 00222/--w--w--w- to 00022/-----w--w- for '${tmpfile}' +" + +rm -f "$tmpfile" || exit 1