2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 static char const copyright
[] =
33 "@(#) Copyright (c) 1989, 1993, 1994\n\
34 The Regents of the University of California. All rights reserved.\n";
38 static char sccsid
[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94";
41 /*#include <sys/cdefs.h> */
42 /*__FBSDID("$FreeBSD: src/bin/chmod/chmod.c,v 1.33 2005/01/10 08:39:20 imp Exp $");*/
44 #include <sys/types.h>
57 # include "mscfakes.h"
60 #include "kmkbuiltin.h"
62 extern void * bsd_setmode(const char *p
);
63 extern mode_t
bsd_getmode(const void *bbox
, mode_t omode
);
64 extern void bsd_strmode(mode_t mode
, char *p
);
66 #if defined(__APPLE__) && !defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)
67 extern int lchmod(const char *, mode_t
);
70 static int usage(FILE *);
72 static struct option long_options
[] =
74 { "help", no_argument
, 0, 261 },
75 { "version", no_argument
, 0, 262 },
81 kmk_builtin_chmod(int argc
, char *argv
[], char **envp
)
86 int Hflag
, Lflag
, Rflag
, ch
, fflag
, fts_options
, hflag
, rval
;
90 int (*change_mode
)(const char *, mode_t
);
92 /* kmk: reset getopt and set progname */
97 optind
= 0; /* init */
100 Hflag
= Lflag
= Rflag
= fflag
= hflag
= vflag
= 0;
101 while ((ch
= getopt_long(argc
, argv
, "HLPRXfghorstuvwx", long_options
, NULL
)) != -1)
122 * In System V (and probably POSIX.2) the -h option
123 * causes chmod to change the mode of the symbolic
124 * link. 4.4BSD's symbolic links didn't have modes,
125 * so it was an undocumented noop. In FreeBSD 3.0,
126 * lchmod(2) is introduced and this option does real
133 * "-[rwx]" are valid mode commands. If they are the entire
134 * argument, getopt has moved past them, so decrement optind.
135 * Regardless, we're done argument processing.
137 case 'g': case 'o': case 'r': case 's':
138 case 't': case 'u': case 'w': case 'X': case 'x':
139 if (argv
[optind
- 1][0] == '-' &&
140 argv
[optind
- 1][1] == ch
&&
141 argv
[optind
- 1][2] == '\0')
151 return kbuild_version(argv
[0]);
154 return usage(stderr
);
156 done
: argv
+= optind
;
160 return usage(stderr
);
163 fts_options
= FTS_PHYSICAL
;
166 "the -R and -h options may not be specified together.");
168 fts_options
|= FTS_COMFOLLOW
;
170 fts_options
&= ~FTS_PHYSICAL
;
171 fts_options
|= FTS_LOGICAL
;
174 fts_options
= hflag
? FTS_PHYSICAL
: FTS_LOGICAL
;
177 change_mode
= lchmod
;
182 if ((set
= bsd_setmode(mode
)) == NULL
)
183 return errx(1, "invalid file mode: %s", mode
);
185 if ((ftsp
= fts_open(++argv
, fts_options
, 0)) == NULL
)
186 return err(1, "fts_open");
187 for (rval
= 0; (p
= fts_read(ftsp
)) != NULL
;) {
188 switch (p
->fts_info
) {
189 case FTS_D
: /* Change it at FTS_DP. */
191 fts_set(ftsp
, p
, FTS_SKIP
);
193 case FTS_DNR
: /* Warn, chmod, continue. */
194 warnx("%s: %s", p
->fts_path
, strerror(p
->fts_errno
));
197 case FTS_ERR
: /* Warn, continue. */
199 warnx("%s: %s", p
->fts_path
, strerror(p
->fts_errno
));
202 case FTS_SL
: /* Ignore. */
205 * The only symlinks that end up here are ones that
206 * don't point to anything and ones that we found
207 * doing a physical walk.
216 newmode
= bsd_getmode(set
, p
->fts_statp
->st_mode
);
217 if ((newmode
& ALLPERMS
) == (p
->fts_statp
->st_mode
& ALLPERMS
))
219 if ((*change_mode
)(p
->fts_accpath
, newmode
) && !fflag
) {
220 warn("%s", p
->fts_path
);
224 (void)printf("%s", p
->fts_path
);
229 bsd_strmode(p
->fts_statp
->st_mode
, m1
);
230 bsd_strmode((p
->fts_statp
->st_mode
&
231 S_IFMT
) | newmode
, m2
);
233 (void)printf(": 0%o [%s] -> 0%o [%s]",
234 p
->fts_statp
->st_mode
, m1
,
235 (p
->fts_statp
->st_mode
& S_IFMT
) |
244 rval
= err(1, "fts_read");
254 "usage: %s [-fhv] [-R [-H | -L | -P]] mode file ...\n"
255 " or: %s --version\n"
257 g_progname
, g_progname
, g_progname
);