diff options
author | Steven Hartland <smh@FreeBSD.org> | 2015-04-29 00:49:00 +0000 |
---|---|---|
committer | Steven Hartland <smh@FreeBSD.org> | 2015-04-29 00:49:00 +0000 |
commit | ad34cace157419ddfc3e717c3b70171c2e4273a5 (patch) | |
tree | 98cd71770f42f33cc41eb6f64de0b60f2b8cd7ad /bin/chmod | |
parent | 2e8457e701b7d956578c96eee75f2b45863e220b (diff) | |
download | src-ad34cace157419ddfc3e717c3b70171c2e4273a5.tar.gz src-ad34cace157419ddfc3e717c3b70171c2e4273a5.zip |
Standardise chmod, chflags, chown and chgrp recursive symlink processing
chmod, chflags, chgrp, chmod and chown now affect symlinks in -R mode as
defined in symlink(7); previously symlinks were silently ignored.
Differential Revision: https://reviews.freebsd.org/D2316
Reviewed by: jilles
MFC after: 1 month
Relnotes: yes
Sponsored by: Multiplay
Notes
Notes:
svn path=/head/; revision=282208
Diffstat (limited to 'bin/chmod')
-rw-r--r-- | bin/chmod/chmod.1 | 14 | ||||
-rw-r--r-- | bin/chmod/chmod.c | 90 |
2 files changed, 53 insertions, 51 deletions
diff --git a/bin/chmod/chmod.1 b/bin/chmod/chmod.1 index 34a1ff018d9f..7efaabcdefcf 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 dc51faa39b01..9b801576efa7 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) |