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:
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