symbolic chmod, thanks pancake

This commit is contained in:
Connor Lane Smith 2011-06-11 00:30:07 +01:00
parent ea7a807a6d
commit 26723ba0dc
3 changed files with 138 additions and 24 deletions

View File

@ -5,6 +5,7 @@ MIT/X Consortium License
© 2011 stateless <stateless@archlinux.us>
© 2011 Rob Pilling <robpilling@gmail.com>
© 2011 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2011 pancake <pancake@youterm.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

63
chmod.1
View File

@ -4,18 +4,65 @@ chmod \- change file mode
.SH SYNOPSIS
.B chmod
.RB [ \-Rr ]
.RI mode
.I octal
.RI [ file ...]
.P
.B chmod
.RB [ \-Rr ]
.RB [ ugoa ][ +-= ][ rwxs ]
.RI [ file ...]
.SH DESCRIPTION
.B chmod
changes the file mode for the given files. The
.I mode
is a four digit octal number derived from its comprising bits.
changes the file mode for the given files.
.P
The first digit defines the setuid (4) and setgid (2) attributes. The second
digit defines the owner's permissions: read (4), write (2), and execute (1); the
third defines permissions for others in the file's group; and the fourth for all
other users. Leading zeroes may be omitted.
If the mode is an
.I octal
number, the modes are set according to that number's comprising bits. The first
digit defines the setuid (4) and setgid (2) attributes. The second digit
defines the owner's permissions: read (4), write (2), and execute (1); the third
defines permissions for others in the file's group; and the fourth for all other
users. Leading zeroes may be omitted.
.P
Alternatively the mode may be symbolic. The symbol meanings are:
.TP
.B u
modifies owner permissions.
.PD 0
.TP
.B g
modifies group permissions.
.TP
.B o
modifies other user permissions.
.TP
.B a
modifies all user permissions.
.PD
.TP
.B +
adds the given permissions to the mode.
.PD 0
.TP
.B -
removes the given permissions from the mode.
.TP
.B =
sets the mode to the given permissions.
.PD
.TP
.B r
read permissions.
.PD 0
.TP
.B w
write permissions.
.TP
.B x
execute permissions.
.TP
.B s
setuid and setgid attributes.
.PD
.SH OPTIONS
.TP
.B \-R, \-r

98
chmod.c
View File

@ -7,15 +7,16 @@
#include "util.h"
static void chmodr(const char *);
static void parsemode(const char *);
static bool rflag = false;
static char oper = '=';
static mode_t mode = 0;
int
main(int argc, char *argv[])
{
char c;
int octal;
while((c = getopt(argc, argv, "Rr")) != -1)
switch(c) {
@ -28,9 +29,45 @@ main(int argc, char *argv[])
}
if(optind == argc)
eprintf("usage: %s [-Rr] mode [file...]\n", argv[0]);
octal = estrtol(argv[optind++], 8);
/* posix doesn't specify modal bits */
parsemode(argv[optind++]);
for(; optind < argc; optind++)
chmodr(argv[optind]);
return EXIT_SUCCESS;
}
void
chmodr(const char *path)
{
struct stat st;
if(stat(path, &st) == -1)
eprintf("stat %s:", path);
switch(oper) {
case '+':
st.st_mode |= mode;
break;
case '-':
st.st_mode &= ~mode;
break;
}
if(chmod(path, st.st_mode) == -1)
eprintf("chmod %s:", path);
if(rflag)
recurse(path, chmodr);
}
void
parsemode(const char *str)
{
char *end;
const char *p;
int octal;
mode_t mask = 0;
octal = strtol(str, &end, 8);
if(*end == '\0') {
if(octal & 04000) mode |= S_ISUID;
if(octal & 02000) mode |= S_ISGID;
if(octal & 00400) mode |= S_IRUSR;
@ -42,17 +79,46 @@ main(int argc, char *argv[])
if(octal & 00004) mode |= S_IROTH;
if(octal & 00002) mode |= S_IWOTH;
if(octal & 00001) mode |= S_IXOTH;
for(; optind < argc; optind++)
chmodr(argv[optind]);
return EXIT_SUCCESS;
}
void
chmodr(const char *path)
{
if(chmod(path, mode) == -1)
eprintf("chmod %s:", path);
if(rflag)
recurse(path, chmodr);
return;
}
for(p = str; *p; p++)
switch(*p) {
/* masks */
case 'u':
mask |= S_IRWXU;
break;
case 'g':
mask |= S_IRWXG;
break;
case 'o':
mask |= S_IRWXO;
break;
case 'a':
mask |= S_IRWXU|S_IRWXG|S_IRWXO;
break;
/* opers */
case '+':
case '-':
case '=':
oper = *p;
break;
/* modes */
case 'r':
mode |= S_IRUSR|S_IRGRP|S_IROTH;
break;
case 'w':
mode |= S_IWUSR|S_IWGRP|S_IWOTH;
break;
case 'x':
mode |= S_IXUSR|S_IXGRP|S_IXOTH;
break;
case 's':
mode |= S_ISUID|S_ISGID;
break;
/* error */
default:
eprintf("%s: invalid mode\n", str);
}
if(mask)
mode &= mask;
}