install correct aliases file
[unix-history] / usr / src / usr.sbin / chown / chown.c
index f9eb48d..b9f049b 100644 (file)
-static char *sccsid = "@(#)chown.c     4.5 (Berkeley) %G%";
-
 /*
 /*
- * chown [-fR] uid[.gid] file ...
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
  */
 
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/types.h>
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chown.c    5.11 (Berkeley) %G%";
+#endif /* not lint */
+
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <pwd.h>
 #include <sys/dir.h>
 #include <sys/dir.h>
+#include <pwd.h>
 #include <grp.h>
 #include <grp.h>
+#include <stdio.h>
+#include <ctype.h>
 
 
-struct passwd  *pwd,*getpwnam();
-struct stat    stbuf;
-int    uid;
-int    status;
-int    fflag, rflag;
+static int ischown, uid, gid, fflag, rflag, retval;
+static char *gname, *myname;
 
 main(argc, argv)
 
 main(argc, argv)
-char *argv[];
+       int argc;
+       char **argv;
 {
 {
-       register int c, gid;
-       register char *flags, *group;
-       struct group *grp;
+       extern char *optarg;
+       extern int optind;
+       register char *cp;
+       int ch;
+       char *index(), *rindex();
 
 
-       if(argc < 3) {
-               fprintf(stderr, "usage: chown [-fR] owner[.group] file ...\n");
-               exit(-1);
-       }
-       if (*argv[1] == '-') {
-               for (flags = argv[1]; *flags; ++flags)
-                       switch (*flags) {
-                         case '-':                     break;
-                         case 'f':     fflag++;        break;
-                         case 'R':     rflag++;        break;
-                         default:
-                               printf("chown: unknown option: %c\n", *flags);
-                               exit(-2);
-                       }
-               argv++, argc--;
-       }
+       myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
+       ischown = myname[2] == 'o';
 
 
-       for (group = argv[1]; *group ; group++) {
-               if (*group == '.') {
-                       *group = '\0';
-                       group++;
-                       if (isnumber(group))
-                               gid = atoi(group);
-                       else {
-                               if ((grp=getgrnam(group)) == NULL) {
-                                       printf("unknown group: %s\n",group);
-                                       exit(-3);
-                               }
-                               gid = grp -> gr_gid;
-                               endgrent();
-                       }
-                       goto owner;
+       while ((ch = getopt(argc, argv, "Rf")) != EOF)
+               switch((char)ch) {
+               case 'R':
+                       rflag++;
+                       break;
+               case 'f':
+                       fflag++;
+                       break;
+               case '?':
+               default:
+                       usage();
                }
                }
-       }
-       group = NULL;
-       
-owner:
-       if (isnumber(argv[1])) {
-               uid = atoi(argv[1]);
-       } else {
-               if ((pwd=getpwnam(argv[1])) == NULL) {
-                       printf("unknown user id: %s\n",argv[1]);
-                       exit(-4);
+       argv += optind;
+       argc -= optind;
+
+       if (argc < 2)
+               usage();
+
+       if (ischown) {
+               if (cp = index(*argv, '.')) {
+                       *cp++ = '\0';
+                       setgid(cp);
                }
                }
-               uid = pwd->pw_uid;
+               else
+                       gid = -1;
+               setuid(*argv);
+       }
+       else {
+               uid = -1;
+               setgid(*argv);
        }
 
        }
 
-       for(c=2; c<argc; c++) {
-               if (lstat(argv[c], &stbuf) < 0) {
-                       printf("chown: couldn't stat %s\n", argv[c]);
-                       exit(-5);
-               }
-               if (group == NULL)
-                       gid = stbuf.st_gid;
-               if (rflag && stbuf.st_mode & S_IFDIR)
-                       status += chownr(argv[c], group, uid, gid);
-               else if (chown(argv[c], uid, gid) < 0 && !fflag) {
-                       perror(argv[c]);
-                       status++;
+       while (*++argv)
+               change(*argv);
+       exit(retval);
+}
+
+static
+setgid(s)
+       register char *s;
+{
+       struct group *gr, *getgrnam();
+
+       if (!*s) {
+               gid = -1;                       /* argument was "uid." */
+               return;
+       }
+       for (gname = s; *s && isdigit(*s); ++s);
+       if (!*s)
+               gid = atoi(gname);
+       else {
+               if (!(gr = getgrnam(gname))) {
+                       if (fflag)
+                               exit(0);
+                       fprintf(stderr, "%s: unknown group id: %s\n",
+                           myname, gname);
+                       exit(-1);
                }
                }
+               gid = gr->gr_gid;
        }
        }
-       exit(status);
 }
 
 }
 
-isnumber(s)
-char *s;
+static
+setuid(s)
+       register char *s;
 {
 {
-       register c;
+       struct passwd *pwd, *getpwnam();
+       char *beg;
 
 
-       while(c = *s++)
-               if(!isdigit(c))
-                       return(0);
-       return(1);
+       if (!*s) {
+               uid = -1;                       /* argument was ".gid" */
+               return;
+       }
+       for (beg = s; *s && isdigit(*s); ++s);
+       if (!*s)
+               uid = atoi(beg);
+       else {
+               if (!(pwd = getpwnam(beg))) {
+                       if (fflag)
+                               exit(0);
+                       fprintf(stderr, "chown: unknown user id: %s\n", beg);
+                       exit(-1);
+               }
+               uid = pwd->pw_uid;
+       }
 }
 
 }
 
-chownr(dir, dogrp, uid, gid_save)
-       char    *dir;
+static
+change(file)
+       char *file;
 {
 {
-       register DIR            *dirp;
-       register struct direct  *dp;
-       register struct stat    st;
-       char                    savedir[1024];
-       int                     gid;
-
-       if (getwd(savedir) == 0) {
-               fprintf(stderr, "chown: %s\n", savedir);
-               exit(-6);
+       register DIR *dirp;
+       register struct direct *dp;
+       struct stat buf;
+
+       if (chown(file, uid, gid)) {
+               chownerr(file);
+               return;
        }
        }
-       if (chown(dir, uid, gid_save) < 0 && !fflag) {
-               perror(dir);
-               return(1);
+       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);
+               }
+       }
+}
 
 
-       chdir(dir);
-       if ((dirp = opendir(".")) == NULL) {
-               perror(dir);
-               exit(status);
+static
+chownerr(file)
+       char *file;
+{
+       static int euid = -1, ngroups = -1;
+
+       /* check for chown without being root */
+       if (uid != -1 && euid == -1 && (euid = geteuid())) {
+               if (fflag)
+                       exit(0);
+               err(file);
+               exit(-1);
        }
        }
-       dp = readdir(dirp);
-       dp = readdir(dirp); /* read "." and ".." */
+       /* check group membership; kernel just returns EPERM */
+       if (gid != -1 && ngroups == -1) {
+               int groups[NGROUPS];
 
 
-       for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
-               if (lstat(dp->d_name, &st) < 0) {
-                       fprintf(stderr, "chown: can't access %s\n", dp->d_name);
-                       return(1);
+               ngroups = getgroups(NGROUPS, groups);
+               while (--ngroups >= 0 && gid != groups[ngroups]);
+               if (ngroups < 0) {
+                       if (fflag)
+                               exit(0);
+                       fprintf(stderr,
+                           "%s: you are not a member of group %s.\n",
+                           myname, gname);
+                       exit(-1);
                }
                }
-               if (dogrp)
-                       gid = gid_save;
-               else
-                       gid = st.st_gid;
-               if (st.st_mode & S_IFDIR)
-                       chownr(dp->d_name, dogrp, uid, gid);
-               else
-                       if (chown(dp->d_name, uid, gid) < 0 && !fflag) {
-                               perror(dp->d_name);
-                               return(1);
-                       }
        }
        }
-       closedir(dirp);
-       chdir(savedir);
-       return(0);
+       err(file);
+}
+
+static
+err(s)
+       char *s;
+{
+       if (fflag)
+               return;
+       fprintf(stderr, "%s: ", myname);
+       perror(s);
+       retval = -1;
+}
+
+static
+usage()
+{
+       fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
+           ischown ? "owner[.group]" : "group");
+       exit(-1);
 }
 }