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 /* 41 * chown [-fR] uid[.gid] file ... 42 */ 43 44 #include <stdio.h> 45 #include <ctype.h> 46 #include <sys/types.h> 47 #include <sys/stat.h> 48 #include <pwd.h> 49 #include <dirent.h> 50 #include <grp.h> 51 #include <errno.h> 52 #include <unistd.h> 53 54 struct passwd *pwd; 55 struct passwd *getpwnam(); 56 struct stat stbuf; 57 uid_t uid; 58 int status; 59 int fflag; 60 int rflag; 61 62 void fatal(int, char *, char *); 63 64 int 65 main(int argc, char *argv[]) 66 { 67 int c; 68 gid_t gid; 69 char *cp, *group; 70 char optchar[2]; 71 struct group *grp; 72 extern char *strchr(); 73 74 argc--, argv++; 75 while (argc > 0 && argv[0][0] == '-') { 76 for (cp = &argv[0][1]; *cp; cp++) 77 78 switch (*cp) { 79 80 case 'f': 81 fflag++; 82 break; 83 84 case 'R': 85 rflag++; 86 break; 87 88 default: 89 optchar[0] = *cp; 90 optchar[1] = '\0'; 91 fatal(255, "unknown option: %s", optchar); 92 } 93 argv++, argc--; 94 } 95 if (argc < 2) { 96 fprintf(stderr, "usage: chown [-fR] owner[.group] file ...\n"); 97 exit(-1); 98 } 99 gid = -1; 100 group = strchr(argv[0], '.'); 101 if (group != NULL) { 102 *group++ = '\0'; 103 if (!isnumber(group)) { 104 if ((grp = getgrnam(group)) == NULL) 105 fatal(255, "unknown group: %s", group); 106 gid = grp -> gr_gid; 107 (void) endgrent(); 108 } else if (*group != '\0') { 109 errno = 0; 110 gid = (gid_t)strtol(group, NULL, 10); 111 if (errno != 0) { 112 if (errno == ERANGE) { 113 fatal(2, 114 "group id too large: %s", group); 115 } else { 116 fatal(2, "group id invalid: %s", group); 117 } 118 } 119 } 120 } 121 if (!isnumber(argv[0])) { 122 if ((pwd = getpwnam(argv[0])) == NULL) 123 fatal(255, "unknown user id: %s", argv[0]); 124 uid = pwd->pw_uid; 125 } else { 126 errno = 0; 127 uid = (uid_t)strtol(argv[0], NULL, 10); 128 if (errno != 0) { 129 if (errno == ERANGE) { 130 fatal(2, "user id too large: %s", argv[0]); 131 } else { 132 fatal(2, "user id invalid: %s", argv[0]); 133 } 134 } 135 } 136 for (c = 1; c < argc; c++) { 137 /* do stat for directory arguments */ 138 if (lstat(argv[c], &stbuf) < 0) { 139 status += Perror(argv[c]); 140 continue; 141 } 142 if (rflag && ((stbuf.st_mode&S_IFMT) == S_IFDIR)) { 143 status += chownr(argv[c], uid, gid); 144 continue; 145 } 146 if (lchown(argv[c], uid, gid)) { 147 status += Perror(argv[c]); 148 continue; 149 } 150 } 151 return (status); 152 } 153 154 int 155 isnumber(char *s) 156 { 157 int c; 158 159 while (c = *s++) 160 if (!isdigit(c)) 161 return (0); 162 return (1); 163 } 164 165 int 166 chownr(char *dir, uid_t uid, gid_t gid) 167 { 168 DIR *dirp; 169 struct dirent *dp; 170 struct stat st; 171 char savedir[1024]; 172 int ecode; 173 174 if (getcwd(savedir, 1024) == NULL) 175 fatal(255, "%s", savedir); 176 /* 177 * Change what we are given before doing it's contents. 178 */ 179 if (chown(dir, uid, gid) < 0 && Perror(dir)) 180 return (1); 181 if (chdir(dir) < 0) { 182 Perror(dir); 183 return (1); 184 } 185 if ((dirp = opendir(".")) == NULL) { 186 Perror(dir); 187 return (1); 188 } 189 dp = readdir(dirp); 190 dp = readdir(dirp); /* read "." and ".." */ 191 ecode = 0; 192 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 193 if (lstat(dp->d_name, &st) < 0) { 194 ecode = Perror(dp->d_name); 195 if (ecode) 196 break; 197 continue; 198 } 199 if ((st.st_mode&S_IFMT) == S_IFDIR) { 200 ecode = chownr(dp->d_name, uid, gid); 201 if (ecode) 202 break; 203 continue; 204 } 205 if (lchown(dp->d_name, uid, gid) < 0 && 206 (ecode = Perror(dp->d_name))) 207 break; 208 } 209 closedir(dirp); 210 if (chdir(savedir) < 0) 211 fatal(255, "can't change back to %s", savedir); 212 return (ecode); 213 } 214 215 int 216 error(char *fmt, char *a) 217 { 218 219 if (!fflag) { 220 fprintf(stderr, "chown: "); 221 fprintf(stderr, fmt, a); 222 putc('\n', stderr); 223 } 224 return (!fflag); 225 } 226 227 void 228 fatal(int status, char *fmt, char *a) 229 { 230 231 fflag = 0; 232 (void) error(fmt, a); 233 exit(status); 234 } 235 236 int 237 Perror(char *s) 238 { 239 240 if (!fflag) { 241 fprintf(stderr, "chown: "); 242 perror(s); 243 } 244 return (!fflag); 245 } 246