summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsmh <smh@FreeBSD.org>2015-06-01 09:04:57 +0000
committersmh <smh@FreeBSD.org>2015-06-01 09:04:57 +0000
commit32367258066d8eaccf6cc78014ae74b397db7e4b (patch)
tree98f751cb965bcce0515d566fa6ed7a433f62a1b8
parent082794a940f23e7eb4f7f03d5fbe9ba4fdd1fe60 (diff)
downloadFreeBSD-src-32367258066d8eaccf6cc78014ae74b397db7e4b.zip
FreeBSD-src-32367258066d8eaccf6cc78014ae74b397db7e4b.tar.gz
MFC r282208:
Standardise chmod, chflags, chown and chgrp recursive symlink processing Relnotes: Yes Sponsored by: Multiplay
-rw-r--r--UPDATING4
-rw-r--r--bin/chflags/chflags.115
-rw-r--r--bin/chflags/chflags.c51
-rw-r--r--bin/chmod/chmod.114
-rw-r--r--bin/chmod/chmod.c90
-rw-r--r--usr.sbin/chown/chgrp.115
-rw-r--r--usr.sbin/chown/chown.811
-rw-r--r--usr.sbin/chown/chown.c106
8 files changed, 164 insertions, 142 deletions
diff --git a/UPDATING b/UPDATING
index 85192e9..f76d504 100644
--- a/UPDATING
+++ b/UPDATING
@@ -16,6 +16,10 @@ from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of
stable/10, and then rebuild without this option. The bootstrap process from
older version of current is a bit fragile.
+20150601:
+ chmod, chflags, chown and chgrp now affect symlinks in -R mode as
+ defined in symlink(7); previously symlinks were silently ignored.
+
20150430:
The const qualifier has been removed from iconv(3) to comply with
POSIX. The ports tree is aware of this from r384038 onwards.
diff --git a/bin/chflags/chflags.1 b/bin/chflags/chflags.1
index 47d5b18..755cbce 100644
--- a/bin/chflags/chflags.1
+++ b/bin/chflags/chflags.1
@@ -32,7 +32,7 @@
.\" @(#)chflags.1 8.4 (Berkeley) 5/2/95
.\" $FreeBSD$
.\"
-.Dd April 8, 2013
+.Dd April 20, 2015
.Dt CHFLAGS 1
.Os
.Sh NAME
@@ -66,8 +66,9 @@ nor modify the exit status to reflect such failures.
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl h
If the
.Ar file
@@ -83,8 +84,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the file flags for the file hierarchies rooted
-in the files instead of just the files themselves.
+Change the file flags of the file hierarchies rooted in the files,
+instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl v
Cause
.Nm
diff --git a/bin/chflags/chflags.c b/bin/chflags/chflags.c
index e94c34d..2029ac5 100644
--- a/bin/chflags/chflags.c
+++ b/bin/chflags/chflags.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
@@ -65,7 +66,6 @@ main(int argc, char *argv[])
int Hflag, Lflag, Rflag, fflag, hflag, vflag;
int ch, fts_options, oct, rval;
char *flags, *ep;
- int (*change_flags)(const char *, unsigned long);
Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
@@ -104,20 +104,23 @@ main(int argc, char *argv[])
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag)
- errx(1, "the -R and -h options "
- "may not be specified together");
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
+ errx(1, "the -R and -h options may not be "
+ "specified together.");
if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
- }
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
- change_flags = hflag ? lchflags : chflags;
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
+ }
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
flags = *argv;
if (*flags >= '0' && *flags <= '7') {
@@ -142,12 +145,21 @@ main(int argc, char *argv[])
err(1, NULL);
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP if we're recursive. */
if (!Rflag)
fts_set(ftsp, p, FTS_SKIP);
continue;
- case FTS_DNR: /* Warn, chflag, continue. */
+ case FTS_DNR: /* Warn, chflags. */
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
break;
@@ -156,16 +168,6 @@ main(int argc, char *argv[])
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL: /* Ignore. */
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (!hflag)
- continue;
- /* FALLTHROUGH */
default:
break;
}
@@ -175,7 +177,8 @@ main(int argc, char *argv[])
newflags = (p->fts_statp->st_flags | set) & clear;
if (newflags == p->fts_statp->st_flags)
continue;
- if ((*change_flags)(p->fts_accpath, newflags) && !fflag) {
+ if (chflagsat(AT_FDCWD, p->fts_accpath, newflags,
+ atflag) == -1 && !fflag) {
warn("%s", p->fts_path);
rval = 1;
} else if (vflag) {
diff --git a/bin/chmod/chmod.1 b/bin/chmod/chmod.1
index 34a1ff0..7efaabc 100644
--- a/bin/chmod/chmod.1
+++ b/bin/chmod/chmod.1
@@ -32,7 +32,7 @@
.\" @(#)chmod.1 8.4 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd January 26, 2009
+.Dd April 20, 2015
.Dt CHMOD 1
.Os
.Sh NAME
@@ -63,9 +63,9 @@ nor modify the exit status to reflect such failures.
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed by
-default.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during tree traversal are not followed.)
.It Fl h
If the file is a symbolic link, change the mode of the link itself
rather than the file that the link points to.
@@ -79,8 +79,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the modes of the file hierarchies rooted in the files
+Change the modes of the file hierarchies rooted in the files,
instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl v
Cause
.Nm
diff --git a/bin/chmod/chmod.c b/bin/chmod/chmod.c
index dc51faa..9b80157 100644
--- a/bin/chmod/chmod.c
+++ b/bin/chmod/chmod.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <limits.h>
#include <stdio.h>
@@ -62,7 +63,7 @@ main(int argc, char *argv[])
FTS *ftsp;
FTSENT *p;
mode_t *set;
- int Hflag, Lflag, Rflag, ch, error, fflag, fts_options, hflag, rval;
+ int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
int vflag;
char *mode;
mode_t newmode;
@@ -126,18 +127,23 @@ done: argv += optind;
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag)
- errx(1,
- "the -R and -h options may not be specified together.");
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
+ errx(1, "the -R and -h options may not be "
+ "specified together.");
if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
+
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
}
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
mode = *argv;
if ((set = setmode(mode)) == NULL)
@@ -146,12 +152,21 @@ done: argv += optind;
if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
err(1, "fts_open");
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP. */
if (!Rflag)
fts_set(ftsp, p, FTS_SKIP);
continue;
- case FTS_DNR: /* Warn, chmod, continue. */
+ case FTS_DNR: /* Warn, chmod. */
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
break;
@@ -160,16 +175,6 @@ done: argv += optind;
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL: /* Ignore. */
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (!hflag)
- continue;
- /* FALLTHROUGH */
default:
break;
}
@@ -182,32 +187,25 @@ done: argv += optind;
if (may_have_nfs4acl(p, hflag) == 0 &&
(newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
continue;
- if (hflag)
- error = lchmod(p->fts_accpath, newmode);
- else
- error = chmod(p->fts_accpath, newmode);
- if (error) {
- if (!fflag) {
- warn("%s", p->fts_path);
- rval = 1;
- }
- } else {
- if (vflag) {
- (void)printf("%s", p->fts_path);
-
- 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");
+ if (fchmodat(AT_FDCWD, p->fts_accpath, newmode, atflag) == -1
+ && !fflag) {
+ warn("%s", p->fts_path);
+ rval = 1;
+ } else if (vflag) {
+ (void)printf("%s", p->fts_path);
+
+ 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");
}
}
if (errno)
diff --git a/usr.sbin/chown/chgrp.1 b/usr.sbin/chown/chgrp.1
index 8a4c271..6fb0a31 100644
--- a/usr.sbin/chown/chgrp.1
+++ b/usr.sbin/chown/chgrp.1
@@ -31,7 +31,7 @@
.\" @(#)chgrp.1 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd April 20, 2015
.Dt CHGRP 1
.Os
.Sh NAME
@@ -60,8 +60,9 @@ The following options are available:
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl L
If the
.Fl R
@@ -72,8 +73,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the group ID for the file hierarchies rooted
-in the files instead of just the files themselves.
+Change the group ID of the file hierarchies rooted in the files,
+instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl f
The force option ignores errors, except for usage errors and does not
query about strange modes (unless the user does not have proper permissions).
diff --git a/usr.sbin/chown/chown.8 b/usr.sbin/chown/chown.8
index b5882a3..6b82728 100644
--- a/usr.sbin/chown/chown.8
+++ b/usr.sbin/chown/chown.8
@@ -28,7 +28,7 @@
.\" @(#)chown.8 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd April 20, 2015
.Dt CHOWN 8
.Os
.Sh NAME
@@ -64,8 +64,9 @@ The options are as follows:
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl L
If the
.Fl R
@@ -76,8 +77,8 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the user ID and/or the group ID of the specified directory trees
-(recursively, including their contents) and files.
+Change the user ID and/or the group ID of the file hierarchies rooted
+in the files, instead of just the files themselves.
Beware of unintentionally matching the
.Dq Pa ".."
hard link to the parent directory when using wildcards like
diff --git a/usr.sbin/chown/chown.c b/usr.sbin/chown/chown.c
index 9780f02..457068a 100644
--- a/usr.sbin/chown/chown.c
+++ b/usr.sbin/chown/chown.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <grp.h>
#include <libgen.h>
@@ -119,18 +120,24 @@ main(int argc, char **argv)
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag && (Hflag || Lflag))
errx(1, "the -R%c and -h options may not be "
"specified together", Hflag ? 'H' : 'L');
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
- else if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
+ if (Lflag) {
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
+
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
}
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
+
if (xflag)
fts_options |= FTS_XDEV;
@@ -156,6 +163,15 @@ main(int argc, char **argv)
err(1, NULL);
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP. */
if (!Rflag)
@@ -170,58 +186,44 @@ main(int argc, char **argv)
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL:
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (hflag)
- break;
- else
- continue;
default:
break;
}
if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
(gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
continue;
- if ((hflag ? lchown : chown)(p->fts_accpath, uid, gid) == -1) {
- if (!fflag) {
- chownerr(p->fts_path);
- rval = 1;
- }
- } else {
- if (vflag) {
- printf("%s", p->fts_path);
- if (vflag > 1) {
- if (ischown) {
- printf(": %ju:%ju -> %ju:%ju",
- (uintmax_t)
- p->fts_statp->st_uid,
- (uintmax_t)
- p->fts_statp->st_gid,
- (uid == (uid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_uid :
- (uintmax_t)uid,
- (gid == (gid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_gid :
- (uintmax_t)gid);
- } else {
- printf(": %ju -> %ju",
- (uintmax_t)
- p->fts_statp->st_gid,
- (gid == (gid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_gid :
- (uintmax_t)gid);
- }
+ if (fchownat(AT_FDCWD, p->fts_accpath, uid, gid, atflag)
+ == -1 && !fflag) {
+ chownerr(p->fts_path);
+ rval = 1;
+ } else if (vflag) {
+ printf("%s", p->fts_path);
+ if (vflag > 1) {
+ if (ischown) {
+ printf(": %ju:%ju -> %ju:%ju",
+ (uintmax_t)
+ p->fts_statp->st_uid,
+ (uintmax_t)
+ p->fts_statp->st_gid,
+ (uid == (uid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_uid :
+ (uintmax_t)uid,
+ (gid == (gid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_gid :
+ (uintmax_t)gid);
+ } else {
+ printf(": %ju -> %ju",
+ (uintmax_t)
+ p->fts_statp->st_gid,
+ (gid == (gid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_gid :
+ (uintmax_t)gid);
}
- printf("\n");
}
+ printf("\n");
}
}
if (errno)
OpenPOWER on IntegriCloud