BSD 4_4 release
[unix-history] / usr / src / usr.sbin / chown / chown.c
index a241495..298211b 100644 (file)
@@ -1,40 +1,58 @@
 /*
 /*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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
-char copyright[] =
-"@(#) Copyright (c) 1988 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)chown.c    5.15 (Berkeley) 6/1/90";
+static char sccsid[] = "@(#)chown.c    8.1 (Berkeley) 6/6/93";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/errno.h>
 #include <dirent.h>
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/errno.h>
 #include <dirent.h>
+#include <fts.h>
 #include <pwd.h>
 #include <grp.h>
 #include <pwd.h>
 #include <grp.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
 
 int ischown, uid, gid, fflag, rflag, retval;
 char *gname, *myname;
 
 int ischown, uid, gid, fflag, rflag, retval;
 char *gname, *myname;
@@ -43,22 +61,35 @@ main(argc, argv)
        int argc;
        char **argv;
 {
        int argc;
        char **argv;
 {
-       extern char *optarg;
        extern int optind;
        extern int optind;
+       register FTS *ftsp;
+       register FTSENT *p;
        register char *cp;
        int ch;
        register char *cp;
        int ch;
-       char curpath[MAXPATHLEN], *reset, *index(), *rindex();
-
+       int fts_options;
+       int hflag, Hflag;
+       
        myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
        ischown = myname[2] == 'o';
        myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
        ischown = myname[2] == 'o';
-
-       while ((ch = getopt(argc, argv, "Rf")) != EOF)
+       
+       hflag = Hflag = 0;
+       fts_options = FTS_NOSTAT | FTS_PHYSICAL;
+       while ((ch = getopt(argc, argv, "HRfh")) != EOF)
                switch((char)ch) {
                case 'R':
                switch((char)ch) {
                case 'R':
-                       rflag++;
+                       rflag = 1;
                        break;
                case 'f':
                        break;
                case 'f':
-                       fflag++;
+                       fflag = 1;
+                       break;
+               case 'h':
+                       hflag = 1;
+                       fts_options &= ~FTS_PHYSICAL;
+                       fts_options |= FTS_LOGICAL;
+                       break;
+               case 'H':
+                       Hflag = 1;
+                       fts_options |= FTS_COMFOLLOW;
                        break;
                case '?':
                default:
                        break;
                case '?':
                default:
@@ -70,115 +101,92 @@ main(argc, argv)
        if (argc < 2)
                usage();
 
        if (argc < 2)
                usage();
 
+       uid = gid = -1;
        if (ischown) {
        if (ischown) {
+#ifdef SUPPORT_DOT
                if (cp = index(*argv, '.')) {
                        *cp++ = '\0';
                if (cp = index(*argv, '.')) {
                        *cp++ = '\0';
-                       setgid(cp);
-               }
-               else
-                       gid = -1;
-               setuid(*argv);
-       }
-       else {
-               uid = -1;
-               setgid(*argv);
+                       a_gid(cp);
+               } else
+#endif
+               if (cp = index(*argv, ':')) {
+                       *cp++ = '\0';
+                       a_gid(cp);
+               } 
+               a_uid(*argv);
        }
        }
+       else 
+               a_gid(*argv);
 
 
-       while (*++argv) {
-               if (reset = index(*argv, '/'))
-                       (void)getwd(curpath);
-               change(*argv);
-               if (reset && chdir(curpath)) {
-                       if (fflag)
-                               exit(0);
-                       err(curpath);
-                       exit(-1);
+       if (!(ftsp = fts_open(++argv, fts_options, 0))) {
+               (void)fprintf(stderr,
+                   "%s: %s.\n", myname, strerror(errno));
+               exit(1);
+       }
+       while (p = fts_read(ftsp)) {
+               if (p->fts_info == FTS_D) {
+                       if (rflag)
+                               continue;
+                       else
+                               fts_set(ftsp, p, FTS_SKIP);
                }
                }
+               if (p->fts_info == FTS_SL &&
+                   !(hflag || (Hflag && p->fts_level == FTS_ROOTLEVEL)))
+                       continue;
+               if (p->fts_info == FTS_ERR) {
+                       error(p->fts_path);
+                       continue;
+               }
+               if (chown(p->fts_accpath, uid, gid) && !fflag)
+                       chownerr(p->fts_path);
        }
        exit(retval);
 }
 
        }
        exit(retval);
 }
 
-setgid(s)
+a_gid(s)
        register char *s;
 {
        register char *s;
 {
-       struct group *gr, *getgrnam();
+       struct group *gr;
 
        if (!*s) {
                gid = -1;                       /* argument was "uid." */
                return;
        }
 
        if (!*s) {
                gid = -1;                       /* argument was "uid." */
                return;
        }
-       for (gname = s; *s && isdigit(*s); ++s);
-       if (!*s)
-               gid = atoi(gname);
+       gname = s;
+       if (gr = getgrnam(s))
+               gid = gr->gr_gid;
        else {
        else {
-               if (!(gr = getgrnam(gname))) {
-                       if (fflag)
-                               exit(0);
+               for (; *s && isdigit(*s); ++s);
+               if (!*s)
+                       gid = atoi(gname);
+               else {
                        (void)fprintf(stderr, "%s: unknown group id: %s\n",
                            myname, gname);
                        (void)fprintf(stderr, "%s: unknown group id: %s\n",
                            myname, gname);
-                       exit(-1);
+                       exit(1);
                }
                }
-               gid = gr->gr_gid;
        }
 }
 
        }
 }
 
-setuid(s)
+a_uid(s)
        register char *s;
 {
        register char *s;
 {
-       struct passwd *pwd, *getpwnam();
-       char *beg;
+       struct passwd *pw;
+       char *uname;
 
        if (!*s) {
                uid = -1;                       /* argument was ".gid" */
                return;
        }
 
        if (!*s) {
                uid = -1;                       /* argument was ".gid" */
                return;
        }
-       for (beg = s; *s && isdigit(*s); ++s);
-       if (!*s)
-               uid = atoi(beg);
+       if (pw = getpwnam(s))
+               uid = pw->pw_uid;
        else {
        else {
-               if (!(pwd = getpwnam(beg))) {
-                       if (fflag)
-                               exit(0);
+               for (uname = s; *s && isdigit(*s); ++s);
+               if (!*s)
+                       uid = atoi(uname);
+               else {
                        (void)fprintf(stderr,
                        (void)fprintf(stderr,
-                           "chown: unknown user id: %s\n", beg);
-                       exit(-1);
-               }
-               uid = pwd->pw_uid;
-       }
-}
-
-change(file)
-       char *file;
-{
-       register DIR *dirp;
-       register struct dirent *dp;
-       struct stat buf;
-
-       if (chown(file, uid, gid)) {
-               chownerr(file);
-               return;
-       }
-       if (!rflag)
-               return;
-       if (lstat(file, &buf)) {
-               err(file);
-               return;
-       }
-       if ((buf.st_mode & S_IFMT) == S_IFDIR) {
-               if (chdir(file) < 0 || !(dirp = opendir("."))) {
-                       err(file);
-                       return;
-               }
-               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);
+                           "chown: unknown user id: %s\n", uname);
+                       exit(1);
                }
        }
 }
                }
        }
 }
@@ -186,15 +194,14 @@ change(file)
 chownerr(file)
        char *file;
 {
 chownerr(file)
        char *file;
 {
-       extern int errno;
        static int euid = -1, ngroups = -1;
 
        /* check for chown without being root */
        if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
                if (fflag)
                        exit(0);
        static int euid = -1, ngroups = -1;
 
        /* check for chown without being root */
        if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
                if (fflag)
                        exit(0);
-               err(file);
-               exit(-1);
+               error(file);
+               exit(1);
        }
        /* check group membership; kernel just returns EPERM */
        if (gid != -1 && ngroups == -1) {
        }
        /* check group membership; kernel just returns EPERM */
        if (gid != -1 && ngroups == -1) {
@@ -208,27 +215,23 @@ chownerr(file)
                        (void)fprintf(stderr,
                            "%s: you are not a member of group %s.\n",
                            myname, gname);
                        (void)fprintf(stderr,
                            "%s: you are not a member of group %s.\n",
                            myname, gname);
-                       exit(-1);
+                       exit(1);
                }
        }
                }
        }
-       err(file);
+       if (!fflag)
+               error(file);
 }
 
 }
 
-err(s)
-       char *s;
+error(name)
+       char *name;
 {
 {
-       extern int errno;
-       char *strerror();
-
-       if (fflag)
-               return;
-       (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
-       retval = -1;
+       (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
+       retval = 1;
 }
 
 usage()
 {
 }
 
 usage()
 {
-       (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
-           ischown ? "owner[.group]" : "group");
-       exit(-1);
+       (void)fprintf(stderr, "usage: %s [-HRfh] %s file ...\n", myname,
+           ischown ? "[owner][:group]" : "group");
+       exit(1);
 }
 }