From 32367258066d8eaccf6cc78014ae74b397db7e4b Mon Sep 17 00:00:00 2001 From: smh Date: Mon, 1 Jun 2015 09:04:57 +0000 Subject: MFC r282208: Standardise chmod, chflags, chown and chgrp recursive symlink processing Relnotes: Yes Sponsored by: Multiplay --- bin/chflags/chflags.1 | 15 ++++++++++----- bin/chflags/chflags.c | 51 +++++++++++++++++++++++++++------------------------ 2 files changed, 37 insertions(+), 29 deletions(-) (limited to 'bin/chflags') 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 #include +#include #include #include #include @@ -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) { -- cgit v1.1