386BSD 0.1 development
[unix-history] / usr / src / usr.sbin / chown / chown.c
CommitLineData
366534c2
WJ
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35char copyright[] =
36"@(#) Copyright (c) 1988 Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)chown.c 5.18 (Berkeley) 3/9/91";
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/stat.h>
46#include <sys/errno.h>
47#include <dirent.h>
48#include <fts.h>
49#include <pwd.h>
50#include <grp.h>
51#include <unistd.h>
52#include <stdio.h>
53#include <ctype.h>
54#include <stdlib.h>
55#include <string.h>
56
57int ischown, uid, gid, fflag, rflag, retval;
58char *gname, *myname;
59
60main(argc, argv)
61 int argc;
62 char **argv;
63{
64 extern int optind;
65 register FTS *fts;
66 register FTSENT *p;
67 register char *cp;
68 int ch;
69
70 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
71 ischown = myname[2] == 'o';
72
73 while ((ch = getopt(argc, argv, "Rf")) != EOF)
74 switch((char)ch) {
75 case 'R':
76 rflag = 1;
77 break;
78 case 'f':
79 fflag = 1;
80 break;
81 case '?':
82 default:
83 usage();
84 }
85 argv += optind;
86 argc -= optind;
87
88 if (argc < 2)
89 usage();
90
91 uid = gid = -1;
92 if (ischown) {
93#ifdef SUPPORT_DOT
94 if (cp = index(*argv, '.')) {
95 *cp++ = '\0';
96 a_gid(cp);
97 } else
98#endif
99 if (cp = index(*argv, ':')) {
100 *cp++ = '\0';
101 a_gid(cp);
102 }
103 a_uid(*argv);
104 }
105 else
106 a_gid(*argv);
107
108 if (rflag) {
109 if (!(fts = fts_open(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) {
110 (void)fprintf(stderr,
111 "%s: %s.\n", myname, strerror(errno));
112 exit(1);
113 }
114 while (p = fts_read(fts)) {
115 if (p->fts_info == FTS_D)
116 continue;
117 if (p->fts_info == FTS_ERR) {
118 error(p->fts_path);
119 continue;
120 }
121 if (chown(p->fts_accpath, uid, gid) && !fflag)
122 chownerr(p->fts_path);
123 }
124 exit(retval);
125 }
126 while (*++argv)
127 if (chown(*argv, uid, gid) && !fflag)
128 chownerr(*argv);
129 exit(retval);
130}
131
132a_gid(s)
133 register char *s;
134{
135 struct group *gr;
136
137 if (!*s) {
138 gid = -1; /* argument was "uid." */
139 return;
140 }
141 gname = s;
142 if (gr = getgrnam(s))
143 gid = gr->gr_gid;
144 else {
145 for (; *s && isdigit(*s); ++s);
146 if (!*s)
147 gid = atoi(gname);
148 else {
149 (void)fprintf(stderr, "%s: unknown group id: %s\n",
150 myname, gname);
151 exit(1);
152 }
153 }
154}
155
156a_uid(s)
157 register char *s;
158{
159 struct passwd *pw;
160 char *uname;
161
162 if (!*s) {
163 uid = -1; /* argument was ".gid" */
164 return;
165 }
166 if (pw = getpwnam(s))
167 uid = pw->pw_uid;
168 else {
169 for (uname = s; *s && isdigit(*s); ++s);
170 if (!*s)
171 uid = atoi(uname);
172 else {
173 (void)fprintf(stderr,
174 "chown: unknown user id: %s\n", uname);
175 exit(1);
176 }
177 }
178}
179
180chownerr(file)
181 char *file;
182{
183 static int euid = -1, ngroups = -1;
184
185 /* check for chown without being root */
186 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
187 if (fflag)
188 exit(0);
189 error(file);
190 exit(1);
191 }
192 /* check group membership; kernel just returns EPERM */
193 if (gid != -1 && ngroups == -1) {
194 int groups[NGROUPS];
195
196 ngroups = getgroups(NGROUPS, groups);
197 while (--ngroups >= 0 && gid != groups[ngroups]);
198 if (ngroups < 0) {
199 if (fflag)
200 exit(0);
201 (void)fprintf(stderr,
202 "%s: you are not a member of group %s.\n",
203 myname, gname);
204 exit(1);
205 }
206 }
207 if (!fflag)
208 error(file);
209}
210
211error(name)
212 char *name;
213{
214 (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
215 retval = 1;
216}
217
218usage()
219{
220 (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
221 ischown ? "[owner][:group]" : "group");
222 exit(1);
223}