diff options
author | ahrens <none@none> | 2005-10-31 11:33:35 -0800 |
---|---|---|
committer | ahrens <none@none> | 2005-10-31 11:33:35 -0800 |
commit | fa9e4066f08beec538e775443c5be79dd423fcab (patch) | |
tree | 576d99665e57bb7cb70584431adb08c14d47e3ce /usr/src/cmd/chmod/chmod.c | |
parent | f1b64740276f67fc6914c1d855f2af601efe99ac (diff) | |
download | illumos-joyent-fa9e4066f08beec538e775443c5be79dd423fcab.tar.gz |
PSARC 2002/240 ZFS
6338653 Integrate ZFS
PSARC 2004/652 - DKIOCFLUSH
5096886 Write caching disks need mechanism to flush cache to physical media
Diffstat (limited to 'usr/src/cmd/chmod/chmod.c')
-rw-r--r-- | usr/src/cmd/chmod/chmod.c | 304 |
1 files changed, 281 insertions, 23 deletions
diff --git a/usr/src/cmd/chmod/chmod.c b/usr/src/cmd/chmod/chmod.c index 37f07e0b2e..71dc1de1df 100644 --- a/usr/src/cmd/chmod/chmod.c +++ b/usr/src/cmd/chmod/chmod.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,7 @@ * chmod option mode files * where * mode is [ugoa][+-=][rwxXlstugo] or an octal number + * mode is [<+|->A[# <number] ]<aclspec> * option is -R and -f */ @@ -63,8 +64,10 @@ #include <string.h> /* strerror() */ #include <stdarg.h> #include <limits.h> +#include <ctype.h> #include <errno.h> #include <sys/acl.h> +#include <aclutils.h> static int rflag; static int fflag; @@ -77,25 +80,38 @@ static char **mav; /* Alternate to argv (for parseargs) */ static char *ms; /* Points to the mode argument */ +#define ACL_ADD 1 +#define ACL_DELETE 2 +#define ACL_SLOT_DELETE 3 +#define ACL_REPLACE 4 +#define ACL_STRIP 5 + +typedef struct acl_args { + acl_t *acl_aclp; + int acl_slot; + int acl_action; +} acl_args_t; + extern mode_t newmode_common(char *ms, mode_t new_mode, mode_t umsk, char *file, char *path, o_mode_t *group_clear_bits, o_mode_t *group_set_bits); static int -dochmod(char *name, char *path, mode_t umsk), -chmodr(char *dir, char *path, mode_t mode, mode_t umsk); +dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp), +chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp); +static int doacl(char *file, struct stat *st, acl_args_t *aclp); static void handle_acl(char *name, o_mode_t group_clear_bits, - o_mode_t group_set_bits); + o_mode_t group_set_bits); -static void -usage(void); +static void usage(void); -void -errmsg(int severity, int code, char *format, ...); +void errmsg(int severity, int code, char *format, ...); -static void -parseargs(int ac, char *av[]); +static void parseargs(int ac, char *av[]); + +int +parse_acl_args(char *arg, acl_args_t **acl_args); int main(int argc, char *argv[]) @@ -103,6 +119,7 @@ main(int argc, char *argv[]) int i, c; int status = 0; mode_t umsk; + acl_args_t *acl_args = NULL; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ @@ -134,9 +151,16 @@ main(int argc, char *argv[]) mac -= optind; mav += optind; - if (mac < 2) { - usage(); - exit(2); + if (mac >= 2 && (mav[0][0] == 'A')) { + if (parse_acl_args(*mav, &acl_args)) { + usage(); + exit(2); + } + } else { + if (mac < 2) { + usage(); + exit(2); + } } ms = mav[0]; @@ -144,14 +168,15 @@ main(int argc, char *argv[]) umsk = umask(0); (void) umask(umsk); - for (i = 1; i < mac; i++) - status += dochmod(mav[i], mav[i], umsk); + for (i = 1; i < mac; i++) { + status += dochmod(mav[i], mav[i], umsk, acl_args); + } return (fflag ? 0 : status); } static int -dochmod(char *name, char *path, mode_t umsk) +dochmod(char *name, char *path, mode_t umsk, acl_args_t *aclp) { static struct stat st; int linkflg = 0; @@ -172,9 +197,11 @@ dochmod(char *name, char *path, mode_t umsk) /* Do not recurse if directory is object of symbolic link */ if (rflag && ((st.st_mode & S_IFMT) == S_IFDIR) && !linkflg) - return (chmodr(name, path, st.st_mode, umsk)); + return (chmodr(name, path, st.st_mode, umsk, aclp)); - if (chmod(name, newmode_common(ms, st.st_mode, umsk, name, path, + if (aclp) { + return (doacl(name, &st, aclp)); + } else if (chmod(name, newmode_common(ms, st.st_mode, umsk, name, path, &group_clear_bits, &group_set_bits)) == -1) { errmsg(2, 0, gettext("can't change %s\n"), path); return (1); @@ -195,7 +222,7 @@ dochmod(char *name, char *path, mode_t umsk) static int -chmodr(char *dir, char *path, mode_t mode, mode_t umsk) +chmodr(char *dir, char *path, mode_t mode, mode_t umsk, acl_args_t *aclp) { DIR *dirp; @@ -204,6 +231,7 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk) char currdir[PATH_MAX+1]; /* current dir name + '/' */ char parentdir[PATH_MAX+1]; /* parent dir name + '/' */ int ecode; + struct stat st; o_mode_t group_clear_bits, group_set_bits; if (getcwd(savedir, PATH_MAX) == 0) @@ -213,7 +241,14 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk) /* * Change what we are given before doing it's contents */ - if (chmod(dir, newmode_common(ms, mode, umsk, dir, path, + if (aclp) { + if (lstat(dir, &st) < 0) { + errmsg(2, 0, gettext("can't access %s\n"), path); + return (1); + } + if (doacl(dir, &st, aclp) != 0) + return (1); + } else if (chmod(dir, newmode_common(ms, mode, umsk, dir, path, &group_clear_bits, &group_set_bits)) < 0) { errmsg(2, 0, gettext("can't change %s\n"), path); return (1); @@ -226,8 +261,11 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk) * permissions changes to both the acl mask and the * general group permissions. */ - if (group_clear_bits || group_set_bits) - handle_acl(dir, group_clear_bits, group_set_bits); + + if (aclp == NULL) { /* only necessary when not setting ACL */ + if (group_clear_bits || group_set_bits) + handle_acl(dir, group_clear_bits, group_set_bits); + } if (chdir(dir) < 0) { errmsg(2, 0, "%s/%s: %s\n", savedir, dir, strerror(errno)); @@ -255,7 +293,7 @@ chmodr(char *dir, char *path, mode_t mode, mode_t umsk) for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { (void) strcpy(currdir, parentdir); (void) strcat(currdir, dp->d_name); - ecode += dochmod(dp->d_name, currdir, umsk); + ecode += dochmod(dp->d_name, currdir, umsk, aclp); } (void) closedir(dirp); if (chdir(savedir) < 0) { @@ -301,13 +339,26 @@ usage(void) "usage:\tchmod [-fR] <absolute-mode> file ...\n")); (void) fprintf(stderr, gettext( + "\tchmod [-fR] <ACL-operation> file ...\n")); + + (void) fprintf(stderr, gettext( "\tchmod [-fR] <symbolic-mode-list> file ...\n")); + (void) fprintf(stderr, gettext( "where \t<symbolic-mode-list> is a comma-separated list of\n")); (void) fprintf(stderr, gettext( "\t[ugoa]{+|-|=}[rwxXlstugo]\n")); + + (void) fprintf(stderr, gettext( + "where \t<ACL-operation> is one of the following\n")); + (void) fprintf(stderr, gettext("\tA-<acl_specification>\n")); + (void) fprintf(stderr, gettext("\tA[number]-\n")); + (void) fprintf(stderr, gettext( + "\tA[number]{+|=}<acl_specification>\n")); + (void) fprintf(stderr, gettext( + "where \t<acl-specification> is a comma-separated list of ACEs\n")); } /* @@ -373,6 +424,74 @@ parseargs(int ac, char *av[]) mav[mac] = (char *)NULL; } +int +parse_acl_args(char *arg, acl_args_t **acl_args) +{ + acl_t *new_acl = NULL; + int slot; + int error; + int len; + int action; + acl_args_t *new_acl_args; + char *acl_spec = NULL; + char *end; + + if (arg[0] != 'A') + return (1); + + slot = strtol(&arg[1], &end, 10); + + len = strlen(arg); + switch (*end) { + case '+': + action = ACL_ADD; + acl_spec = ++end; + break; + case '-': + if (len == 2 && arg[0] == 'A' && arg[1] == '-') + action = ACL_STRIP; + else + action = ACL_DELETE; + if (action != ACL_STRIP) { + acl_spec = ++end; + if (acl_spec[0] == '\0') { + action = ACL_SLOT_DELETE; + acl_spec = NULL; + } else if (arg[1] != '-') + return (1); + } + break; + case '=': + action = ACL_REPLACE; + acl_spec = ++end; + break; + default: + return (1); + } + + if ((action == ACL_REPLACE || action == ACL_ADD) && acl_spec[0] == '\0') + return (1); + + if (acl_spec) { + if (error = acl_fromtext(acl_spec, &new_acl)) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + return (1); + } + } + + new_acl_args = malloc(sizeof (acl_args_t)); + if (new_acl_args == NULL) + return (1); + + new_acl_args->acl_aclp = new_acl; + new_acl_args->acl_slot = slot; + new_acl_args->acl_action = action; + + *acl_args = new_acl_args; + + return (0); +} + /* * This function is called whenever the group permissions of a file * is being modified. According to the chmod(1) manpage, any @@ -388,6 +507,14 @@ handle_acl(char *name, o_mode_t group_clear_bits, o_mode_t group_set_bits) aclent_t *aclp, *tp; o_mode_t newperm; + /* + * if this file system support ace_t acl's + * then simply return since we don't have an + * acl mask to deal with + */ + if (pathconf(name, _PC_ACL_ENABLED) == _ACL_ACE_ENABLED) + return; + if ((aclcnt = acl(name, GETACLCNT, 0, NULL)) <= MIN_ACL_ENTRIES) return; /* it's just a trivial acl; no need to change it */ @@ -424,3 +551,134 @@ handle_acl(char *name, o_mode_t group_clear_bits, o_mode_t group_set_bits) } free(aclp); } + +static int +doacl(char *file, struct stat *st, acl_args_t *acl_args) +{ + acl_t *aclp; + acl_t *set_aclp; + int error = 0; + void *to, *from; + int len; + int isdir; + + isdir = S_ISDIR(st->st_mode); + + error = acl_get(file, 0, &aclp); + + if (error != 0) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + return (1); + } + + switch (acl_args->acl_action) { + case ACL_ADD: + if ((error = acl_addentries(aclp, + acl_args->acl_aclp, acl_args->acl_slot)) != 0) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + acl_free(aclp); + return (1); + } + set_aclp = aclp; + break; + case ACL_SLOT_DELETE: + + if (acl_args->acl_slot + 1 > aclp->acl_cnt) { + errmsg(1, 1, + gettext("Invalid slot specified for removal\n")); + acl_free(aclp); + return (1); + } + + if (acl_args->acl_slot == 0 && aclp->acl_cnt == 1) { + errmsg(1, 1, + gettext("Can't remove all ACL " + "entries from a file\n")); + acl_free(aclp); + return (1); + } + + /* + * remove a single entry + * + * if last entry just adjust acl_cnt + */ + + if ((acl_args->acl_slot + 1) == aclp->acl_cnt) + aclp->acl_cnt--; + else { + to = (char *)aclp->acl_aclp + + (acl_args->acl_slot * aclp->acl_entry_size); + from = (char *)to + aclp->acl_entry_size; + len = (aclp->acl_cnt - acl_args->acl_slot - 1) * + aclp->acl_entry_size; + (void) memmove(to, from, len); + aclp->acl_cnt--; + } + set_aclp = aclp; + break; + + case ACL_DELETE: + if ((error = acl_removeentries(aclp, acl_args->acl_aclp, + acl_args->acl_slot, ACL_REMOVE_ALL)) != 0) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + acl_free(aclp); + return (1); + } + + if (aclp->acl_cnt == 0) { + errmsg(1, 1, + gettext("Can't remove all ACL " + "entries from a file\n")); + acl_free(aclp); + return (1); + } + + set_aclp = aclp; + break; + case ACL_REPLACE: + if (acl_args->acl_slot >= 0) { + error = acl_modifyentries(aclp, acl_args->acl_aclp, + acl_args->acl_slot); + if (error) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + acl_free(aclp); + return (1); + } + set_aclp = aclp; + } else { + set_aclp = acl_args->acl_aclp; + } + break; + case ACL_STRIP: + error = acl_strip(file, st->st_uid, st->st_gid, st->st_mode); + if (error) { + errmsg(1, 1, "%s\n", acl_strerror(error)); + return (1); + } + acl_free(aclp); + return (0); + /*NOTREACHED*/ + default: + errmsg(1, 0, gettext("Unknown ACL action requested\n")); + return (1); + break; + } + + error = acl_check(set_aclp, isdir); + + if (error) { + errmsg(1, 0, "%s\n%s", acl_strerror(error), + gettext("See chmod(1) for more information on " + "valid ACL syntax\n")); + return (1); + } + if ((error = acl_set(file, set_aclp)) != 0) { + errmsg(1, 0, gettext("Failed to set ACL: %s\n"), + acl_strerror(error)); + acl_free(aclp); + return (1); + } + acl_free(aclp); + return (0); +} |