-/* $NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $ */
-
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#ifndef lint
-__COPYRIGHT(
+static char const copyright[] =
"@(#) Copyright (c) 1989, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n");
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94";
-#else
-__RCSID("$NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $");
#endif
#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/chmod/chmod.c,v 1.27 2002/08/04 05:29:13 obrien Exp $");
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
-#include <locale.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <limits.h>
-int main __P((int, char *[]));
-void usage __P((void));
+#ifdef __APPLE__
+#include "chmod_acl.h"
+
+#endif /*__APPLE__*/
+
+int fflag = 0;
+
+int main(int, char *[]);
+void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
- FTS *ftsp;
- FTSENT *p;
- mode_t *set;
- long val;
- int oct, omode;
- int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
+ FTS *ftsp = NULL;
+ FTSENT *p = NULL;
+ mode_t *set = NULL;
+ long val = 0;
+ int oct = 0;
+ int Hflag, Lflag, Pflag, Rflag, ch, fts_options, hflag, rval;
+ int vflag;
char *ep, *mode;
- int (*change_mode) __P((const char *, mode_t));
+ mode_t newmode, omode;
+#ifdef __APPLE__
+ unsigned int acloptflags = 0;
+ long aclpos = -1;
+ int inheritance_level = 0;
+ int index = 0;
+ size_t acloptlen = 0;
+ int ace_arg_not_required = 0;
+ acl_t acl_input = NULL;
+#endif /* __APPLE__*/
+ int (*change_mode)(const char *, mode_t);
- set = NULL; /* XXX gcc -Wuninitialized */
- omode = 0; /* XXX gcc -Wuninitialized */
-
- (void)setlocale(LC_ALL, "");
-
- Hflag = Lflag = Rflag = fflag = hflag = 0;
- while ((ch = getopt(argc, argv, "HLPRXfghorstuwx")) != -1)
+ set = NULL;
+ omode = 0;
+ Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "ACEHILNPRVXafghinorstuvwx")) != -1)
+#endif
switch (ch) {
case 'H':
Hflag = 1;
Lflag = 0;
+ Pflag = 0;
break;
case 'L':
Lflag = 1;
Hflag = 0;
+ Pflag = 0;
break;
case 'P':
Hflag = Lflag = 0;
+ Pflag = 1;
break;
case 'R':
Rflag = 1;
break;
- case 'f': /* XXX: undocumented. */
+ case 'f':
fflag = 1;
break;
-#ifndef __APPLE__
case 'h':
/*
* In System V (and probably POSIX.2) the -h option
* causes chmod to change the mode of the symbolic
* link. 4.4BSD's symbolic links didn't have modes,
- * so it was an undocumented noop. In NetBSD 1.3,
+ * so it was an undocumented noop. In FreeBSD 3.0,
* lchmod(2) is introduced and this option does real
* work.
*/
hflag = 1;
break;
-#endif
+#ifdef __APPLE__
+ case 'a':
+ if (argv[optind - 1][0] == '-' &&
+ argv[optind - 1][1] == ch)
+ --optind;
+ goto done;
+ case 'A':
+// acloptflags |= ACL_FLAG | ACL_TO_STDOUT;
+// ace_arg_not_required = 1;
+ errx(1, "-A not implemented");
+ goto done;
+ case 'E':
+ acloptflags |= ACL_FLAG | ACL_FROM_STDIN;
+ goto done;
+ case 'C':
+ acloptflags |= ACL_FLAG | ACL_CHECK_CANONICITY;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'i':
+ acloptflags |= ACL_FLAG | ACL_REMOVE_INHERIT_FLAG;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'I':
+ acloptflags |= ACL_FLAG | ACL_REMOVE_INHERITED_ENTRIES;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'n':
+ acloptflags |= ACL_FLAG | ACL_NO_TRANSLATE;
+ break;
+ case 'N':
+ acloptflags |= ACL_FLAG | ACL_CLEAR_FLAG;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'V':
+// acloptflags |= ACL_FLAG | ACL_INVOKE_EDITOR;
+// ace_arg_not_required = 1;
+ errx(1, "-V not implemented");
+ goto done;
+#endif /* __APPLE__ */
/*
* XXX
* "-[rwx]" are valid mode commands. If they are the entire
argv[optind - 1][2] == '\0')
--optind;
goto done;
+ case 'v':
+ vflag++;
+ break;
case '?':
default:
usage();
done: argv += optind;
argc -= optind;
+#ifdef __APPLE__
+ if (argc < ((acloptflags & ACL_FLAG) ? 1 : 2))
+ usage();
+ if (!Rflag && (Hflag || Lflag || Pflag))
+ warnx("options -H, -L, -P only useful with -R");
+#else /* !__APPLE__ */
if (argc < 2)
usage();
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ if (!(acloptflags & ACL_FLAG) && ((acloptlen = strlen(argv[0])) > 1) && (argv[0][1] == 'a')) {
+ acloptflags |= ACL_FLAG;
+ switch (argv[0][0]) {
+ case '+':
+ acloptflags |= ACL_SET_FLAG;
+ break;
+ case '-':
+ acloptflags |= ACL_DELETE_FLAG;
+ break;
+ case '=':
+ acloptflags |= ACL_REWRITE_FLAG;
+ break;
+ default:
+ acloptflags &= ~ACL_FLAG;
+ goto apnoacl;
+ }
+
+ if (argc < 3)
+ usage();
+
+ if (acloptlen > 2) {
+ for (index = 2; index < acloptlen; index++) {
+ switch (argv[0][index]) {
+ case '#':
+ acloptflags |= ACL_ORDER_FLAG;
+
+ if (argc < ((acloptflags & ACL_DELETE_FLAG)
+ ? 3 : 4))
+ usage();
+ argv++;
+ argc--;
+ errno = 0;
+ aclpos = strtol(argv[0], &ep, 0);
+
+ if (aclpos > ACL_MAX_ENTRIES
+ || aclpos < 0)
+ errno = ERANGE;
+ if (errno || *ep)
+ errx(1, "Invalid ACL entry number: %ld", aclpos);
+ if (acloptflags & ACL_DELETE_FLAG)
+ ace_arg_not_required = 1;
+
+ goto apdone;
+ case 'i':
+ acloptflags |= ACL_INHERIT_FLAG;
+ /* The +aii.. syntax to specify
+ * inheritance level is rather unwieldy,
+ * find an alternative.
+ */
+ inheritance_level++;
+ if (inheritance_level > 1)
+ warnx("Inheritance across more than one generation is not currently supported");
+ if (inheritance_level >= MAX_INHERITANCE_LEVEL)
+ goto apdone;
+ break;
+ default:
+ errno = EINVAL;
+ usage();
+ }
+ }
+ }
+apdone:
+ argv++;
+ argc--;
+ }
+apnoacl:
+#endif /*__APPLE__*/
- fts_options = FTS_PHYSICAL;
if (Rflag) {
+ fts_options = FTS_PHYSICAL;
if (hflag)
errx(1,
"the -R and -h options may not be specified together.");
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
}
- }
-#ifndef __APPLE__
+ } else
+ fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+
if (hflag)
change_mode = lchmod;
else
- change_mode = chmod;
-#else
- change_mode = chmod;
-#endif
-
- mode = *argv;
- if (*mode >= '0' && *mode <= '7') {
- errno = 0;
- val = strtol(mode, &ep, 8);
- if (val > INT_MAX || val < 0)
- errno = ERANGE;
- if (errno)
- err(1, "invalid file mode: %s", mode);
- if (*ep)
- errx(1, "invalid file mode: %s", mode);
- omode = val;
- oct = 1;
- } else {
- if ((set = setmode(mode)) == NULL)
- errx(1, "invalid file mode: %s", mode);
- oct = 0;
+ change_mode = chmod;
+#ifdef __APPLE__
+ if (acloptflags & ACL_FROM_STDIN) {
+ ssize_t readval = 0;
+ size_t readtotal = 0;
+
+ mode = (char *) malloc(MAX_ACL_TEXT_SIZE);
+
+ if (mode == NULL)
+ err(1, "Unable to allocate mode string");
+ /* Read the ACEs from STDIN */
+ do {
+ readtotal += readval;
+ readval = read(STDIN_FILENO, mode + readtotal,
+ MAX_ACL_TEXT_SIZE);
+ } while ((readval > 0) && (readtotal <= MAX_ACL_TEXT_SIZE));
+
+ if (0 == readtotal)
+ errx(1, "-E specified, but read from STDIN failed");
+ else
+ mode[readtotal - 1] = '\0';
+ --argv;
}
+ else
+#endif /* __APPLE */
+ mode = *argv;
+#ifdef __APPLE__
+ if ((acloptflags & ACL_FLAG)) {
+
+ /* Are we deleting by entry number, verifying
+ * canonicity or performing some other operation that
+ * does not require an input entry? If so, there's no
+ * entry to convert.
+ */
+ if (ace_arg_not_required) {
+ --argv;
+ }
+ else {
+ /* Parse the text into an ACL*/
+ acl_input = parse_acl_entries(mode);
+ if (acl_input == NULL) {
+ errx(1, "Invalid ACL specification: %s", mode);
+ }
+ }
+ }
+ else {
+#endif /* __APPLE__*/
+ if (*mode >= '0' && *mode <= '7') {
+ errno = 0;
+ val = strtol(mode, &ep, 8);
+ if (val > USHRT_MAX || val < 0)
+ errno = ERANGE;
+ if (errno)
+ err(1, "Invalid file mode: %s", mode);
+ if (*ep)
+ errx(1, "Invalid file mode: %s", mode);
+ omode = (mode_t)val;
+ oct = 1;
+ } else {
+ if ((set = setmode(mode)) == NULL)
+ errx(1, "Invalid file mode: %s", mode);
+ oct = 0;
+ }
+#ifdef __APPLE__
+ }
+#endif /* __APPLE__*/
if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
- err(1, argv[0]);
+ err(1, "fts_open");
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
switch (p->fts_info) {
case FTS_D:
break;
case FTS_DP: /* Already changed at FTS_D. */
continue;
- case FTS_ERR: /* Warn, continue. */
case FTS_NS:
+ if (acloptflags & ACL_FLAG) /* don't need stat for -N */
+ break;
+ case FTS_ERR: /* Warn, continue. */
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
* don't point to anything and ones that we found
* doing a physical walk.
*/
-#ifndef __APPLE__
if (!hflag)
continue;
/* else */
/* FALLTHROUGH */
-#else
- continue;
-#endif
default:
break;
}
- if ((*change_mode)(p->fts_accpath, oct ? omode :
- getmode(set, p->fts_statp->st_mode)) && !fflag) {
- warn("%s", p->fts_path);
- rval = 1;
+#ifdef __APPLE__
+/* If an ACL manipulation option was specified, manipulate */
+ if (acloptflags & ACL_FLAG) {
+ if (0 != modify_file_acl(acloptflags, p->fts_accpath, acl_input, (int)aclpos, inheritance_level, !hflag))
+ rval = 1;
+ }
+ else {
+#endif /* __APPLE__ */
+ newmode = oct ? omode : getmode(set, p->fts_statp->st_mode);
+ if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
+ continue;
+ if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
+ warn("Unable to change file mode on %s", p->fts_path);
+ rval = 1;
+ } else {
+ if (vflag) {
+ (void)printf("%s", p->fts_accpath);
+
+ if (vflag > 1) {
+ char m1[12], m2[12];
+
+ strmode(p->fts_statp->st_mode, m1);
+ strmode((p->fts_statp->st_mode &
+ S_IFMT) | newmode, m2);
+
+ (void)printf(": 0%o [%s] -> 0%o [%s]",
+ p->fts_statp->st_mode, m1,
+ (p->fts_statp->st_mode & S_IFMT) |
+ newmode, m2);
+ }
+ (void)printf("\n");
+ }
+
+ }
+#ifdef __APPLE__
}
+#endif /* __APPLE__*/
}
if (errno)
err(1, "fts_read");
+#ifdef __APPLE__
+ if (acl_input)
+ acl_free(acl_input);
+ if (mode && (acloptflags & ACL_FROM_STDIN))
+ free(mode);
+
+#endif /* __APPLE__ */
+ if (set)
+ free(set);
exit(rval);
- /* NOTREACHED */
}
void
-usage()
+usage(void)
{
-#ifndef __APPLE__
+#ifdef __APPLE__
(void)fprintf(stderr,
- "usage: chmod [-R [-H | -L | -P]] [-h] mode file ...\n");
+ "usage:\tchmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a [i][# [ n]]] mode|entry file ...\n"
+ "\tchmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -N | -i | -I] file ...\n"); /* add -A and -V when implemented */
#else
(void)fprintf(stderr,
- "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
-#endif
+ "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n");
+#endif /* __APPLE__ */
exit(1);
- /* NOTREACHED */
}