BSD 4_3_Net_2 release
[unix-history] / usr / src / bin / chmod / chmod.c
index 4435269..99e08bb 100644 (file)
-static char *sccsid = "@(#)chmod.c     4.5 %G%";
-
 /*
 /*
- * chmod options mode files
- * where
- *     mode    is [ugoa][+-=][rwxXstugo] or a octal number
- *     options are -R
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
  */
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/dir.h>
-
-#define        USER    05700   /* user's bits */
-#define        GROUP   02070   /* group's bits */
-#define        OTHER   00007   /* other's bits */
-#define        ALL     01777   /* all (note absence of setuid, etc) */
 
 
-#define        READ    00444   /* read permit */
-#define        WRITE   00222   /* write permit */
-#define        EXEC    00111   /* exec permit */
-#define        SETID   06000   /* set[ug]id */
-#define        STICKY  01000   /* sticky bit */
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
 
 
-char   *modestring, *ms;
-int    um;
-int    status;
-int    rflag, debug;
+#ifndef lint
+static char sccsid[] = "@(#)chmod.c    5.19 (Berkeley) 3/12/91";
+#endif /* not lint */
 
 
-main(argc,argv)
-char **argv;
-{
-       register i;
-       register char *p, *flags;
-       struct  stat st;
-
-usage:
-       if (argc < 3) {
-               fprintf(stderr
-                       ,"Usage: chmod [-R] [ugoa][+-=][rwxXstugo] file ...\n");
-               exit(-1);
-       }
-
-       argv++, --argc;
-       if (*argv[0] == '-') {
-               for (flags = argv[0]; *flags; ++flags)
-                       switch (*flags) {
-                         case '-':                     break;
-                         case 'R':     rflag++;        break;
-                         default:      argc = 0;       goto usage;
-                       }
-               argv++, argc--;
-       }
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <stdio.h>
+#include <string.h>
 
 
-       modestring = argv[0];
+extern int errno;
+int retval;
 
 
-       um = umask(0);
-       (void) newmode(0);
-       for (i = 1; i < argc; i++) {
-               p = argv[i];
-               if (stat(p, &st) < 0) {
-                       fprintf(stderr, "chmod: can't access %s\n", p);
-                       ++status;
-                       continue;
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int optind;
+       register FTS *fts;
+       register FTSENT *p;
+       register int oct, omode;
+       register char *mode;
+       mode_t *set, *setmode();
+       struct stat sb;
+       int ch, fflag, rflag;
+
+       fflag = rflag = 0;
+       while ((ch = getopt(argc, argv, "Rfrwx")) != EOF)
+               switch((char)ch) {
+               case 'R':
+                       rflag = 1;
+                       break;
+               case 'f':               /* no longer documented */
+                       fflag = 1;
+                       break;
+               case 'r':               /* "-[rwx]" are valid file modes */
+               case 'w':
+               case 'x':
+                       --optind;
+                       goto done;
+               case '?':
+               default:
+                       usage();
                }
                }
-               if (rflag && st.st_mode & S_IFDIR) {
-                       status += chmodr(p, newmode(st.st_mode));
-               } else if (chmod(p, newmode(st.st_mode)) < 0) {
-                       fprintf(stderr, "chmod: can't change %s\n", p);
-                       ++status;
-                       continue;
+done:  argv += optind;
+       argc -= optind;
+
+       if (argc < 2)
+               usage();
+
+       mode = *argv;
+       if (*mode >= '0' && *mode <= '7') {
+               omode = (int)strtol(mode, (char **)NULL, 8);
+               oct = 1;
+       } else {
+               if (!(set = setmode(mode))) {
+                       (void)fprintf(stderr, "chmod: invalid file mode.\n");
+                       exit(1);
                }
                }
-       }
-       exit(status);
-}
-
-chmodr(dir, mode)
-       char    *dir;
-{
-       register DIR            *dirp;
-       register struct direct  *dp;
-       register struct stat    st;
-       char                    savedir[1024];
-
-       if (getwd(savedir) == 0) {
-               fprintf(stderr, "chmod: %s\n", savedir);
-               exit(255);
+               oct = 0;
        }
 
        }
 
-       /*
-       ** chmod what we are given before doing it's contents
-       */
-       chmod(dir, newmode(mode));
-       
-       chdir(dir);
-       if ((dirp = opendir(".")) == NULL) {
-               perror(dir);
-               return(1);
-       }
-       dp = readdir(dirp);
-       dp = readdir(dirp); /* read "." and ".." */
-       for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
-               if (stat(dp->d_name, &st) < 0) {
-                       fprintf(stderr, "chmod: can't access %s\n", dp->d_name);
-                       return(1);
+       retval = 0;
+       if (rflag) {
+               if (!(fts = fts_open(++argv,
+                   oct ? FTS_NOSTAT|FTS_PHYSICAL : FTS_PHYSICAL, 0))) {
+                       (void)fprintf(stderr, "chmod: %s.\n", strerror(errno));
+                       exit(1);
                }
                }
-               chmod(dp->d_name, newmode(st.st_mode));
-               if (st.st_mode & S_IFDIR)
-                       chmodr(dp->d_name, mode);
-       }
-       closedir(dirp);
-       chdir(savedir);
-       return(0);
-}
-
-newmode(nm)
-unsigned nm;
-{
-       register o, m, b;
-       int savem;
-
-       ms = modestring;
-       savem = nm;
-       m = abs();
-       if (!*ms)
-               return(m);
-       do {
-               m = who();
-               while (o = what()) {
-                       b = where(nm);
-                       switch (o) {
-                       case '+':
-                               nm |= b & m;
-                               break;
-                       case '-':
-                               nm &= ~(b & m);
+               while (p = fts_read(fts))
+                       switch(p->fts_info) {
+                       case FTS_D:
                                break;
                                break;
-                       case '=':
-                               nm &= ~m;
-                               nm |= b & m;
+                       case FTS_DNR:
+                       case FTS_ERR:
+                       case FTS_NS:
+                               (void)fprintf(stderr, "chmod: %s: %s.\n",
+                                   p->fts_path, strerror(errno));
+                               exit(1);
+                       default:
+                               if (chmod(p->fts_accpath, oct ? omode :
+                                   getmode(set, p->fts_statb.st_mode)) &&
+                                   !fflag)
+                                       error(p->fts_path);
                                break;
                        }
                                break;
                        }
-               }
-       } while (*ms++ == ',');
-       if (*--ms) {
-               fprintf(stderr, "chmod: invalid mode\n");
-               exit(255);
+               exit(retval);
        }
        }
-       return(nm);
+       if (oct) {
+               while (*++argv)
+                       if (chmod(*argv, omode) && !fflag)
+                               error(*argv);
+       } else
+               while (*++argv)
+                       if ((lstat(*argv, &sb) ||
+                           chmod(*argv, getmode(set, sb.st_mode))) && !fflag)
+                               error(*argv);
+       exit(retval);
 }
 
 }
 
-abs()
+error(name)
+       char *name;
 {
 {
-       register c, i;
-
-       i = 0;
-       while ((c = *ms++) >= '0' && c <= '7')
-               i = (i << 3) + (c - '0');
-       ms--;
-       return(i);
+       (void)fprintf(stderr, "chmod: %s: %s.\n", name, strerror(errno));
+       retval = 1;
 }
 
 }
 
-who()
+usage()
 {
 {
-       register m;
-
-       m = 0;
-       for (;;) switch (*ms++) {
-       case 'u':
-               m |= USER;
-               continue;
-       case 'g':
-               m |= GROUP;
-               continue;
-       case 'o':
-               m |= OTHER;
-               continue;
-       case 'a':
-               m |= ALL;
-               continue;
-       default:
-               ms--;
-               if (m == 0)
-                       m = ALL & ~um;
-               return m;
-       }
-}
-
-what()
-{
-
-       switch (*ms) {
-       case '+':
-       case '-':
-       case '=':
-               return *ms++;
-       }
-       return(0);
-}
-
-where(om)
-register om;
-{
-       register m;
-
-       m = 0;
-       switch (*ms) {
-       case 'u':
-               m = (om & USER) >> 6;
-               goto dup;
-       case 'g':
-               m = (om & GROUP) >> 3;
-               goto dup;
-       case 'o':
-               m = (om & OTHER);
-       dup:
-               m &= (READ|WRITE|EXEC);
-               m |= (m << 3) | (m << 6);
-               ++ms;
-               return m;
-       }
-       for (;;) switch (*ms++) {
-       case 'r':
-               m |= READ;
-               continue;
-       case 'w':
-               m |= WRITE;
-               continue;
-       case 'x':
-               m |= EXEC;
-               continue;
-       case 'X':
-               if ((om & S_IFDIR) || (om & EXEC))
-                       m |= EXEC;
-               continue;
-       case 's':
-               m |= SETID;
-               continue;
-       case 't':
-               m |= STICKY;
-               continue;
-       default:
-               ms--;
-               return m;
-       }
+       (void)fprintf(stderr, "chmod: chmod [-R] mode file ...\n");
+       exit(1);
 }
 }