Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Jun 2015 09:04:58 +0000 (UTC)
From:      Steven Hartland <smh@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r283875 - in stable/10: . bin/chflags bin/chmod usr.sbin/chown
Message-ID:  <201506010904.t5194wLM047286@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: smh
Date: Mon Jun  1 09:04:57 2015
New Revision: 283875
URL: https://svnweb.freebsd.org/changeset/base/283875

Log:
  MFC r282208:
  Standardise chmod, chflags, chown and chgrp recursive symlink processing
  
  Relnotes:	Yes
  Sponsored by:	Multiplay

Modified:
  stable/10/UPDATING
  stable/10/bin/chflags/chflags.1
  stable/10/bin/chflags/chflags.c
  stable/10/bin/chmod/chmod.1
  stable/10/bin/chmod/chmod.c
  stable/10/usr.sbin/chown/chgrp.1
  stable/10/usr.sbin/chown/chown.8
  stable/10/usr.sbin/chown/chown.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/UPDATING
==============================================================================
--- stable/10/UPDATING	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/UPDATING	Mon Jun  1 09:04:57 2015	(r283875)
@@ -16,6 +16,10 @@ from older versions of FreeBSD, try WITH
 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.

Modified: stable/10/bin/chflags/chflags.1
==============================================================================
--- stable/10/bin/chflags/chflags.1	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/bin/chflags/chflags.1	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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 su
 .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

Modified: stable/10/bin/chflags/chflags.c
==============================================================================
--- stable/10/bin/chflags/chflags.c	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/bin/chflags/chflags.c	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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;
+			fts_options = FTS_LOGICAL;
+		} else {
+			fts_options = FTS_PHYSICAL;
+
+			if (Hflag) {
+				fts_options |= FTS_COMFOLLOW;
+			}
 		}
-	} else
-		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
-
-	change_flags = hflag ? lchflags : chflags;
+	} 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) {

Modified: stable/10/bin/chmod/chmod.1
==============================================================================
--- stable/10/bin/chmod/chmod.1	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/bin/chmod/chmod.1	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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 su
 .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

Modified: stable/10/bin/chmod/chmod.c
==============================================================================
--- stable/10/bin/chmod/chmod.c	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/bin/chmod/chmod.c	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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 (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];
+			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");
+				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)

Modified: stable/10/usr.sbin/chown/chgrp.1
==============================================================================
--- stable/10/usr.sbin/chown/chgrp.1	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/usr.sbin/chown/chgrp.1	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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).

Modified: stable/10/usr.sbin/chown/chown.8
==============================================================================
--- stable/10/usr.sbin/chown/chown.8	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/usr.sbin/chown/chown.8	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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

Modified: stable/10/usr.sbin/chown/chown.c
==============================================================================
--- stable/10/usr.sbin/chown/chown.c	Mon Jun  1 08:52:11 2015	(r283874)
+++ stable/10/usr.sbin/chown/chown.c	Mon Jun  1 09:04:57 2015	(r283875)
@@ -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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506010904.t5194wLM047286>