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.
This commit is contained in:
Michael Forney 2020-01-06 13:08:38 -08:00
parent e5284b1537
commit f3d05ffd0a
3 changed files with 11 additions and 5 deletions

View File

@ -47,7 +47,7 @@ If
.Ar mode .Ar mode
is is
.Em symbolic .Em symbolic
"[ugoa]*[+-=][rwxst]*" "[ugoa]*[+-=][rwxXst]*"
.Bl -tag -width Ds .Bl -tag -width Ds
.It u|g|o|a .It u|g|o|a
owner | group | other (non-group) | everyone owner | group | other (non-group) | everyone
@ -55,6 +55,8 @@ owner | group | other (non-group) | everyone
add | remove | set add | remove | set
.It r|w|x|s|t .It r|w|x|s|t
read | write | execute | setuid and setgid | sticky read | write | execute | setuid and setgid | sticky
.It X
execute, if directory or at least one execute bit is already set
.El .El
.Sh OPTIONS .Sh OPTIONS
.Bl -tag -width Ds .Bl -tag -width Ds

View File

@ -13,7 +13,7 @@ chmodr(const char *path, struct stat *st, void *data, struct recursor *r)
{ {
mode_t m; mode_t m;
m = parsemode(modestr, st->st_mode & ~S_IFMT, mask); m = parsemode(modestr, st->st_mode, mask);
if (chmod(path, m) < 0) { if (chmod(path, m) < 0) {
weprintf("chmod %s:", path); weprintf("chmod %s:", path);
ret = 1; ret = 1;
@ -50,8 +50,8 @@ main(int argc, char *argv[])
case 'P': case 'P':
r.follow = (*argv)[i]; r.follow = (*argv)[i];
break; break;
case 'r': case 'w': case 'x': case 's': case 't': case 'r': case 'w': case 'x': case 'X': case 's': case 't':
/* -[rwxst] are valid modes, so we're done */ /* -[rwxXst] are valid modes, so we're done */
if (i == 1) if (i == 1)
goto done; goto done;
/* fallthrough */ /* fallthrough */

View File

@ -113,6 +113,10 @@ next:
case 'x': case 'x':
perm |= S_IXUSR|S_IXGRP|S_IXOTH; perm |= S_IXUSR|S_IXGRP|S_IXOTH;
break; break;
case 'X':
if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
break;
case 's': case 's':
perm |= S_ISUID|S_ISGID; perm |= S_ISUID|S_ISGID;
break; break;
@ -144,5 +148,5 @@ apply:
goto next; goto next;
} }
} }
return mode; return mode & ~S_IFMT;
} }