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