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.
master
Michael Forney 3 years ago
parent e5284b1537
commit f3d05ffd0a

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

@ -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 */

@ -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;
}

Loading…
Cancel
Save