]> git.saurik.com Git - apple/file_cmds.git/blobdiff - chmod/chmod.c
file_cmds-264.50.1.tar.gz
[apple/file_cmds.git] / chmod / chmod.c
index c01c5dd32b3dfb4501880ee72d5f552189ccdd57..442815d4916aea55b8f492471ebefa6e4e064947 100644 (file)
@@ -31,8 +31,9 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
-static char const copyright[] =
+__used static char const copyright[] =
 "@(#) Copyright (c) 1989, 1993, 1994\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
@@ -57,42 +58,61 @@ __RCSID("$FreeBSD: src/bin/chmod/chmod.c,v 1.27 2002/08/04 05:29:13 obrien Exp $
 #include <string.h>
 #include <unistd.h>
 
+#ifdef __APPLE__
+#include "chmod_acl.h"
+
+#endif /*__APPLE__*/
+
+int fflag = 0;
+
 int main(int, char *[]);
 void usage(void);
 
 int
 main(int argc, char *argv[])
 {
-       FTS *ftsp;
-       FTSENT *p;
-       mode_t *set;
-       long val;
-       int oct;
-       int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
+       FTS *ftsp = NULL;
+       FTSENT *p = NULL;
+       mode_t *set = NULL;
+       long val = 0;
+       int oct = 0;
+       int Hflag, Lflag, Pflag, Rflag, ch, fts_options, hflag, rval;
        int vflag;
        char *ep, *mode;
        mode_t newmode, omode;
+#ifdef __APPLE__
+       unsigned int acloptflags = 0;
+       long aclpos = -1;
+       int inheritance_level = 0;
+       int index = 0;
+       size_t acloptlen = 0;
+       int ace_arg_not_required = 0;
+       acl_t acl_input = NULL;
+#endif /* __APPLE__*/
        int (*change_mode)(const char *, mode_t);
 
        set = NULL;
        omode = 0;
-       Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
+       Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0;
 #ifndef __APPLE__
        while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
 #else
-       while ((ch = getopt(argc, argv, "HLPRXfgorstuvwx")) != -1)
+       while ((ch = getopt(argc, argv, "ACEHILNPRVXafghinorstuvwx")) != -1)
 #endif
                switch (ch) {
                case 'H':
                        Hflag = 1;
                        Lflag = 0;
+                       Pflag = 0;
                        break;
                case 'L':
                        Lflag = 1;
                        Hflag = 0;
+                       Pflag = 0;
                        break;
                case 'P':
                        Hflag = Lflag = 0;
+                       Pflag = 1;
                        break;
                case 'R':
                        Rflag = 1;
@@ -100,7 +120,6 @@ main(int argc, char *argv[])
                case 'f':
                        fflag = 1;
                        break;
-#ifndef __APPLE__
                case 'h':
                        /*
                         * In System V (and probably POSIX.2) the -h option
@@ -112,6 +131,44 @@ main(int argc, char *argv[])
                         */
                        hflag = 1;
                        break;
+#ifdef __APPLE__
+               case 'a':
+                       if (argv[optind - 1][0] == '-' &&
+                           argv[optind - 1][1] == ch)
+                               --optind;
+                       goto done;
+               case 'A':
+//                     acloptflags |= ACL_FLAG | ACL_TO_STDOUT;
+//                     ace_arg_not_required = 1;
+                       errx(1, "-A not implemented");
+                       goto done;
+               case 'E':
+                       acloptflags |= ACL_FLAG | ACL_FROM_STDIN;
+                       goto done;
+               case 'C':
+                       acloptflags |= ACL_FLAG | ACL_CHECK_CANONICITY;
+                       ace_arg_not_required = 1;
+                       goto done;
+               case 'i':
+                       acloptflags |= ACL_FLAG | ACL_REMOVE_INHERIT_FLAG;
+                       ace_arg_not_required = 1;
+                       goto done;
+               case 'I':
+                       acloptflags |= ACL_FLAG | ACL_REMOVE_INHERITED_ENTRIES;
+                       ace_arg_not_required = 1;
+                       goto done;
+               case 'n':
+                       acloptflags |= ACL_FLAG | ACL_NO_TRANSLATE;
+                       break;
+               case 'N':
+                       acloptflags |= ACL_FLAG | ACL_CLEAR_FLAG;
+                       ace_arg_not_required = 1;
+                       goto done;
+               case 'V':
+//                     acloptflags |= ACL_FLAG | ACL_INVOKE_EDITOR;
+//                     ace_arg_not_required = 1;
+                       errx(1, "-V not implemented");
+                       goto done;
 #endif /* __APPLE__ */
                /*
                 * XXX
@@ -136,8 +193,84 @@ main(int argc, char *argv[])
 done:  argv += optind;
        argc -= optind;
 
+#ifdef __APPLE__
+       if (argc < ((acloptflags & ACL_FLAG) ? 1 : 2))
+               usage();
+       if (!Rflag && (Hflag || Lflag || Pflag))
+               warnx("options -H, -L, -P only useful with -R");
+#else  /* !__APPLE__ */
        if (argc < 2)
                usage();
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+       if (!(acloptflags & ACL_FLAG) && ((acloptlen = strlen(argv[0])) > 1) && (argv[0][1] == 'a')) {
+               acloptflags |= ACL_FLAG;
+               switch (argv[0][0]) {
+               case '+':
+                       acloptflags |= ACL_SET_FLAG;
+                       break;
+               case '-':
+                       acloptflags |= ACL_DELETE_FLAG;
+                       break;
+               case '=':
+                       acloptflags |= ACL_REWRITE_FLAG;
+                       break;
+               default:
+                       acloptflags &= ~ACL_FLAG;
+                       goto apnoacl;
+               }
+               
+               if (argc < 3)
+                       usage();
+
+               if (acloptlen > 2) {
+                       for (index = 2; index < acloptlen; index++) {
+                               switch (argv[0][index]) {
+                               case '#':
+                                       acloptflags |= ACL_ORDER_FLAG;
+
+                                       if (argc < ((acloptflags & ACL_DELETE_FLAG)
+                                                   ? 3 : 4))
+                                               usage();
+                                       argv++;
+                                       argc--;
+                                       errno = 0;
+                                       aclpos = strtol(argv[0], &ep, 0);
+
+                                       if (aclpos > ACL_MAX_ENTRIES
+                                           || aclpos < 0)
+                                               errno = ERANGE;
+                                       if (errno || *ep)
+                                               errx(1, "Invalid ACL entry number: %ld", aclpos);
+                                       if (acloptflags & ACL_DELETE_FLAG)
+                                               ace_arg_not_required = 1;
+
+                                       goto apdone;
+                               case 'i':
+                                       acloptflags |= ACL_INHERIT_FLAG;
+                                       /* The +aii.. syntax to specify
+                                        * inheritance level is rather unwieldy,
+                                        * find an alternative.
+                                        */
+                                       inheritance_level++;
+                                       if (inheritance_level > 1)
+                                               warnx("Inheritance across more than one generation is not currently supported");
+                                       if (inheritance_level >= MAX_INHERITANCE_LEVEL)
+                                               goto apdone;
+                                       break;
+                               default:
+                                       errno = EINVAL;
+                                       usage();
+                               }
+                       }
+               }
+apdone:
+               argv++;
+               argc--;
+       }
+apnoacl:
+#endif /*__APPLE__*/
 
        if (Rflag) {
                fts_options = FTS_PHYSICAL;
@@ -153,47 +286,94 @@ done:     argv += optind;
        } else
                fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
 
-#ifndef __APPLE__
        if (hflag)
                change_mode = lchmod;
        else
                change_mode = chmod;
-#else
-       change_mode = chmod;
-#endif /* __APPLE__ */
-
-       mode = *argv;
-       if (*mode >= '0' && *mode <= '7') {
-               errno = 0;
-               val = strtol(mode, &ep, 8);
-               if (val > USHRT_MAX || val < 0)
-                       errno = ERANGE;
-               if (errno)
-                       err(1, "invalid file mode: %s", mode);
-               if (*ep)
-                       errx(1, "invalid file mode: %s", mode);
-               omode = (mode_t)val;
-               oct = 1;
-       } else {
-               if ((set = setmode(mode)) == NULL)
-                       errx(1, "invalid file mode: %s", mode);
-               oct = 0;
+#ifdef __APPLE__
+       if (acloptflags & ACL_FROM_STDIN) {
+               ssize_t readval = 0;
+               size_t readtotal = 0;
+               
+               mode = (char *) malloc(MAX_ACL_TEXT_SIZE);
+               
+               if (mode == NULL)
+                       err(1, "Unable to allocate mode string");
+               /* Read the ACEs from STDIN */
+               do {
+                       readtotal += readval;
+                       readval = read(STDIN_FILENO, mode + readtotal, 
+                                      MAX_ACL_TEXT_SIZE);
+               } while ((readval > 0) && (readtotal <= MAX_ACL_TEXT_SIZE));
+                       
+               if (0 == readtotal)
+                       errx(1, "-E specified, but read from STDIN failed");
+               else
+                       mode[readtotal - 1] = '\0';
+               --argv;
        }
+       else
+#endif /* __APPLE */
+               mode = *argv;
+
+#ifdef __APPLE__
+       if ((acloptflags & ACL_FLAG)) {
 
+               /* Are we deleting by entry number, verifying
+                * canonicity or performing some other operation that
+                * does not require an input entry? If so, there's no
+                * entry to convert.
+                */
+               if (ace_arg_not_required) {
+                       --argv;
+               }
+               else {
+                        /* Parse the text into an ACL*/
+                       acl_input = parse_acl_entries(mode);
+                       if (acl_input == NULL) {
+                               errx(1, "Invalid ACL specification: %s", mode);
+                       }
+               }
+       }
+       else {
+#endif /* __APPLE__*/
+               if (*mode >= '0' && *mode <= '7') {
+                       errno = 0;
+                       val = strtol(mode, &ep, 8);
+                       if (val > USHRT_MAX || val < 0)
+                               errno = ERANGE;
+                       if (errno)
+                               err(1, "Invalid file mode: %s", mode);
+                       if (*ep)
+                               errx(1, "Invalid file mode: %s", mode);
+                       omode = (mode_t)val;
+                       oct = 1;
+               } else {
+                       if ((set = setmode(mode)) == NULL)
+                               errx(1, "Invalid file mode: %s", mode);
+                       oct = 0;
+               }
+#ifdef __APPLE__
+       }
+#endif /* __APPLE__*/
        if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
                err(1, "fts_open");
        for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
                switch (p->fts_info) {
-               case FTS_D:                     /* Change it at FTS_DP. */
+               case FTS_D:
                        if (!Rflag)
-                               fts_set(ftsp, p, FTS_SKIP);
-                       continue;
+                               (void)fts_set(ftsp, p, FTS_SKIP);
+                       break;
                case FTS_DNR:                   /* Warn, chmod, continue. */
                        warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
                        rval = 1;
                        break;
-               case FTS_ERR:                   /* Warn, continue. */
+               case FTS_DP:                    /* Already changed at FTS_D. */
+                       continue;
                case FTS_NS:
+                       if (acloptflags & ACL_FLAG) /* don't need stat for -N */
+                               break;
+               case FTS_ERR:                   /* Warn, continue. */
                        warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
                        rval = 1;
                        continue;
@@ -211,36 +391,55 @@ done:     argv += optind;
                default:
                        break;
                }
-               newmode = oct ? omode : getmode(set, p->fts_statp->st_mode);
-               if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
-                       continue;
-               if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
-                       warn("%s", p->fts_path);
-                       rval = 1;
-               } else {
-                       if (vflag) {
-                               (void)printf("%s", p->fts_accpath);
-
-                               if (vflag > 1) {
-                                       char m1[12], m2[12];
-
-                                       strmode(p->fts_statp->st_mode, m1);
-                                       strmode((p->fts_statp->st_mode &
-                                           S_IFMT) | newmode, m2);
+#ifdef __APPLE__
+/* If an ACL manipulation option was specified, manipulate */
+               if (acloptflags & ACL_FLAG)     {
+                       if (0 != modify_file_acl(acloptflags, p->fts_accpath, acl_input, (int)aclpos, inheritance_level, !hflag))
+                               rval = 1;
+               }
+               else {
+#endif /* __APPLE__ */
+                       newmode = oct ? omode : getmode(set, p->fts_statp->st_mode);
+                       if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
+                               continue;
+                       if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
+                               warn("Unable to change file mode on %s", p->fts_path);
+                               rval = 1;
+                       } else {
+                               if (vflag) {
+                                       (void)printf("%s", p->fts_accpath);
 
-                                       (void)printf(": 0%o [%s] -> 0%o [%s]",
-                                           p->fts_statp->st_mode, m1,
+                                       if (vflag > 1) {
+                                               char m1[12], m2[12];
+                                               
+                                               strmode(p->fts_statp->st_mode, m1);
+                                               strmode((p->fts_statp->st_mode &
+                                                        S_IFMT) | newmode, m2);
+                                               
+                                               (void)printf(": 0%o [%s] -> 0%o [%s]",
+                                                            p->fts_statp->st_mode, m1,
                                            (p->fts_statp->st_mode & S_IFMT) |
-                                           newmode, m2);
+                                                            newmode, m2);
+                                       }
+                                       (void)printf("\n");
                                }
-                               (void)printf("\n");
+                               
                        }
-
+#ifdef __APPLE__
                }
+#endif /* __APPLE__*/
        }
        if (errno)
                err(1, "fts_read");
-       free(set);
+#ifdef __APPLE__
+       if (acl_input)
+               acl_free(acl_input);
+       if (mode && (acloptflags & ACL_FROM_STDIN))
+               free(mode);
+       
+#endif /* __APPLE__ */
+       if (set)
+               free(set);
        exit(rval);
 }
 
@@ -249,7 +448,8 @@ usage(void)
 {
 #ifdef __APPLE__
        (void)fprintf(stderr,
-           "usage: chmod [-fv] [-R [-H | -L | -P]] mode file ...\n");
+                     "usage:\tchmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a  [i][# [ n]]] mode|entry file ...\n"
+                     "\tchmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -N | -i | -I] file ...\n"); /* add -A and -V when implemented */
 #else
        (void)fprintf(stderr,
            "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n");