chflags.c revision 1.10 1 /* $NetBSD: chflags.c,v 1.10 2003/08/07 11:13:17 agc Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)chflags.c 8.5 (Berkeley) 4/1/94";
41 #else
42 __RCSID("$NetBSD: chflags.c,v 1.10 2003/08/07 11:13:17 agc Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48
49 #include <err.h>
50 #include <errno.h>
51 #include <fts.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "stat_flags.h"
58
59 int main __P((int, char **));
60 void usage __P((void));
61
62 int
63 main(argc, argv)
64 int argc;
65 char *argv[];
66 {
67 FTS *ftsp;
68 FTSENT *p;
69 u_long clear, set, newflags;
70 long val;
71 int Hflag, Lflag, Rflag, ch, fts_options, hflag, oct, rval;
72 char *flags, *ep;
73 int (*change_flags) __P((const char *, u_long));
74
75 Hflag = Lflag = Rflag = hflag = 0;
76 while ((ch = getopt(argc, argv, "HLPRh")) != -1)
77 switch (ch) {
78 case 'H':
79 Hflag = 1;
80 Lflag = 0;
81 break;
82 case 'L':
83 Lflag = 1;
84 Hflag = 0;
85 break;
86 case 'P':
87 Hflag = Lflag = 0;
88 break;
89 case 'R':
90 Rflag = 1;
91 break;
92 case 'h':
93 hflag = 1;
94 break;
95 case '?':
96 default:
97 usage();
98 }
99 argv += optind;
100 argc -= optind;
101
102 if (argc < 2)
103 usage();
104
105 fts_options = FTS_PHYSICAL;
106 if (Rflag) {
107 if (Hflag)
108 fts_options |= FTS_COMFOLLOW;
109 if (Lflag) {
110 fts_options &= ~FTS_PHYSICAL;
111 fts_options |= FTS_LOGICAL;
112 }
113 } else if (!hflag)
114 fts_options |= FTS_COMFOLLOW;
115
116 flags = *argv;
117 if (*flags >= '0' && *flags <= '7') {
118 errno = 0;
119 val = strtol(flags, &ep, 8);
120 if (val < 0)
121 errno = ERANGE;
122 if (errno)
123 err(1, "invalid flags: %s", flags);
124 if (*ep)
125 errx(1, "invalid flags: %s", flags);
126 set = val;
127 oct = 1;
128 } else {
129 if (string_to_flags(&flags, &set, &clear))
130 errx(1, "invalid flag: %s", flags);
131 clear = ~clear;
132 oct = 0;
133 }
134
135 if ((ftsp = fts_open(++argv, fts_options, NULL)) == NULL)
136 err(1, "fts_open");
137
138 for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
139 change_flags = chflags;
140 switch (p->fts_info) {
141 case FTS_D:
142 if (Rflag) /* Change it at FTS_DP. */
143 continue;
144 fts_set(ftsp, p, FTS_SKIP);
145 break;
146 case FTS_DNR: /* Warn, chflag, continue. */
147 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
148 rval = 1;
149 break;
150 case FTS_ERR: /* Warn, continue. */
151 case FTS_NS:
152 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
153 rval = 1;
154 continue;
155 case FTS_SL: /* Ignore unless -h. */
156 /*
157 * All symlinks we found while doing a physical
158 * walk end up here.
159 */
160 if (!hflag)
161 continue;
162 /*
163 * Note that if we follow a symlink, fts_info is
164 * not FTS_SL but FTS_F or whatever. And we should
165 * use lchflags only for FTS_SL and should use chflags
166 * for others.
167 */
168 change_flags = lchflags;
169 break;
170 case FTS_SLNONE: /* Ignore. */
171 /*
172 * The only symlinks that end up here are ones that
173 * don't point to anything. Note that if we are
174 * doing a phisycal walk, we never reach here unless
175 * we asked to follow explicitly.
176 */
177 continue;
178 default:
179 break;
180 }
181 if (oct)
182 newflags = set;
183 else {
184 newflags = p->fts_statp->st_flags;
185 newflags |= set;
186 newflags &= clear;
187 }
188 if ((*change_flags)(p->fts_accpath, newflags)) {
189 warn("%s", p->fts_path);
190 rval = 1;
191 }
192 }
193 if (errno)
194 err(1, "fts_read");
195 exit(rval);
196 }
197
198 void
199 usage()
200 {
201
202 (void)fprintf(stderr,
203 "usage: chflags [-R [-H | -L | -P]] [-h] flags file ...\n");
204 exit(1);
205 }
206