bin/74500: [PATCH] allow chflags to set flags on symlinks

Dan Nelson dnelson at allantgroup.com
Sun Nov 28 20:50:22 PST 2004


>Number:         74500
>Category:       bin
>Synopsis:       [PATCH] allow chflags to set flags on symlinks
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 29 04:50:21 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Dan Nelson
>Release:        FreeBSD 5.3-STABLE i386
>Organization:
The Allant Group
>Environment:
System: FreeBSD dan.emsphone.com 5.3-STABLE FreeBSD 5.3-STABLE #373: Fri Nov 26 21:49:32 CST 2004 zsh at dan.emsphone.com:/usr/src/sys/i386/compile/DANSMP i386


	
>Description:
	

/bin/chflags always calls chflags(2), which means that it drills
through symlinks and changes attricutes on the underlying files.  This
may not be what is intended if the user wants to prevent the symlink
itself from being changed (to point to a different location, for
example).

The prototypes for chflags and fchflags are also incorrect; they take
an int argument, not an unsigned long.

>How-To-Repeat:
	
>Fix:

Apply the following patch which adds the -h switch, copied from the
chown code.  A newer version may be at
http://dan.allantgroup.com/FreeBSD/ .

Index: /usr/src/sys/sys/stat.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/stat.h,v
retrieving revision 1.40
diff -u -r1.40 stat.h
--- /usr/src/sys/sys/stat.h	17 Jun 2004 17:16:52 -0000	1.40
+++ /usr/src/sys/sys/stat.h	11 Nov 2004 20:06:24 -0000
@@ -299,11 +299,11 @@
 #ifndef _KERNEL
 __BEGIN_DECLS
 #if __BSD_VISIBLE
-int	chflags(const char *, unsigned long);
+int	chflags(const char *, int);
 #endif
 int	chmod(const char *, mode_t);
 #if __BSD_VISIBLE
-int	fchflags(int, unsigned long);
+int	fchflags(int, int);
 int	fchmod(int, mode_t);
 #endif
 int	fstat(int, struct stat *);
Index: /usr/src/bin/chflags/chflags.1
===================================================================
RCS file: /home/ncvs/src/bin/chflags/chflags.1,v
retrieving revision 1.18
diff -u -r1.18 chflags.1
--- /usr/src/bin/chflags/chflags.1	6 Apr 2004 20:06:44 -0000	1.18
+++ /usr/src/bin/chflags/chflags.1	11 Nov 2004 20:01:49 -0000
@@ -39,6 +39,7 @@
 .Nd change file flags
 .Sh SYNOPSIS
 .Nm
+.Op Fl h
 .Oo
 .Fl R
 .Op Fl H | Fl L | Fl P
@@ -72,6 +73,9 @@
 .It Fl R
 Change the file flags for the file hierarchies rooted
 in the files instead of just the files themselves.
+.It Fl h
+If the file is a symbolic link, change the user ID and/or the
+group ID of the link itself.
 .El
 .Pp
 The flags are specified as an octal number or a comma separated list
Index: /usr/src/bin/chflags/chflags.c
===================================================================
RCS file: /home/ncvs/src/bin/chflags/chflags.c,v
retrieving revision 1.20
diff -u -r1.20 chflags.c
--- /usr/src/bin/chflags/chflags.c	6 Apr 2004 20:06:44 -0000	1.20
+++ /usr/src/bin/chflags/chflags.c	11 Nov 2004 20:04:01 -0000
@@ -62,11 +62,11 @@
 	FTSENT *p;
 	u_long clear, set;
 	long val;
-	int Hflag, Lflag, Pflag, Rflag, ch, fts_options, oct, rval;
+	int Hflag, Lflag, Pflag, Rflag, hflag, ch, fts_options, oct, rval;
 	char *flags, *ep;
 
-	Hflag = Lflag = Pflag = Rflag = 0;
-	while ((ch = getopt(argc, argv, "HLPR")) != -1)
+	Hflag = Lflag = Pflag = Rflag = hflag = 0;
+	while ((ch = getopt(argc, argv, "HLPRh")) != -1)
 		switch (ch) {
 		case 'H':
 			Hflag = 1;
@@ -83,6 +83,9 @@
 		case 'R':
 			Rflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -95,6 +98,9 @@
 
 	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;
 		if (Lflag) {
@@ -102,7 +108,7 @@
 			fts_options |= FTS_LOGICAL;
 		}
 	} else
-		fts_options = FTS_LOGICAL;
+		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
 
 	flags = *argv;
 	if (*flags >= '0' && *flags <= '7') {
@@ -148,17 +154,20 @@
 			 * don't point to anything and ones that we found
 			 * doing a physical walk.
 			 */
-			continue;
+			if (hflag)
+				break;
+			else
+				continue;
 		default:
 			break;
 		}
 		if (oct) {
-			if (!chflags(p->fts_accpath, set))
+			if (!(hflag ? lchflags : chflags)(p->fts_accpath, set))
 				continue;
 		} else {
 			p->fts_statp->st_flags |= set;
 			p->fts_statp->st_flags &= clear;
-			if (!chflags(p->fts_accpath, (u_long)p->fts_statp->st_flags))
+			if (!(hflag ? lchflags : chflags)(p->fts_accpath, (u_long)p->fts_statp->st_flags))
 				continue;
 		}
 		warn("%s", p->fts_path);
@@ -173,6 +182,6 @@
 usage(void)
 {
 	(void)fprintf(stderr,
-	    "usage: chflags [-R [-H | -L | -P]] flags file ...\n");
+	    "usage: chflags [-h] [-R [-H | -L | -P]] flags file ...\n");
 	exit(1);
 }


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list