prettiness police
[unix-history] / usr / src / usr.sbin / chown / chown.c
CommitLineData
da158ee3 1/*
c6bbda50 2 * Copyright (c) 1988, 1993, 1994
19180e1c 3 * The Regents of the University of California. All rights reserved.
7445173f 4 *
32ce521f 5 * %sccs.include.redist.c%
da158ee3
DF
6 */
7
8#ifndef lint
19180e1c 9static char copyright[] =
c6bbda50 10"@(#) Copyright (c) 1988, 1993, 1994\n\
19180e1c 11 The Regents of the University of California. All rights reserved.\n";
7445173f 12#endif /* not lint */
da158ee3
DF
13
14#ifndef lint
a61ba0b2 15static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) %G%";
7445173f 16#endif /* not lint */
702e3fe5 17
7445173f 18#include <sys/param.h>
69e53de7 19#include <sys/stat.h>
c6bbda50
KB
20
21#include <ctype.h>
f78af81d 22#include <dirent.h>
c6bbda50
KB
23#include <err.h>
24#include <errno.h>
a7bd3fcd 25#include <fts.h>
702e3fe5 26#include <grp.h>
c6bbda50 27#include <pwd.h>
7445173f 28#include <stdio.h>
0594ed17 29#include <stdlib.h>
a7bd3fcd 30#include <string.h>
c6bbda50
KB
31#include <unistd.h>
32
33void a_gid __P((char *));
34void a_uid __P((char *));
35void chownerr __P((char *));
36u_long id __P((char *, char *));
37void usage __P((void));
69e53de7 38
c6bbda50
KB
39uid_t uid;
40gid_t gid;
41int Rflag, ischown, fflag;
fe46eefc 42char *gname, *myname;
69e53de7 43
c6bbda50 44int
69e53de7 45main(argc, argv)
7445173f 46 int argc;
c6bbda50 47 char *argv[];
69e53de7 48{
7445173f 49 extern int optind;
c6bbda50
KB
50 FTS *ftsp;
51 FTSENT *p;
52 int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval;
53 char *cp;
1c8f2f3c 54
7445173f
KB
55 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
56 ischown = myname[2] == 'o';
1c8f2f3c 57
c6bbda50
KB
58 Hflag = Lflag = Pflag = hflag = 0;
59 while ((ch = getopt(argc, argv, "HLPRfh")) != EOF)
60 switch (ch) {
61 case 'H':
62 Hflag = 1;
63 Lflag = Pflag = 0;
64 break;
65 case 'L':
66 Lflag = 1;
67 Hflag = Pflag = 0;
68 break;
69 case 'P':
70 Pflag = 1;
71 Hflag = Lflag = 0;
72 break;
7445173f 73 case 'R':
c6bbda50 74 Rflag = 1;
7445173f 75 break;
c76e0466 76 case 'f':
a7bd3fcd 77 fflag = 1;
c76e0466 78 break;
7c4a71e0 79 case 'h':
c6bbda50
KB
80 /*
81 * In System V (and probably POSIX.2) the -h option
82 * causes chown/chgrp to change the owner/group of
83 * the symbolic link. 4.4BSD's symbolic links don't
84 * have owners/groups, so it's an undocumented noop.
85 * Do syntax checking, though.
86 */
1c8f2f3c 87 hflag = 1;
7c4a71e0 88 break;
7445173f
KB
89 case '?':
90 default:
91 usage();
92 }
93 argv += optind;
94 argc -= optind;
c76e0466 95
7445173f
KB
96 if (argc < 2)
97 usage();
c76e0466 98
da2fcce6 99 fts_options = FTS_PHYSICAL;
c6bbda50
KB
100 if (Rflag) {
101 if (hflag)
102 errx(1,
103 "the -R and -h options may not be specified together.");
104 if (Hflag)
105 fts_options |= FTS_COMFOLLOW;
106 if (Lflag) {
107 fts_options &= ~FTS_PHYSICAL;
108 fts_options |= FTS_LOGICAL;
109 }
110 }
111
a7bd3fcd 112 uid = gid = -1;
7445173f 113 if (ischown) {
a7bd3fcd 114#ifdef SUPPORT_DOT
c6bbda50 115 if ((cp = strchr(*argv, '.')) != NULL) {
7445173f 116 *cp++ = '\0';
0594ed17 117 a_gid(cp);
a7bd3fcd
KB
118 } else
119#endif
c6bbda50 120 if ((cp = strchr(*argv, ':')) != NULL) {
a7bd3fcd 121 *cp++ = '\0';
0594ed17 122 a_gid(cp);
a7bd3fcd 123 }
0594ed17 124 a_uid(*argv);
c6bbda50 125 } else
0594ed17 126 a_gid(*argv);
69e53de7 127
c6bbda50
KB
128 if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
129 err(1, NULL);
130
131 for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
132 switch (p->fts_info) {
133 case FTS_D:
134 if (Rflag) /* Change it at FTS_DP. */
a7bd3fcd 135 continue;
c6bbda50
KB
136 fts_set(ftsp, p, FTS_SKIP);
137 break;
c3729774 138 case FTS_DNR: /* Warn, chown, continue. */
8cd86009 139 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
c3729774
KB
140 rval = 1;
141 break;
142 case FTS_ERR: /* Warn, continue. */
da2fcce6 143 case FTS_NS:
8cd86009 144 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
c6bbda50 145 rval = 1;
1c8f2f3c 146 continue;
c3729774 147 case FTS_SL: /* Ignore. */
c6bbda50
KB
148 case FTS_SLNONE:
149 /*
150 * The only symlinks that end up here are ones that
151 * don't point to anything and ones that we found
152 * doing a physical walk.
153 */
7c4a71e0 154 continue;
c3729774
KB
155 default:
156 break;
a7bd3fcd 157 }
c6bbda50 158 if (chown(p->fts_accpath, uid, gid) && !fflag) {
7c4a71e0 159 chownerr(p->fts_path);
c6bbda50
KB
160 rval = 1;
161 }
c439a634 162 }
84f17227
KB
163 if (errno)
164 err(1, "fts_read");
c6bbda50 165 exit(rval);
69e53de7 166}
702e3fe5 167
c6bbda50 168void
0594ed17 169a_gid(s)
c6bbda50 170 char *s;
702e3fe5 171{
0594ed17 172 struct group *gr;
7445173f 173
c6bbda50 174 if (*s == '\0') /* Argument was "uid[:.]". */
7445173f 175 return;
0594ed17 176 gname = s;
c6bbda50 177 gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid;
c76e0466
SL
178}
179
c6bbda50 180void
0594ed17 181a_uid(s)
c6bbda50 182 char *s;
c76e0466 183{
0594ed17 184 struct passwd *pw;
c76e0466 185
c6bbda50 186 if (*s == '\0') /* Argument was "[:.]gid". */
7445173f 187 return;
c6bbda50 188 uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid;
c76e0466
SL
189}
190
c6bbda50
KB
191u_long
192id(name, type)
193 char *name, *type;
194{
195 u_long val;
196 char *ep;
197
198 /*
199 * XXX
200 * We know that uid_t's and gid_t's are unsigned longs.
201 */
202 errno = 0;
203 val = strtoul(name, &ep, 10);
204 if (errno)
205 err(1, "%s", name);
206 if (*ep != '\0')
207 errx(1, "%s: illegal %s name", name, type);
208 return (val);
209}
210
211void
2a151187
KB
212chownerr(file)
213 char *file;
214{
215 static int euid = -1, ngroups = -1;
c6bbda50 216 int groups[NGROUPS];
2a151187 217
c6bbda50
KB
218 /* Check for chown without being root. */
219 if (errno != EPERM ||
220 uid != -1 && euid == -1 && (euid = geteuid()) != 0) {
2a151187
KB
221 if (fflag)
222 exit(0);
c6bbda50 223 err(1, "%s", file);
2a151187 224 }
2a151187 225
c6bbda50
KB
226 /* Check group membership; kernel just returns EPERM. */
227 if (gid != -1 && ngroups == -1) {
2a151187
KB
228 ngroups = getgroups(NGROUPS, groups);
229 while (--ngroups >= 0 && gid != groups[ngroups]);
230 if (ngroups < 0) {
231 if (fflag)
232 exit(0);
c6bbda50 233 errx(1, "you are not a member of group %s", gname);
2a151187
KB
234 }
235 }
2a151187 236
c6bbda50
KB
237 if (!fflag)
238 warn("%s", file);
7445173f 239}
c76e0466 240
c6bbda50 241void
7445173f
KB
242usage()
243{
c6bbda50
KB
244 (void)fprintf(stderr,
245 "usage: %s [-R [-H | -L | -P]] [-f] %s file ...\n",
246 myname, ischown ? "[owner][:group]" : "group");
a7bd3fcd 247 exit(1);
702e3fe5 248}