Home | History | Annotate | Download | only in chown
      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