BSD 4_3_Tahoe release
[unix-history] / usr / src / bin / chmod.c
index 6782de9..09c7e8a 100644 (file)
-static char *sccsid = "@(#)chmod.c     4.1 (Berkeley) 10/1/80";
 /*
 /*
- * chmod [ugoa][+-=][rwxstugo] files
- *  change mode of files
+ * Copyright (c) 1980, 1988 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chmod.c    5.7 (Berkeley) 4/21/88";
+#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 <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) */
+static int     fflag, rflag, retval, um;
+static char    *modestring, *ms;
 
 
-#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 */
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern char *optarg;
+       extern int optind, opterr;
+       int ch;
+
+       /*
+        * since "-[rwx]" etc. are valid file modes, we don't let getopt(3)
+        * print error messages, and we mess around with optind as necessary.
+        */
+       opterr = 0;
+       while ((ch = getopt(argc, argv, "Rf")) != EOF)
+               switch((char)ch) {
+               case 'R':
+                       rflag++;
+                       break;
+               case 'f':
+                       fflag++;
+                       break;
+               case '?':
+               default:
+                       --optind;
+                       goto done;
+               }
+done:  argv += optind;
+       argc -= optind;
+
+       if (argc < 2) {
+               fputs("usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n",
+                   stderr);
+               exit(-1);
+       }
+
+       modestring = *argv;
+       um = umask(0);
+       (void)newmode((u_short)0);
 
 
-char   *ms;
-int    um;
-struct stat st;
+       while (*++argv)
+               change(*argv);
+       exit(retval);
+}
 
 
-main(argc,argv)
-char **argv;
+change(file)
+       char *file;
 {
 {
-       register i;
-       register char *p;
-       int status = 0;
+       register DIR *dirp;
+       register struct direct *dp;
+       struct stat buf;
 
 
-       if (argc < 3) {
-               fprintf(stderr, "Usage: chmod [ugoa][+-=][rwxstugo] file ...\n");
-               exit(255);
+       if (lstat(file, &buf) || chmod(file, newmode(buf.st_mode))) {
+               err(file);
+               return;
        }
        }
-       ms = argv[1];
-       um = umask(0);
-       newmode(0);
-       for (i = 2; i < argc; i++) {
-               p = argv[i];
-               if (stat(p, &st) < 0) {
-                       fprintf(stderr, "chmod: can't access %s\n", p);
-                       ++status;
-                       continue;
+       if (rflag && ((buf.st_mode & S_IFMT) == S_IFDIR)) {
+               if (chdir(file) < 0 || !(dirp = opendir("."))) {
+                       err(file);
+                       return;
                }
                }
-               ms = argv[1];
-               if (chmod(p, newmode(st.st_mode)) < 0) {
-                       fprintf(stderr, "chmod: can't change %s\n", p);
-                       ++status;
-                       continue;
+               for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
+                       if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
+                           dp->d_name[1] == '.' && !dp->d_name[2]))
+                               continue;
+                       change(dp->d_name);
+               }
+               closedir(dirp);
+               if (chdir("..")) {
+                       err("..");
+                       exit(fflag ? 0 : -1);
                }
        }
                }
        }
-       exit(status);
+}
+
+err(s)
+       char *s;
+{
+       if (fflag)
+               return;
+       fputs("chmod: ", stderr);
+       perror(s);
+       retval = -1;
 }
 
 newmode(nm)
 }
 
 newmode(nm)
-unsigned nm;
+       u_short nm;
 {
 {
-       register o, m, b;
+       register int o, m, b;
 
 
+       ms = modestring;
        m = abs();
        m = abs();
-       if (!*ms)
-               return(m);
+       if (*ms == '\0')
+               return (m);
        do {
                m = who();
                while (o = what()) {
        do {
                m = who();
                while (o = what()) {
-                       b = where(nm);
+                       b = where((int)nm);
                        switch (o) {
                        case '+':
                                nm |= b & m;
                        switch (o) {
                        case '+':
                                nm |= b & m;
@@ -80,26 +140,37 @@ unsigned nm;
                }
        } while (*ms++ == ',');
        if (*--ms) {
                }
        } while (*ms++ == ',');
        if (*--ms) {
-               fprintf(stderr, "chmod: invalid mode\n");
-               exit(255);
+               fputs("chmod: invalid mode.\n", stderr);
+               exit(-1);
        }
        }
-       return(nm);
+       return ((int)nm);
 }
 
 abs()
 {
 }
 
 abs()
 {
-       register c, i;
+       register int c, i;
 
        i = 0;
        while ((c = *ms++) >= '0' && c <= '7')
                i = (i << 3) + (c - '0');
        ms--;
 
        i = 0;
        while ((c = *ms++) >= '0' && c <= '7')
                i = (i << 3) + (c - '0');
        ms--;
-       return(i);
+       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()
 {
 who()
 {
-       register m;
+       register int m;
 
        m = 0;
        for (;;) switch (*ms++) {
 
        m = 0;
        for (;;) switch (*ms++) {
@@ -119,7 +190,7 @@ who()
                ms--;
                if (m == 0)
                        m = ALL & ~um;
                ms--;
                if (m == 0)
                        m = ALL & ~um;
-               return m;
+               return (m);
        }
 }
 
        }
 }
 
@@ -129,17 +200,17 @@ what()
        case '+':
        case '-':
        case '=':
        case '+':
        case '-':
        case '=':
-               return *ms++;
+               return (*ms++);
        }
        }
-       return(0);
+       return (0);
 }
 
 where(om)
 }
 
 where(om)
-register om;
+       register int om;
 {
 {
-       register m;
+       register int m;
 
 
-       m = 0;
+       m = 0;
        switch (*ms) {
        case 'u':
                m = (om & USER) >> 6;
        switch (*ms) {
        case 'u':
                m = (om & USER) >> 6;
@@ -153,7 +224,7 @@ register om;
                m &= (READ|WRITE|EXEC);
                m |= (m << 3) | (m << 6);
                ++ms;
                m &= (READ|WRITE|EXEC);
                m |= (m << 3) | (m << 6);
                ++ms;
-               return m;
+               return (m);
        }
        for (;;) switch (*ms++) {
        case 'r':
        }
        for (;;) switch (*ms++) {
        case 'r':
@@ -165,6 +236,10 @@ register om;
        case 'x':
                m |= EXEC;
                continue;
        case 'x':
                m |= EXEC;
                continue;
+       case 'X':
+               if ((om & S_IFDIR) || (om & EXEC))
+                       m |= EXEC;
+               continue;
        case 's':
                m |= SETID;
                continue;
        case 's':
                m |= SETID;
                continue;
@@ -173,6 +248,6 @@ register om;
                continue;
        default:
                ms--;
                continue;
        default:
                ms--;
-               return m;
+               return (m);
        }
 }
        }
 }