file_cmds-202.2.tar.gz
[apple/file_cmds.git] / chflags / chflags.c
1 /*-
2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #if 0
31 #ifndef lint
32 static const char copyright[] =
33 "@(#) Copyright (c) 1992, 1993, 1994\n\
34 The Regents of the University of California. All rights reserved.\n";
35 #endif
36
37 #ifndef lint
38 static char sccsid[] = "@(#)chflags.c 8.5 (Berkeley) 4/1/94";
39 #endif
40 #endif
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD: src/bin/chflags/chflags.c,v 1.23 2005/05/14 23:23:10 dd Exp $");
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47
48 #include <err.h>
49 #include <errno.h>
50 #include <fts.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55
56 void usage(void);
57
58 int
59 main(int argc, char *argv[])
60 {
61 FTS *ftsp;
62 FTSENT *p;
63 u_long clear, set;
64 long val;
65 int Hflag, Lflag, Rflag, hflag, ch, fts_options, oct, rval;
66 char *flags, *ep;
67 int (*change_flags)(const char *, u_int);
68
69 Hflag = Lflag = Rflag = hflag = 0;
70 #ifdef __APPLE__
71 while ((ch = getopt(argc, argv, "HLPR")) != -1)
72 #else /* !__APPLE__ */
73 while ((ch = getopt(argc, argv, "HLPRh")) != -1)
74 #endif /* __APPLE__ */
75 switch (ch) {
76 case 'H':
77 Hflag = 1;
78 Lflag = 0;
79 break;
80 case 'L':
81 Lflag = 1;
82 Hflag = 0;
83 break;
84 case 'P':
85 Hflag = Lflag = 0;
86 break;
87 case 'R':
88 Rflag = 1;
89 break;
90 #ifndef __APPLE__
91 case 'h':
92 hflag = 1;
93 break;
94 #endif /* !__APPLE__ */
95 case '?':
96 default:
97 usage();
98 }
99 argv += optind;
100 argc -= optind;
101
102 if (argc < 2)
103 usage();
104
105 if (Rflag) {
106 fts_options = FTS_PHYSICAL;
107 if (hflag)
108 errx(1, "the -R and -h options "
109 "may not be specified together");
110 if (Hflag)
111 fts_options |= FTS_COMFOLLOW;
112 if (Lflag) {
113 fts_options &= ~FTS_PHYSICAL;
114 fts_options |= FTS_LOGICAL;
115 }
116 } else
117 fts_options = FTS_LOGICAL;
118
119 /* XXX: Why don't chflags and lchflags have compatible prototypes? */
120 #ifndef __APPLE__
121 if (hflag)
122 change_flags = (int (*)(const char *, u_int))lchflags;
123 else
124 #endif /* !__APPLE__ */
125 change_flags = chflags;
126
127 flags = *argv;
128 if (*flags >= '0' && *flags <= '7') {
129 errno = 0;
130 val = strtol(flags, &ep, 8);
131 if (val < 0)
132 errno = ERANGE;
133 if (errno)
134 err(1, "invalid flags: %s", flags);
135 if (*ep)
136 errx(1, "invalid flags: %s", flags);
137 set = val;
138 oct = 1;
139 } else {
140 if (strtofflags(&flags, &set, &clear))
141 errx(1, "invalid flag: %s", flags);
142 clear = ~clear;
143 oct = 0;
144 }
145
146 if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
147 err(1, NULL);
148
149 for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
150 switch (p->fts_info) {
151 case FTS_D: /* Change it at FTS_DP if we're recursive. */
152 if (!Rflag)
153 fts_set(ftsp, p, FTS_SKIP);
154 continue;
155 case FTS_DNR: /* Warn, chflag, continue. */
156 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
157 rval = 1;
158 break;
159 case FTS_ERR: /* Warn, continue. */
160 case FTS_NS:
161 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
162 rval = 1;
163 continue;
164 case FTS_SL: /* Ignore. */
165 case FTS_SLNONE:
166 /*
167 * The only symlinks that end up here are ones that
168 * don't point to anything and ones that we found
169 * doing a physical walk.
170 */
171 if (!hflag)
172 continue;
173 /* FALLTHROUGH */
174 default:
175 break;
176 }
177 if (oct) {
178 if (!(*change_flags)(p->fts_accpath, set))
179 continue;
180 } else {
181 p->fts_statp->st_flags |= set;
182 p->fts_statp->st_flags &= clear;
183 if (!(*change_flags)(p->fts_accpath,
184 (u_long)p->fts_statp->st_flags))
185 continue;
186 }
187 warn("%s", p->fts_path);
188 rval = 1;
189 }
190 if (errno)
191 err(1, "fts_read");
192 exit(rval);
193 }
194
195 void
196 usage(void)
197 {
198 (void)fprintf(stderr,
199 #ifdef __APPLE__
200 "usage: chflags [-R [-H | -L | -P]] flags file ...\n");
201 #else /* !__APPLE__ */
202 "usage: chflags [-h] [-R [-H | -L | -P]] flags file ...\n");
203 #endif /* __APPLE__ */
204 exit(1);
205 }