1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)chown.c 5.20 (Berkeley) 06/01/92"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <sys/errno.h> 21 #include <dirent.h> 22 #include <fts.h> 23 #include <pwd.h> 24 #include <grp.h> 25 #include <unistd.h> 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 int ischown, uid, gid, fflag, rflag, retval; 32 char *gname, *myname; 33 34 main(argc, argv) 35 int argc; 36 char **argv; 37 { 38 extern int optind; 39 register FTS *ftsp; 40 register FTSENT *p; 41 register char *cp; 42 int ch; 43 int fts_options; 44 int hflag, Hflag; 45 46 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 47 ischown = myname[2] == 'o'; 48 49 hflag = Hflag = 0; 50 fts_options = FTS_NOSTAT | FTS_PHYSICAL; 51 while ((ch = getopt(argc, argv, "HRfh")) != EOF) 52 switch((char)ch) { 53 case 'R': 54 rflag = 1; 55 break; 56 case 'f': 57 fflag = 1; 58 break; 59 case 'h': 60 hflag = 1; 61 fts_options &= ~FTS_PHYSICAL; 62 fts_options |= FTS_LOGICAL; 63 break; 64 case 'H': 65 Hflag = 1; 66 fts_options |= FTS_COMFOLLOW; 67 break; 68 case '?': 69 default: 70 usage(); 71 } 72 argv += optind; 73 argc -= optind; 74 75 if (argc < 2) 76 usage(); 77 78 uid = gid = -1; 79 if (ischown) { 80 #ifdef SUPPORT_DOT 81 if (cp = index(*argv, '.')) { 82 *cp++ = '\0'; 83 a_gid(cp); 84 } else 85 #endif 86 if (cp = index(*argv, ':')) { 87 *cp++ = '\0'; 88 a_gid(cp); 89 } 90 a_uid(*argv); 91 } 92 else 93 a_gid(*argv); 94 95 if (!(ftsp = fts_open(++argv, fts_options, 0))) { 96 (void)fprintf(stderr, 97 "%s: %s.\n", myname, strerror(errno)); 98 exit(1); 99 } 100 while (p = fts_read(ftsp)) { 101 if (p->fts_info == FTS_D) { 102 if (rflag) 103 continue; 104 else 105 fts_set(ftsp, p, FTS_SKIP); 106 } 107 if (p->fts_info == FTS_SL && 108 !(hflag || (Hflag && p->fts_level == FTS_ROOTLEVEL))) 109 continue; 110 if (p->fts_info == FTS_ERR) { 111 error(p->fts_path); 112 continue; 113 } 114 if (chown(p->fts_accpath, uid, gid) && !fflag) 115 chownerr(p->fts_path); 116 } 117 exit(retval); 118 } 119 120 a_gid(s) 121 register char *s; 122 { 123 struct group *gr; 124 125 if (!*s) { 126 gid = -1; /* argument was "uid." */ 127 return; 128 } 129 gname = s; 130 if (gr = getgrnam(s)) 131 gid = gr->gr_gid; 132 else { 133 for (; *s && isdigit(*s); ++s); 134 if (!*s) 135 gid = atoi(gname); 136 else { 137 (void)fprintf(stderr, "%s: unknown group id: %s\n", 138 myname, gname); 139 exit(1); 140 } 141 } 142 } 143 144 a_uid(s) 145 register char *s; 146 { 147 struct passwd *pw; 148 char *uname; 149 150 if (!*s) { 151 uid = -1; /* argument was ".gid" */ 152 return; 153 } 154 if (pw = getpwnam(s)) 155 uid = pw->pw_uid; 156 else { 157 for (uname = s; *s && isdigit(*s); ++s); 158 if (!*s) 159 uid = atoi(uname); 160 else { 161 (void)fprintf(stderr, 162 "chown: unknown user id: %s\n", uname); 163 exit(1); 164 } 165 } 166 } 167 168 chownerr(file) 169 char *file; 170 { 171 static int euid = -1, ngroups = -1; 172 173 /* check for chown without being root */ 174 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 175 if (fflag) 176 exit(0); 177 error(file); 178 exit(1); 179 } 180 /* check group membership; kernel just returns EPERM */ 181 if (gid != -1 && ngroups == -1) { 182 int groups[NGROUPS]; 183 184 ngroups = getgroups(NGROUPS, groups); 185 while (--ngroups >= 0 && gid != groups[ngroups]); 186 if (ngroups < 0) { 187 if (fflag) 188 exit(0); 189 (void)fprintf(stderr, 190 "%s: you are not a member of group %s.\n", 191 myname, gname); 192 exit(1); 193 } 194 } 195 if (!fflag) 196 error(file); 197 } 198 199 error(name) 200 char *name; 201 { 202 (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno)); 203 retval = 1; 204 } 205 206 usage() 207 { 208 (void)fprintf(stderr, "usage: %s [-HRfh] %s file ...\n", myname, 209 ischown ? "[owner][:group]" : "group"); 210 exit(1); 211 } 212