]> git.saurik.com Git - apple/file_cmds.git/blobdiff - chmod/chmod.c
file_cmds-220.7.tar.gz
[apple/file_cmds.git] / chmod / chmod.c
index 4dae785bb260e19b18a3f238df44737610ba2863..a4ab0357b9fc5cf7ad7de42c006b4f1a6e172c12 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $       */
-
 /*
  * Copyright (c) 1989, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
-__COPYRIGHT(
+static char const copyright[] =
 "@(#) Copyright (c) 1989, 1993, 1994\n\
-       The Regents of the University of California.  All rights reserved.\n");
+       The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)chmod.c    8.8 (Berkeley) 4/1/94";
-#else
-__RCSID("$NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $");
 #endif
 #endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/chmod/chmod.c,v 1.27 2002/08/04 05:29:13 obrien Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -54,68 +51,124 @@ __RCSID("$NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $");
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
-#include <locale.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <limits.h>
 
-int main __P((int, char *[]));
-void usage __P((void));
+#ifdef __APPLE__
+#include "chmod_acl.h"
+
+#endif /*__APPLE__*/
+
+int fflag = 0;
+
+int main(int, char *[]);
+void usage(void);
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char *argv[])
 {
-       FTS *ftsp;
-       FTSENT *p;
-       mode_t *set;
-       long val;
-       int oct, omode;
-       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;
-       int (*change_mode) __P((const char *, mode_t));
+       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;     /* XXX gcc -Wuninitialized */
-       omode = 0;      /* XXX gcc -Wuninitialized */
-
-       (void)setlocale(LC_ALL, "");
-
-       Hflag = Lflag = Rflag = fflag = hflag = 0;
-       while ((ch = getopt(argc, argv, "HLPRXfghorstuwx")) != -1)
+       set = NULL;
+       omode = 0;
+       Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0;
+#ifndef __APPLE__
+       while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
+#else
+       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;
                        break;
-               case 'f':               /* XXX: undocumented. */
+               case 'f':
                        fflag = 1;
                        break;
-#ifndef __APPLE__
                case 'h':
                        /*
                         * In System V (and probably POSIX.2) the -h option
                         * causes chmod to change the mode of the symbolic
                         * link.  4.4BSD's symbolic links didn't have modes,
-                        * so it was an undocumented noop.  In NetBSD 1.3,
+                        * so it was an undocumented noop.  In FreeBSD 3.0,
                         * lchmod(2) is introduced and this option does real
                         * work.
                         */
                        hflag = 1;
                        break;
-#endif
+#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
                 * "-[rwx]" are valid mode commands.  If they are the entire
@@ -129,6 +182,9 @@ main(argc, argv)
                            argv[optind - 1][2] == '\0')
                                --optind;
                        goto done;
+               case 'v':
+                       vflag++;
+                       break;
                case '?':
                default:
                        usage();
@@ -136,11 +192,87 @@ main(argc, 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__*/
 
-       fts_options = FTS_PHYSICAL;
        if (Rflag) {
+               fts_options = FTS_PHYSICAL;
                if (hflag)
                        errx(1,
                "the -R and -h options may not be specified together.");
@@ -150,36 +282,81 @@ done:     argv += optind;
                        fts_options &= ~FTS_PHYSICAL;
                        fts_options |= FTS_LOGICAL;
                }
-       }
-#ifndef __APPLE__
+       } else
+               fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+
        if (hflag)
                change_mode = lchmod;
        else
-            change_mode = chmod;
-#else
-        change_mode = chmod;
-#endif
-
-       mode = *argv;
-       if (*mode >= '0' && *mode <= '7') {
-               errno = 0;
-               val = strtol(mode, &ep, 8);
-               if (val > INT_MAX || val < 0)
-                       errno = ERANGE;
-               if (errno)
-                       err(1, "invalid file mode: %s", mode);
-               if (*ep)
-                       errx(1, "invalid file mode: %s", mode);
-               omode = val;
-               oct = 1;
-       } else {
-               if ((set = setmode(mode)) == NULL)
-                       errx(1, "invalid file mode: %s", mode);
-               oct = 0;
+               change_mode = chmod;
+#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, argv[0]);
+               err(1, "fts_open");
        for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
                switch (p->fts_info) {
                case FTS_D:
@@ -192,8 +369,10 @@ done:      argv += optind;
                        break;
                case FTS_DP:                    /* Already changed at FTS_D. */
                        continue;
-               case FTS_ERR:                   /* Warn, 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;
@@ -204,39 +383,75 @@ done:     argv += optind;
                         * don't point to anything and ones that we found
                         * doing a physical walk.
                         */
-#ifndef __APPLE__
                        if (!hflag)
                                continue;
                        /* else */
                        /* FALLTHROUGH */
-#else
-                       continue;
-#endif
                default:
                        break;
                }
-               if ((*change_mode)(p->fts_accpath, oct ? omode :
-                   getmode(set, p->fts_statp->st_mode)) && !fflag) {
-                       warn("%s", p->fts_path);
-                       rval = 1;
+#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);
+
+                                       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);
+                                       }
+                                       (void)printf("\n");
+                               }
+                               
+                       }
+#ifdef __APPLE__
                }
+#endif /* __APPLE__*/
        }
        if (errno)
                err(1, "fts_read");
+#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);
-       /* NOTREACHED */
 }
 
 void
-usage()
+usage(void)
 {
-#ifndef __APPLE__
+#ifdef __APPLE__
        (void)fprintf(stderr,
-           "usage: chmod [-R [-H | -L | -P]] [-h] 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 [-R [-H | -L | -P]] mode file ...\n");
-#endif
+           "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n");
+#endif /* __APPLE__ */
        exit(1);
-       /* NOTREACHED */
 }