~cfuhrman/+junk/netbsd-othersrc-trunk

« back to all changes in this revision

Viewing changes to usr.sbin/chown/chown.c

  • Committer: stacktic
  • Date: 2009-03-23 21:04:00 UTC
  • Revision ID: svn-v4:288d5a72-fed7-e111-8680-000c29dcf8fe:trunk:1946
ImportedĀ fs-utilsĀ binaries

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $NetBSD$        */
 
2
/* from */
 
3
/*      NetBSD: chown.c,v 1.32 2008/07/21 13:36:57 lukem Exp    */
 
4
 
 
5
/*
 
6
 * Copyright (c) 1988, 1993, 1994, 2003
 
7
 *      The Regents of the University of California.  All rights reserved.
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted provided that the following conditions
 
11
 * are met:
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer.
 
14
 * 2. Redistributions in binary form must reproduce the above copyright
 
15
 *    notice, this list of conditions and the following disclaimer in the
 
16
 *    documentation and/or other materials provided with the distribution.
 
17
 * 3. 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
#include <sys/cdefs.h>
 
35
#ifndef lint
 
36
__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\
 
37
 The Regents of the University of California.  All rights reserved.");
 
38
#endif /* not lint */
 
39
 
 
40
#ifndef lint
 
41
#if 0
 
42
static char sccsid[] = "@(#)chown.c     8.8 (Berkeley) 4/4/94";
 
43
#else
 
44
__RCSID("$NetBSD: chown.c,v 1.32 2008/07/21 13:36:57 lukem Exp $");
 
45
#endif
 
46
#endif /* not lint */
 
47
 
 
48
#include <sys/types.h>
 
49
#include <sys/stat.h>
 
50
 
 
51
#include <ctype.h>
 
52
#include <dirent.h>
 
53
#include <err.h>
 
54
#include <errno.h>
 
55
#include <locale.h>
 
56
#ifndef USE_UKFS
 
57
#include <fts.h>
 
58
#endif
 
59
#include <grp.h>
 
60
#include <pwd.h>
 
61
#include <stdio.h>
 
62
#include <stdlib.h>
 
63
#include <string.h>
 
64
#include <unistd.h>
 
65
 
 
66
#ifdef USE_UKFS
 
67
#include <rump/ukfs.h>
 
68
 
 
69
#include <fts2fsufts.h>
 
70
#include <fsu_mount.h>
 
71
 
 
72
DECLARE_UKFS(ukfs)
 
73
 
 
74
int
 
75
chown(const char *path, uid_t owner, gid_t group)
 
76
{
 
77
 
 
78
        return ukfs_chown(ukfs, path, owner, group);
 
79
}
 
80
 
 
81
int
 
82
lchown(const char *path, uid_t owner, gid_t group)
 
83
{
 
84
 
 
85
        return ukfs_lchown(ukfs, path, owner, group);
 
86
}
 
87
 
 
88
#endif /* USE_UKFS */
 
89
 
 
90
static void     a_gid(const char *);
 
91
static void     a_uid(const char *);
 
92
static id_t     id(const char *, const char *);
 
93
static void     usage(void);
 
94
 
 
95
static uid_t uid;
 
96
static gid_t gid;
 
97
static int ischown;
 
98
static char *myname;
 
99
 
 
100
int
 
101
main(int argc, char **argv)
 
102
{
 
103
        FTS *ftsp;
 
104
        FTSENT *p;
 
105
        int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag;
 
106
        char *cp;
 
107
        int (*change_owner)(const char *, uid_t, gid_t);
 
108
 
 
109
        (void)setlocale(LC_ALL, "");
 
110
 
 
111
        myname = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv;
 
112
#ifdef USE_UKFS
 
113
        ischown = (myname[6] == 'o' || myname[2] == 'o');
 
114
#else
 
115
        ischown = (myname[2] == 'o');
 
116
#endif
 
117
 
 
118
#ifdef USE_UKFS
 
119
        FSU_MOUNT(argc, argv, ukfs);
 
120
#endif
 
121
 
 
122
        Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
 
123
        while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
 
124
                switch (ch) {
 
125
                case 'H':
 
126
                        Hflag = 1;
 
127
                        Lflag = 0;
 
128
                        break;
 
129
                case 'L':
 
130
                        Lflag = 1;
 
131
                        Hflag = 0;
 
132
                        break;
 
133
                case 'P':
 
134
                        Hflag = Lflag = 0;
 
135
                        break;
 
136
                case 'R':
 
137
                        Rflag = 1;
 
138
                        break;
 
139
                case 'f':
 
140
                        fflag = 1;
 
141
                        break;
 
142
                case 'h':
 
143
                        /*
 
144
                         * In System V the -h option causes chown/chgrp to
 
145
                         * change the owner/group of the symbolic link.
 
146
                         * 4.4BSD's symbolic links didn't have owners/groups,
 
147
                         * so it was an undocumented noop.
 
148
                         * In NetBSD 1.3, lchown(2) is introduced.
 
149
                         */
 
150
                        hflag = 1;
 
151
                        break;
 
152
                case 'v':
 
153
                        vflag = 1;
 
154
                        break;
 
155
                case '?':
 
156
                default:
 
157
                        usage();
 
158
                }
 
159
        argv += optind;
 
160
        argc -= optind;
 
161
 
 
162
        if (argc < 2)
 
163
                usage();
 
164
 
 
165
        fts_options = FTS_PHYSICAL;
 
166
        if (Rflag) {
 
167
                if (Hflag)
 
168
                        fts_options |= FTS_COMFOLLOW;
 
169
                if (Lflag) {
 
170
                        if (hflag)
 
171
                                errx(EXIT_FAILURE,
 
172
                                    "the -L and -h options "
 
173
                                    "may not be specified together.");
 
174
                        fts_options &= ~FTS_PHYSICAL;
 
175
                        fts_options |= FTS_LOGICAL;
 
176
                }
 
177
        } else if (!hflag)
 
178
                fts_options |= FTS_COMFOLLOW;
 
179
 
 
180
        uid = (uid_t)-1;
 
181
        gid = (gid_t)-1;
 
182
        if (ischown) {
 
183
                if ((cp = strchr(*argv, ':')) != NULL) {
 
184
                        *cp++ = '\0';
 
185
                        a_gid(cp);
 
186
                }
 
187
#ifdef SUPPORT_DOT
 
188
                else if ((cp = strrchr(*argv, '.')) != NULL) {
 
189
                        if (uid_from_user(*argv, &uid) == -1) {
 
190
                                *cp++ = '\0';
 
191
                                a_gid(cp);
 
192
                        }
 
193
                }
 
194
#endif
 
195
                a_uid(*argv);
 
196
        } else
 
197
                a_gid(*argv);
 
198
 
 
199
        if ((ftsp = fts_open(++argv, fts_options, NULL)) == NULL)
 
200
                err(EXIT_FAILURE, "fts_open");
 
201
 
 
202
        for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) {
 
203
                change_owner = chown;
 
204
                switch (p->fts_info) {
 
205
                case FTS_D:
 
206
                        if (!Rflag)             /* Change it at FTS_DP. */
 
207
                                fts_set(ftsp, p, FTS_SKIP);
 
208
                        continue;
 
209
                case FTS_DNR:                   /* Warn, chown, continue. */
 
210
                        warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
 
211
                        rval = EXIT_FAILURE;
 
212
                        break;
 
213
                case FTS_ERR:                   /* Warn, continue. */
 
214
                case FTS_NS:
 
215
                        warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
 
216
                        rval = EXIT_FAILURE;
 
217
                        continue;
 
218
                case FTS_SL:                    /* Ignore unless -h. */
 
219
                        /*
 
220
                         * All symlinks we found while doing a physical
 
221
                         * walk end up here.
 
222
                         */
 
223
                        if (!hflag)
 
224
                                continue;
 
225
                        /*
 
226
                         * Note that if we follow a symlink, fts_info is
 
227
                         * not FTS_SL but FTS_F or whatever.  And we should
 
228
                         * use lchown only for FTS_SL and should use chown
 
229
                         * for others.
 
230
                         */
 
231
                        change_owner = lchown;
 
232
                        break;
 
233
                case FTS_SLNONE:                /* Ignore. */
 
234
                        /*
 
235
                         * The only symlinks that end up here are ones that
 
236
                         * don't point to anything.  Note that if we are
 
237
                         * doing a phisycal walk, we never reach here unless
 
238
                         * we asked to follow explicitly.
 
239
                         */
 
240
                        continue;
 
241
                default:
 
242
                        break;
 
243
                }
 
244
 
 
245
                if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
 
246
                        warn("%s", p->fts_path);
 
247
                        rval = EXIT_FAILURE;
 
248
                } else {
 
249
                        if (vflag)
 
250
                                printf("%s\n", p->fts_path);
 
251
                }
 
252
        }
 
253
        if (errno)
 
254
                err(EXIT_FAILURE, "fts_read");
 
255
        exit(rval);
 
256
        /* NOTREACHED */
 
257
}
 
258
 
 
259
static void
 
260
a_gid(const char *s)
 
261
{
 
262
        struct group *gr;
 
263
 
 
264
        if (*s == '\0')                 /* Argument was "uid[:.]". */
 
265
                return;
 
266
        gr = *s == '#' ? NULL : getgrnam(s);
 
267
        if (gr == NULL)
 
268
                gid = id(s, "group");
 
269
        else
 
270
                gid = gr->gr_gid;
 
271
        return;
 
272
}
 
273
 
 
274
static void
 
275
a_uid(const char *s)
 
276
{
 
277
        if (*s == '\0')                 /* Argument was "[:.]gid". */
 
278
                return;
 
279
        if (*s == '#' || uid_from_user(s, &uid) == -1) {
 
280
                uid = id(s, "user");
 
281
        }
 
282
        return;
 
283
}
 
284
 
 
285
static id_t
 
286
id(const char *name, const char *type)
 
287
{
 
288
        id_t val;
 
289
        char *ep;
 
290
 
 
291
        errno = 0;
 
292
        if (*name == '#')
 
293
                name++;
 
294
        val = (id_t)strtoul(name, &ep, 10);
 
295
        if (errno)
 
296
                err(EXIT_FAILURE, "%s", name);
 
297
        if (*ep != '\0')
 
298
                errx(EXIT_FAILURE, "%s: invalid %s name", name, type);
 
299
        return (val);
 
300
}
 
301
 
 
302
static void
 
303
usage(void)
 
304
{
 
305
#ifdef USE_UKFS
 
306
        (void)fprintf(stderr,
 
307
                      "usage: %s %s [-R [-H | -L | -P]] [-fhv] %s file ...\n",
 
308
                      myname, fsu_mount_usage(),
 
309
                      ischown ? "[owner][:group]" : "group");
 
310
#else
 
311
 
 
312
        (void)fprintf(stderr,
 
313
            "usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n",
 
314
            myname, ischown ? "[owner][:group]" : "group");
 
315
#endif
 
316
        exit(EXIT_FAILURE);
 
317
}