POSIX 1003.2B/D9 symbolic links
[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
c6bbda50 15static char sccsid[] = "@(#)chown.c 8.2 (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
c6bbda50
KB
99 fts_options = FTS_NOSTAT | FTS_PHYSICAL;
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;
138 case FTS_DC:
139 warnx("tree cycle: %s", p->fts_path);
140 rval = 1;
141 continue;
142 case FTS_ERR:
143 errno = p->fts_errno;
144 warn("%s", p->fts_path);
145 rval = 1;
1c8f2f3c 146 continue;
c6bbda50
KB
147 case FTS_SL:
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;
a7bd3fcd 155 }
c6bbda50 156 if (chown(p->fts_accpath, uid, gid) && !fflag) {
7c4a71e0 157 chownerr(p->fts_path);
c6bbda50
KB
158 rval = 1;
159 }
c439a634 160 }
c6bbda50 161 exit(rval);
69e53de7 162}
702e3fe5 163
c6bbda50 164void
0594ed17 165a_gid(s)
c6bbda50 166 char *s;
702e3fe5 167{
0594ed17 168 struct group *gr;
7445173f 169
c6bbda50 170 if (*s == '\0') /* Argument was "uid[:.]". */
7445173f 171 return;
0594ed17 172 gname = s;
c6bbda50 173 gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid;
c76e0466
SL
174}
175
c6bbda50 176void
0594ed17 177a_uid(s)
c6bbda50 178 char *s;
c76e0466 179{
0594ed17 180 struct passwd *pw;
c76e0466 181
c6bbda50 182 if (*s == '\0') /* Argument was "[:.]gid". */
7445173f 183 return;
c6bbda50 184 uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid;
c76e0466
SL
185}
186
c6bbda50
KB
187u_long
188id(name, type)
189 char *name, *type;
190{
191 u_long val;
192 char *ep;
193
194 /*
195 * XXX
196 * We know that uid_t's and gid_t's are unsigned longs.
197 */
198 errno = 0;
199 val = strtoul(name, &ep, 10);
200 if (errno)
201 err(1, "%s", name);
202 if (*ep != '\0')
203 errx(1, "%s: illegal %s name", name, type);
204 return (val);
205}
206
207void
2a151187
KB
208chownerr(file)
209 char *file;
210{
211 static int euid = -1, ngroups = -1;
c6bbda50 212 int groups[NGROUPS];
2a151187 213
c6bbda50
KB
214 /* Check for chown without being root. */
215 if (errno != EPERM ||
216 uid != -1 && euid == -1 && (euid = geteuid()) != 0) {
2a151187
KB
217 if (fflag)
218 exit(0);
c6bbda50 219 err(1, "%s", file);
2a151187 220 }
2a151187 221
c6bbda50
KB
222 /* Check group membership; kernel just returns EPERM. */
223 if (gid != -1 && ngroups == -1) {
2a151187
KB
224 ngroups = getgroups(NGROUPS, groups);
225 while (--ngroups >= 0 && gid != groups[ngroups]);
226 if (ngroups < 0) {
227 if (fflag)
228 exit(0);
c6bbda50 229 errx(1, "you are not a member of group %s", gname);
2a151187
KB
230 }
231 }
2a151187 232
c6bbda50
KB
233 if (!fflag)
234 warn("%s", file);
7445173f 235}
c76e0466 236
c6bbda50 237void
7445173f
KB
238usage()
239{
c6bbda50
KB
240 (void)fprintf(stderr,
241 "usage: %s [-R [-H | -L | -P]] [-f] %s file ...\n",
242 myname, ischown ? "[owner][:group]" : "group");
a7bd3fcd 243 exit(1);
702e3fe5 244}