commit f3d05ffd0ac4226f9064be5c71606ab9b7d12d92
parent e5284b15378085f541449532798d3d99b13cacd2
Author: Michael Forney <mforney@mforney.org>
Date: Mon, 6 Jan 2020 13:08:38 -0800
chmod: Implement X perm symbol
Instead of clearing the format bits before calling parsemode, leave
them in so we can differentiate between directories and other files,
then clear the format bits in the result.
Diffstat:
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/chmod.1 b/chmod.1
@@ -47,7 +47,7 @@ If
.Ar mode
is
.Em symbolic
-"[ugoa]*[+-=][rwxst]*"
+"[ugoa]*[+-=][rwxXst]*"
.Bl -tag -width Ds
.It u|g|o|a
owner | group | other (non-group) | everyone
@@ -55,6 +55,8 @@ owner | group | other (non-group) | everyone
add | remove | set
.It r|w|x|s|t
read | write | execute | setuid and setgid | sticky
+.It X
+execute, if directory or at least one execute bit is already set
.El
.Sh OPTIONS
.Bl -tag -width Ds
diff --git a/chmod.c b/chmod.c
@@ -13,7 +13,7 @@ chmodr(const char *path, struct stat *st, void *data, struct recursor *r)
{
mode_t m;
- m = parsemode(modestr, st->st_mode & ~S_IFMT, mask);
+ m = parsemode(modestr, st->st_mode, mask);
if (chmod(path, m) < 0) {
weprintf("chmod %s:", path);
ret = 1;
@@ -50,8 +50,8 @@ main(int argc, char *argv[])
case 'P':
r.follow = (*argv)[i];
break;
- case 'r': case 'w': case 'x': case 's': case 't':
- /* -[rwxst] are valid modes, so we're done */
+ case 'r': case 'w': case 'x': case 'X': case 's': case 't':
+ /* -[rwxXst] are valid modes, so we're done */
if (i == 1)
goto done;
/* fallthrough */
diff --git a/libutil/mode.c b/libutil/mode.c
@@ -113,6 +113,10 @@ next:
case 'x':
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
break;
+ case 'X':
+ if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
case 's':
perm |= S_ISUID|S_ISGID;
break;
@@ -144,5 +148,5 @@ apply:
goto next;
}
}
- return mode;
+ return mode & ~S_IFMT;
}