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