BSD 4_3_Net_2 release
[unix-history] / usr / src / bin / chmod / chmod.c
index a4aba03..99e08bb 100644 (file)
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * 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.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)chmod.c    5.4 (Berkeley) %G%";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chmod.c    5.19 (Berkeley) 3/12/91";
+#endif /* not lint */
 
 
-/*
- * chmod options mode files
- * where
- *     mode is [ugoa][+-=][rwxXstugo] or an octal number
- *     options are -Rf
- */
-#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/dir.h>
+#include <fts.h>
+#include <stdio.h>
+#include <string.h>
 
 
-char   *modestring, *ms;
-int    um;
-int    status;
-int    fflag;
-int    rflag;
+extern int errno;
+int retval;
 
 main(argc, argv)
 
 main(argc, argv)
-       char *argv[];
+       int argc;
+       char **argv;
 {
 {
-       register char *p, *flags;
-       register int i;
-       struct stat st;
-
-       if (argc < 3) {
-               fprintf(stderr,
-                   "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n");
-               exit(-1);
-       }
-       argv++, --argc;
-       while (argc > 0 && argv[0][0] == '-') {
-               for (p = &argv[0][1]; *p; p++) switch (*p) {
-
+       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':
                case 'R':
-                       rflag++;
+                       rflag = 1;
                        break;
                        break;
-
-               case 'f':
-                       fflag++;
+               case 'f':               /* no longer documented */
+                       fflag = 1;
                        break;
                        break;
-
-               default:
+               case 'r':               /* "-[rwx]" are valid file modes */
+               case 'w':
+               case 'x':
+                       --optind;
                        goto done;
                        goto done;
+               case '?':
+               default:
+                       usage();
                }
                }
-               argc--, argv++;
-       }
-done:
-       modestring = argv[0];
-       um = umask(0);
-       (void) newmode(0);
-       for (i = 1; i < argc; i++) {
-               p = argv[i];
-               /* do stat for directory arguments */
-               if (stat(p, &st) < 0) {
-                       status += error("can't access %s", p);
-                       continue;
-               }
-               if (rflag && st.st_mode&S_IFDIR) {
-                       status += chmodr(p, newmode(st.st_mode));
-                       continue;
-               }
-               if (chmod(p, newmode(st.st_mode)) < 0) {
-                       status += error("can't change %s", p);
-                       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);
                }
                }
+               oct = 0;
        }
        }
-       exit(status);
-}
-
-chmodr(dir, mode)
-       char *dir;
-{
-       register DIR *dirp;
-       register struct direct *dp;
-       register struct stat st;
-       char savedir[1024];
-       int ecode;
 
 
-       if (getwd(savedir) == 0)
-               fatal(255, "%s", savedir);
-       /*
-        * Change what we are given before doing it's contents
-        */
-       if (chmod(dir, newmode(mode)) < 0 && error("can't change %s", dir))
-               return (1);
-       if (chdir(dir) < 0)
-               return (Perror(dir));
-       if ((dirp = opendir(".")) == NULL)
-               return (Perror(dir));
-       dp = readdir(dirp);
-       dp = readdir(dirp); /* read "." and ".." */
-       ecode = 0;
-       for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
-               if (lstat(dp->d_name, &st) < 0) {
-                       ecode = error("can't access %s", dp->d_name);
-                       if (ecode)
-                               break;
-                       continue;
-               }
-               if (st.st_mode&S_IFDIR) {
-                       ecode = chmodr(dp->d_name, newmode(st.st_mode));
-                       if (ecode)
-                               break;
-                       continue;
+       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);
                }
                }
-               if (chmod(dp->d_name, newmode(st.st_mode)) < 0 &&
-                   (ecode = error("can't change %s", dp->d_name)))
-                       break;
-       }
-       closedir(dirp);
-       if (chdir(savedir) < 0)
-               fatal(255, "can't change back to %s", savedir);
-       return (ecode);
-}
-
-error(fmt, a)
-       char *fmt, *a;
-{
-
-       if (!fflag) {
-               fprintf(stderr, "chmod: ");
-               fprintf(stderr, fmt, a);
-               putc('\n', stderr);
-       }
-       return (!fflag);
-}
-
-fatal(status, fmt, a)
-       int status;
-       char *fmt, *a;
-{
-
-       fflag = 0;
-       (void) error(fmt, a);
-       exit(status);
-}
-
-Perror(s)
-       char *s;
-{
-
-       fprintf(stderr, "chmod: ");
-       perror(s);
-       return (1);
-}
-
-newmode(nm)
-       unsigned nm;
-{
-       register o, m, b;
-       int savem;
-
-       ms = modestring;
-       savem = nm;
-       m = abs();
-       if (*ms == '\0')
-               return (m);
-       do {
-               m = who();
-               while (o = what()) {
-                       b = where(nm);
-                       switch (o) {
-                       case '+':
-                               nm |= b & m;
+               while (p = fts_read(fts))
+                       switch(p->fts_info) {
+                       case FTS_D:
                                break;
                                break;
-                       case '-':
-                               nm &= ~(b & m);
-                               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)
-               fatal(255, "invalid mode");
-       return (nm);
-}
-
-abs()
-{
-       register c, i;
-
-       i = 0;
-       while ((c = *ms++) >= '0' && c <= '7')
-               i = (i << 3) + (c - '0');
-       ms--;
-       return (i);
-}
-
-#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 */
-
-who()
-{
-       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);
+               exit(retval);
        }
        }
+       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);
 }
 
 }
 
-what()
+error(name)
+       char *name;
 {
 {
-
-       switch (*ms) {
-       case '+':
-       case '-':
-       case '=':
-               return (*ms++);
-       }
-       return (0);
+       (void)fprintf(stderr, "chmod: %s: %s.\n", name, strerror(errno));
+       retval = 1;
 }
 
 }
 
-where(om)
-       register om;
+usage()
 {
 {
-       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);
 }
 }