1 /* $NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $ */
4 * Copyright (c) 1988, 1993, 1994, 2003
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94";
42 __RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $");
46 #include <sys/types.h>
63 static void a_gid(const char *);
64 static void a_uid(const char *);
65 static id_t
id(const char *, const char *);
66 __dead
static void usage(void);
71 static const char *myname
;
73 struct option chown_longopts
[] = {
74 { "reference", required_argument
, 0,
81 main(int argc
, char **argv
)
85 int Hflag
, Lflag
, Rflag
, ch
, fflag
, fts_options
, hflag
, rval
, vflag
;
87 int (*change_owner
)(const char *, uid_t
, gid_t
);
91 (void)setlocale(LC_ALL
, "");
93 myname
= getprogname();
94 ischown
= (myname
[2] == 'o');
97 Hflag
= Lflag
= Rflag
= fflag
= hflag
= vflag
= 0;
98 while ((ch
= getopt_long(argc
, argv
, "HLPRfhv",
99 chown_longopts
, NULL
)) != -1)
123 * In System V the -h option causes chown/chgrp to
124 * change the owner/group of the symbolic link.
125 * 4.4BSD's symbolic links didn't have owners/groups,
126 * so it was an undocumented noop.
127 * In NetBSD 1.3, lchown(2) is introduced.
141 if (argc
== 0 || (argc
== 1 && reference
== NULL
))
144 fts_options
= FTS_PHYSICAL
;
147 fts_options
|= FTS_COMFOLLOW
;
151 "the -L and -h options "
152 "may not be specified together.");
153 fts_options
&= ~FTS_PHYSICAL
;
154 fts_options
|= FTS_LOGICAL
;
157 fts_options
|= FTS_COMFOLLOW
;
161 if (reference
== NULL
) {
163 if ((cp
= strchr(*argv
, ':')) != NULL
) {
168 else if ((cp
= strrchr(*argv
, '.')) != NULL
) {
169 if (uid_from_user(*argv
, &uid
) == -1) {
182 if (stat(reference
, &st
) == -1)
183 err(EXIT_FAILURE
, "Cannot stat `%s'", reference
);
189 if ((ftsp
= fts_open(argv
, fts_options
, NULL
)) == NULL
)
190 err(EXIT_FAILURE
, "fts_open");
192 for (rval
= EXIT_SUCCESS
; (p
= fts_read(ftsp
)) != NULL
;) {
193 change_owner
= chown
;
194 switch (p
->fts_info
) {
196 if (!Rflag
) /* Change it at FTS_DP. */
197 fts_set(ftsp
, p
, FTS_SKIP
);
199 case FTS_DNR
: /* Warn, chown, continue. */
200 warnx("%s: %s", p
->fts_path
, strerror(p
->fts_errno
));
203 case FTS_ERR
: /* Warn, continue. */
205 warnx("%s: %s", p
->fts_path
, strerror(p
->fts_errno
));
208 case FTS_SL
: /* Ignore unless -h. */
210 * All symlinks we found while doing a physical
216 * Note that if we follow a symlink, fts_info is
217 * not FTS_SL but FTS_F or whatever. And we should
218 * use lchown only for FTS_SL and should use chown
221 change_owner
= lchown
;
223 case FTS_SLNONE
: /* Ignore. */
225 * The only symlinks that end up here are ones that
226 * don't point to anything. Note that if we are
227 * doing a phisycal walk, we never reach here unless
228 * we asked to follow explicitly.
235 if ((*change_owner
)(p
->fts_accpath
, uid
, gid
) && !fflag
) {
236 warn("%s", p
->fts_path
);
240 printf("%s\n", p
->fts_path
);
244 err(EXIT_FAILURE
, "fts_read");
254 if (*s
== '\0') /* Argument was "uid[:.]". */
256 gr
= *s
== '#' ? NULL
: getgrnam(s
);
258 gid
= id(s
, "group");
267 if (*s
== '\0') /* Argument was "[:.]gid". */
269 if (*s
== '#' || uid_from_user(s
, &uid
) == -1) {
276 id(const char *name
, const char *type
)
284 val
= (id_t
)strtoul(name
, &ep
, 10);
286 err(EXIT_FAILURE
, "%s", name
);
288 errx(EXIT_FAILURE
, "%s: invalid %s name", name
, type
);
296 (void)fprintf(stderr
,
297 "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n"
298 "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n",
299 myname
, ischown
? "owner:group|owner|:group" : "group",