chflags.c revision 1.12 1 /* $NetBSD: chflags.c,v 1.12 2005/01/20 15:44:59 xtraeme 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.12 2005/01/20 15:44:59 xtraeme 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 void usage(void);
60
61 int
62 main(int argc, char *argv[])
63 {
64 FTS *ftsp;
65 FTSENT *p;
66 u_long clear, set, newflags;
67 long val;
68 int Hflag, Lflag, Rflag, ch, fts_options, hflag, oct, rval;
69 char *flags, *ep;
70 int (*change_flags) __P((const char *, u_long));
71
72 Hflag = Lflag = Rflag = hflag = 0;
73 while ((ch = getopt(argc, argv, "HLPRh")) != -1)
74 switch (ch) {
75 case 'H':
76 Hflag = 1;
77 Lflag = 0;
78 break;
79 case 'L':
80 Lflag = 1;
81 Hflag = 0;
82 break;
83 case 'P':
84 Hflag = Lflag = 0;
85 break;
86 case 'R':
87 Rflag = 1;
88 break;
89 case 'h':
90 hflag = 1;
91 break;
92 case '?':
93 default:
94 usage();
95 }
96 argv += optind;
97 argc -= optind;
98
99 if (argc < 2)
100 usage();
101
102 fts_options = FTS_PHYSICAL;
103 if (Rflag) {
104 if (Hflag)
105 fts_options |= FTS_COMFOLLOW;
106 if (Lflag) {
107 fts_options &= ~FTS_PHYSICAL;
108 fts_options |= FTS_LOGICAL;
109 }
110 } else if (!hflag)
111 fts_options |= FTS_COMFOLLOW;
112
113 flags = *argv;
114 if (*flags >= '0' && *flags <= '7') {
115 errno = 0;
116 val = strtol(flags, &ep, 8);
117 if (val < 0)
118 errno = ERANGE;
119 if (errno)
120 err(1, "invalid flags: %s", flags);
121 if (*ep)
122 errx(1, "invalid flags: %s", flags);
123 set = val;
124 oct = 1;
125 } else {
126 if (string_to_flags(&flags, &set, &clear))
127 errx(1, "invalid flag: %s", flags);
128 clear = ~clear;
129 oct = 0;
130 }
131
132 if ((ftsp = fts_open(++argv, fts_options, NULL)) == NULL)
133 err(1, "fts_open");
134
135 for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
136 change_flags = chflags;
137 switch (p->fts_info) {
138 case FTS_D:
139 if (Rflag) /* Change it at FTS_DP. */
140 continue;
141 fts_set(ftsp, p, FTS_SKIP);
142 break;
143 case FTS_DNR: /* Warn, chflag, continue. */
144 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
145 rval = 1;
146 break;
147 case FTS_ERR: /* Warn, continue. */
148 case FTS_NS:
149 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
150 rval = 1;
151 continue;
152 case FTS_SL: /* Ignore unless -h. */
153 /*
154 * All symlinks we found while doing a physical
155 * walk end up here.
156 */
157 if (!hflag)
158 continue;
159 /*
160 * Note that if we follow a symlink, fts_info is
161 * not FTS_SL but FTS_F or whatever. And we should
162 * use lchflags only for FTS_SL and should use chflags
163 * for others.
164 */
165 change_flags = lchflags;
166 break;
167 case FTS_SLNONE: /* Ignore. */
168 /*
169 * The only symlinks that end up here are ones that
170 * don't point to anything. Note that if we are
171 * doing a phisycal walk, we never reach here unless
172 * we asked to follow explicitly.
173 */
174 continue;
175 default:
176 break;
177 }
178 if (oct)
179 newflags = set;
180 else {
181 newflags = p->fts_statp->st_flags;
182 newflags |= set;
183 newflags &= clear;
184 }
185 if ((*change_flags)(p->fts_accpath, newflags)) {
186 warn("%s", p->fts_path);
187 rval = 1;
188 }
189 }
190 if (errno)
191 err(1, "fts_read");
192 exit(rval);
193 }
194
195 void
196 usage(void)
197 {
198
199 (void)fprintf(stderr,
200 "usage: chflags [-R [-H | -L | -P]] [-h] flags file ...\n");
201 exit(1);
202 }
203