1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * chown [-fR] uid[.gid] file ... 44 */ 45 46 #include <stdio.h> 47 #include <ctype.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <pwd.h> 51 #include <dirent.h> 52 #include <grp.h> 53 #include <errno.h> 54 55 struct passwd *pwd; 56 struct passwd *getpwnam(); 57 struct stat stbuf; 58 uid_t uid; 59 int status; 60 int fflag; 61 int rflag; 62 63 void fatal(int, char *, char *); 64 65 int 66 main(int argc, char *argv[]) 67 { 68 int c; 69 gid_t gid; 70 char *cp, *group; 71 char optchar[2]; 72 struct group *grp; 73 extern char *strchr(); 74 75 argc--, argv++; 76 while (argc > 0 && argv[0][0] == '-') { 77 for (cp = &argv[0][1]; *cp; cp++) 78 79 switch (*cp) { 80 81 case 'f': 82 fflag++; 83 break; 84 85 case 'R': 86 rflag++; 87 break; 88 89 default: 90 optchar[0] = *cp; 91 optchar[1] = '\0'; 92 fatal(255, "unknown option: %s", optchar); 93 } 94 argv++, argc--; 95 } 96 if (argc < 2) { 97 fprintf(stderr, "usage: chown [-fR] owner[.group] file ...\n"); 98 exit(-1); 99 } 100 gid = -1; 101 group = strchr(argv[0], '.'); 102 if (group != NULL) { 103 *group++ = '\0'; 104 if (!isnumber(group)) { 105 if ((grp = getgrnam(group)) == NULL) 106 fatal(255, "unknown group: %s", group); 107 gid = grp -> gr_gid; 108 (void) endgrent(); 109 } else if (*group != '\0') { 110 errno = 0; 111 gid = (gid_t)strtol(group, NULL, 10); 112 if (errno != 0) { 113 if (errno == ERANGE) { 114 fatal(2, 115 "group id too large: %s", group); 116 } else { 117 fatal(2, "group id invalid: %s", group); 118 } 119 } 120 } 121 } 122 if (!isnumber(argv[0])) { 123 if ((pwd = getpwnam(argv[0])) == NULL) 124 fatal(255, "unknown user id: %s", argv[0]); 125 uid = pwd->pw_uid; 126 } else { 127 errno = 0; 128 uid = (uid_t)strtol(argv[0], NULL, 10); 129 if (errno != 0) { 130 if (errno == ERANGE) { 131 fatal(2, "user id too large: %s", argv[0]); 132 } else { 133 fatal(2, "user id invalid: %s", argv[0]); 134 } 135 } 136 } 137 for (c = 1; c < argc; c++) { 138 /* do stat for directory arguments */ 139 if (lstat(argv[c], &stbuf) < 0) { 140 status += Perror(argv[c]); 141 continue; 142 } 143 if (rflag && ((stbuf.st_mode&S_IFMT) == S_IFDIR)) { 144 status += chownr(argv[c], uid, gid); 145 continue; 146 } 147 if (lchown(argv[c], uid, gid)) { 148 status += Perror(argv[c]); 149 continue; 150 } 151 } 152 return (status); 153 } 154 155 int 156 isnumber(char *s) 157 { 158 int c; 159 160 while (c = *s++) 161 if (!isdigit(c)) 162 return (0); 163 return (1); 164 } 165 166 int 167 chownr(char *dir, uid_t uid, gid_t gid) 168 { 169 DIR *dirp; 170 struct dirent *dp; 171 struct stat st; 172 char savedir[1024]; 173 int ecode; 174 175 if (getcwd(savedir, 1024) == NULL) 176 fatal(255, "%s", savedir); 177 /* 178 * Change what we are given before doing it's contents. 179 */ 180 if (chown(dir, uid, gid) < 0 && Perror(dir)) 181 return (1); 182 if (chdir(dir) < 0) { 183 Perror(dir); 184 return (1); 185 } 186 if ((dirp = opendir(".")) == NULL) { 187 Perror(dir); 188 return (1); 189 } 190 dp = readdir(dirp); 191 dp = readdir(dirp); /* read "." and ".." */ 192 ecode = 0; 193 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 194 if (lstat(dp->d_name, &st) < 0) { 195 ecode = Perror(dp->d_name); 196 if (ecode) 197 break; 198 continue; 199 } 200 if ((st.st_mode&S_IFMT) == S_IFDIR) { 201 ecode = chownr(dp->d_name, uid, gid); 202 if (ecode) 203 break; 204 continue; 205 } 206 if (lchown(dp->d_name, uid, gid) < 0 && 207 (ecode = Perror(dp->d_name))) 208 break; 209 } 210 closedir(dirp); 211 if (chdir(savedir) < 0) 212 fatal(255, "can't change back to %s", savedir); 213 return (ecode); 214 } 215 216 int 217 error(char *fmt, char *a) 218 { 219 220 if (!fflag) { 221 fprintf(stderr, "chown: "); 222 fprintf(stderr, fmt, a); 223 putc('\n', stderr); 224 } 225 return (!fflag); 226 } 227 228 void 229 fatal(int status, char *fmt, char *a) 230 { 231 232 fflag = 0; 233 (void) error(fmt, a); 234 exit(status); 235 } 236 237 int 238 Perror(char *s) 239 { 240 241 if (!fflag) { 242 fprintf(stderr, "chown: "); 243 perror(s); 244 } 245 return (!fflag); 246 } 247