/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 * The Regents of the University of California * All Rights Reserved * * University Acknowledgment- Portions of this document are derived from * software developed by the University of California, Berkeley, and its * contributors. */ /* * chown [-fR] uid[.gid] file ... */ #include #include #include #include #include #include #include #include #include struct passwd *pwd; struct passwd *getpwnam(); struct stat stbuf; uid_t uid; int status; int fflag; int rflag; void fatal(int, char *, char *); int main(int argc, char *argv[]) { int c; gid_t gid; char *cp, *group; char optchar[2]; struct group *grp; extern char *strchr(); argc--, argv++; while (argc > 0 && argv[0][0] == '-') { for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { case 'f': fflag++; break; case 'R': rflag++; break; default: optchar[0] = *cp; optchar[1] = '\0'; fatal(255, "unknown option: %s", optchar); } argv++, argc--; } if (argc < 2) { fprintf(stderr, "usage: chown [-fR] owner[.group] file ...\n"); exit(-1); } gid = -1; group = strchr(argv[0], '.'); if (group != NULL) { *group++ = '\0'; if (!isnumber(group)) { if ((grp = getgrnam(group)) == NULL) fatal(255, "unknown group: %s", group); gid = grp -> gr_gid; (void) endgrent(); } else if (*group != '\0') { errno = 0; gid = (gid_t)strtol(group, NULL, 10); if (errno != 0) { if (errno == ERANGE) { fatal(2, "group id too large: %s", group); } else { fatal(2, "group id invalid: %s", group); } } } } if (!isnumber(argv[0])) { if ((pwd = getpwnam(argv[0])) == NULL) fatal(255, "unknown user id: %s", argv[0]); uid = pwd->pw_uid; } else { errno = 0; uid = (uid_t)strtol(argv[0], NULL, 10); if (errno != 0) { if (errno == ERANGE) { fatal(2, "user id too large: %s", argv[0]); } else { fatal(2, "user id invalid: %s", argv[0]); } } } for (c = 1; c < argc; c++) { /* do stat for directory arguments */ if (lstat(argv[c], &stbuf) < 0) { status += Perror(argv[c]); continue; } if (rflag && ((stbuf.st_mode&S_IFMT) == S_IFDIR)) { status += chownr(argv[c], uid, gid); continue; } if (lchown(argv[c], uid, gid)) { status += Perror(argv[c]); continue; } } return (status); } int isnumber(char *s) { int c; while (c = *s++) if (!isdigit(c)) return (0); return (1); } int chownr(char *dir, uid_t uid, gid_t gid) { DIR *dirp; struct dirent *dp; struct stat st; char savedir[1024]; int ecode; if (getcwd(savedir, 1024) == NULL) fatal(255, "%s", savedir); /* * Change what we are given before doing it's contents. */ if (chown(dir, uid, gid) < 0 && Perror(dir)) return (1); if (chdir(dir) < 0) { Perror(dir); return (1); } if ((dirp = opendir(".")) == NULL) { Perror(dir); return (1); } dp = readdir(dirp); dp = readdir(dirp); /* read "." and ".." */ ecode = 0; for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if (lstat(dp->d_name, &st) < 0) { ecode = Perror(dp->d_name); if (ecode) break; continue; } if ((st.st_mode&S_IFMT) == S_IFDIR) { ecode = chownr(dp->d_name, uid, gid); if (ecode) break; continue; } if (lchown(dp->d_name, uid, gid) < 0 && (ecode = Perror(dp->d_name))) break; } closedir(dirp); if (chdir(savedir) < 0) fatal(255, "can't change back to %s", savedir); return (ecode); } int error(char *fmt, char *a) { if (!fflag) { fprintf(stderr, "chown: "); fprintf(stderr, fmt, a); putc('\n', stderr); } return (!fflag); } void fatal(int status, char *fmt, char *a) { fflag = 0; (void) error(fmt, a); exit(status); } int Perror(char *s) { if (!fflag) { fprintf(stderr, "chown: "); perror(s); } return (!fflag); }