Bug 29355

Summary: [kernel] [patch] add lchflags support
Product: Base System Reporter: Joshua Goodall <joshua>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
lchflags.diff none

Description Joshua Goodall 2001-08-01 01:30:00 UTC
Of the general syscall group [lf]?(utimes|chflags|chown|chmod|stat), the interfaces to VOP_GETATTR & VOP_SETATTR, only lchflags is missing. We can however set flags on symlinks with fsdb(8), or by a mount with NetBSD.

see thread "flags on symlinks" in -hackers/-fs for more (start here):
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=0+0+archive/2001/freebsd-hackers/20010729.freebsd-hackers

bde effectively gave me the go-ahead, I think.

Some code is from NetBSD but this patch is a more complete treatment of all possible side-effects in the base system.

Reviewed-by: cmc
"Review-already-requested-from": bde, adrian

Fix: 

http://www.roughtrade.net/bsd/README.lchflags
http://www.roughtrade.net/bsd/lchflags.diff
How-To-Repeat: n/a
Comment 1 Adrian Chadd freebsd_committer freebsd_triage 2001-08-29 11:28:23 UTC
Responsible Changed
From-To: freebsd-bugs->adrian

I already told Joshua that I'd take care of this. 
(when I get home. :-)
Comment 2 Joshua Goodall 2002-04-01 06:19:33 UTC
[resent to correct gnats address, oops]

I have attached an updated version of this change, and it's
also available at http://www.roughtrade.net/bsd/lchflags.diff
with a readme at  http://www.roughtrade.net/bsd/README.lchflags

original justification at:
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1862+0+archive/2001/freebsd-hackers/20010729.freebsd-hackers

This PR appears to have undergone committer timeout, perhaps
it could be reassigned?

Joshua

Index: bin/cp/utils.c
===================================================================
RCS file: /cvs/src/bin/cp/utils.c,v
retrieving revision 1.34
diff -u -r1.34 utils.c
--- bin/cp/utils.c	22 Feb 2002 21:24:14 -0000	1.34
+++ bin/cp/utils.c	29 Mar 2002 09:50:16 -0000
@@ -205,7 +205,7 @@
 		warn("symlink: %s", llink);
 		return (1);
 	}
-	return (0);
+	return (pflag ? setfile(p->fts_statp, 0) : 0);
 }
 
 int
@@ -250,11 +250,11 @@
 
 	TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
 	TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
-	if (utimes(to.p_path, tv)) {
+	if (lutimes(to.p_path, tv)) {
 		warn("utimes: %s", to.p_path);
 		rval = 1;
 	}
-	if (fd ? fstat(fd, &ts) : stat(to.p_path, &ts))
+	if (fd ? fstat(fd, &ts) : lstat(to.p_path, &ts))
 		gotstat = 0;
 	else {
 		gotstat = 1;
@@ -269,7 +269,7 @@
 	 */
 	if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
 		if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
-		    chown(to.p_path, fs->st_uid, fs->st_gid)) {
+		    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
 			if (errno != EPERM) {
 				warn("chown: %s", to.p_path);
 				rval = 1;
@@ -278,14 +278,14 @@
 		}
 
 	if (!gotstat || fs->st_mode != ts.st_mode)
-		if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+		if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
 			warn("chmod: %s", to.p_path);
 			rval = 1;
 		}
 
 	if (!gotstat || fs->st_flags != ts.st_flags)
 		if (fd ?
-		    fchflags(fd, fs->st_flags) : chflags(to.p_path, fs->st_flags)) {
+		    fchflags(fd, fs->st_flags) : lchflags(to.p_path, fs->st_flags)) {
 			warn("chflags: %s", to.p_path);
 			rval = 1;
 		}
Index: bin/ln/symlink.7
===================================================================
RCS file: /cvs/src/bin/ln/symlink.7,v
retrieving revision 1.20
diff -u -r1.20 symlink.7
--- bin/ln/symlink.7	14 Aug 2001 10:01:43 -0000	1.20
+++ bin/ln/symlink.7	29 Mar 2002 09:44:19 -0000
@@ -106,11 +106,14 @@
 would return a file descriptor to the file
 .Dq afile .
 .Pp
-There are six system calls that do not follow links, and which operate
+There are nine system calls that do not follow links, and which operate
 on the symbolic link itself.
 They are:
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
 .Xr lchown 2 ,
 .Xr lstat 2 ,
+.Xr lutimes 2 ,
 .Xr readlink 2 ,
 .Xr rename 2 ,
 .Xr rmdir 2 ,
@@ -126,12 +129,16 @@
 is applied to a symbolic link, it fails with the error
 .Er ENOTDIR .
 .Pp
-The owner and group of an existing symbolic link can be changed by
-means of the
-.Xr lchown 2
-system call.
-The other file attributes, such as the modification time and access
-permissions, are not used by the system and cannot be changed.
+The flags, access permissions, owner/group and modification time of
+an existing symbolic link can be changed by means of the
+.Xr lchflags 2
+.Xr lchmod 2 ,
+.Xr lchown 2 ,
+and 
+.Xr lutimes 2 ,
+system calls, respectively. Of these only the flags are used by
+the system, so a symbolic link can be made immutable. The access
+permissions and ownership are ignored.
 .Pp
 The
 .Bx 4.4
@@ -441,8 +448,11 @@
 .Xr pax 1 ,
 .Xr rm 1 ,
 .Xr tar 1 ,
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
 .Xr lchown 2 ,
 .Xr lstat 2 ,
+.Xr lutimes 2 ,
 .Xr readlink 2 ,
 .Xr rename 2 ,
 .Xr symlink 2 ,
Index: bin/rm/rm.c
===================================================================
RCS file: /cvs/src/bin/rm/rm.c,v
retrieving revision 1.36
diff -u -r1.36 rm.c
--- bin/rm/rm.c	14 Feb 2002 01:59:47 -0000	1.36
+++ bin/rm/rm.c	29 Mar 2002 09:44:19 -0000
@@ -237,7 +237,7 @@
 		if (!uid &&
 		    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 		    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
-			rval = chflags(p->fts_accpath,
+			rval = lchflags(p->fts_accpath,
 				       p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 		if (rval == 0) {
 			/*
@@ -327,7 +327,7 @@
 		if (!uid &&
 		    (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 		    !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
-			rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
+			rval = lchflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
 		if (rval == 0) {
 			if (S_ISWHT(sb.st_mode))
 				rval = undelete(f);
Index: contrib/gdb/gdb/proc-events.c
===================================================================
RCS file: /cvs/src/contrib/gdb/gdb/proc-events.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 proc-events.c
--- contrib/gdb/gdb/proc-events.c	4 Aug 2000 09:34:08 -0000	1.1.1.1
+++ contrib/gdb/gdb/proc-events.c	29 Mar 2002 09:44:19 -0000
@@ -525,6 +525,12 @@
 #if defined (SYS_ksigqueue)
   syscall_table[SYS_ksigqueue] = "ksigqueue";
 #endif
+#if defined (SYS_lchflags)
+  syscall_table[SYS_lchflags] = "lchflags";
+#endif
+#if defined (SYS_lchmod)
+  syscall_table[SYS_lchmod] = "lchmod";
+#endif
 #if defined (SYS_lchown)
   syscall_table[SYS_lchown] = "lchown";
 #endif
@@ -548,6 +554,9 @@
 #endif
 #if defined (SYS_lstat64)
   syscall_table[SYS_lstat64] = "lstat64";
+#endif
+#if defined (SYS_lutimes)
+  syscall_table[SYS_lutimes] = "lutimes";
 #endif
 #if defined (SYS_lvldom)
   syscall_table[SYS_lvldom] = "lvldom";
Index: lib/libc/sys/chflags.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/chflags.2,v
retrieving revision 1.19
diff -u -r1.19 chflags.2
--- lib/libc/sys/chflags.2	1 Oct 2001 16:09:01 -0000	1.19
+++ lib/libc/sys/chflags.2	29 Mar 2002 09:44:19 -0000
@@ -37,7 +37,8 @@
 .Os
 .Sh NAME
 .Nm chflags ,
-.Nm fchflags
+.Nm fchflags ,
+.Nm lchflags
 .Nd set file flags
 .Sh LIBRARY
 .Lb libc
@@ -48,6 +49,8 @@
 .Fn chflags "const char *path"  "u_long flags"
 .Ft int
 .Fn fchflags "int fd" "u_long flags"
+.Ft int
+.Fn lchflags "const char *path"  "u_long flags"
 .Sh DESCRIPTION
 The file whose name
 is given by
@@ -57,6 +60,11 @@
 has its flags changed to
 .Fa flags .
 .Pp
+.Fn Lchflags
+is similar to
+.Fn chflags
+but does not follow symbolic links.
+.Pp
 The flags specified are formed by
 .Em or Ns 'ing
 the following values
@@ -171,3 +179,7 @@
 .Nm fchflags
 functions first appeared in
 .Bx 4.4 .
+The
+.Fn lchflags
+function first appeared in
+.Nx 1.5 .
Index: sbin/restore/tape.c
===================================================================
RCS file: /cvs/src/sbin/restore/tape.c,v
retrieving revision 1.31
diff -u -r1.31 tape.c
--- sbin/restore/tape.c	20 Mar 2002 22:49:40 -0000	1.31
+++ sbin/restore/tape.c	29 Mar 2002 09:51:44 -0000
@@ -529,6 +529,8 @@
 extractfile(char *name)
 {
 	int flags;
+	uid_t uid;
+	gid_t gid;
 	mode_t mode;
 	struct timeval timep[2];
 	struct entry *ep;
@@ -539,6 +541,8 @@
 	timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
 	timep[1].tv_sec = curfile.dip->di_mtime;
 	timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
+	uid = curfile.dip->di_uid;
+	gid = curfile.dip->di_gid;
 	mode = curfile.dip->di_mode;
 	flags = curfile.dip->di_flags;
 	switch (mode & IFMT) {
@@ -573,7 +577,17 @@
 			    "%s: zero length symbolic link (ignored)\n", name);
 			return (GOOD);
 		}
-		return (linkit(lnkbuf, name, SYMLINK));
+		if (uflag)
+			(void) unlink(name);
+		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
+			(void) lutimes(name, timep);
+			(void) lchown(name, uid, gid);
+			(void) lchmod(name, mode);
+			(void) lchflags(name, flags);
+			return (GOOD);
+		} else {
+			return (FAIL);
+		}
 
 	case IFIFO:
 		vprintf(stdout, "extract fifo %s\n", name);
@@ -589,9 +603,9 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+		(void) utimes(name, timep);
+		(void) chown(name, uid, gid);
 		(void) chmod(name, mode);
-		utimes(name, timep);
 		(void) chflags(name, flags);
 		skipfile();
 		return (GOOD);
@@ -611,9 +625,9 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+		(void) utimes(name, timep);
+		(void) chown(name, uid, gid);
 		(void) chmod(name, mode);
-		utimes(name, timep);
 		(void) chflags(name, flags);
 		skipfile();
 		return (GOOD);
@@ -633,12 +647,12 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
-		(void) fchmod(ofile, mode);
 		getfile(xtrfile, xtrskip);
+		(void) futimes(ofile, timep);
+		(void) fchown(ofile, uid, gid);
+		(void) fchmod(ofile, mode);
+		(void) fchflags(ofile, flags);
 		(void) close(ofile);
-		utimes(name, timep);
-		(void) chflags(name, flags);
 		return (GOOD);
 	}
 	/* NOTREACHED */
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.118
diff -u -r1.118 init_sysent.c
--- sys/kern/init_sysent.c	5 Mar 2002 16:13:00 -0000	1.118
+++ sys/kern/init_sysent.c	29 Mar 2002 10:12:20 -0000
@@ -2,7 +2,7 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/init_sysent.c,v 1.118 2002/03/05 16:13:00 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.107 2002/03/05 16:11:11 rwatson Exp 
  */
 
@@ -412,4 +412,5 @@
 	{ 0, (sy_call_t *)nosys },			/* 387 = __mac_get_file */
 	{ 0, (sy_call_t *)nosys },			/* 388 = __mac_set_fd */
 	{ 0, (sy_call_t *)nosys },			/* 389 = __mac_set_file */
+	{ AS(lchflags_args), (sy_call_t *)lchflags },	/* 390 = lchflags */
 };
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.c,v
retrieving revision 1.105
diff -u -r1.105 syscalls.c
--- sys/kern/syscalls.c	5 Mar 2002 16:13:00 -0000	1.105
+++ sys/kern/syscalls.c	29 Mar 2002 10:12:20 -0000
@@ -2,7 +2,7 @@
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/syscalls.c,v 1.105 2002/03/05 16:13:00 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.107 2002/03/05 16:11:11 rwatson Exp 
  */
 
@@ -397,4 +397,5 @@
 	"#387",			/* 387 = __mac_get_file */
 	"#388",			/* 388 = __mac_set_fd */
 	"#389",			/* 389 = __mac_set_file */
+	"lchflags",			/* 390 = lchflags */
 };
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.107
diff -u -r1.107 syscalls.master
--- sys/kern/syscalls.master	5 Mar 2002 16:11:11 -0000	1.107
+++ sys/kern/syscalls.master	29 Mar 2002 10:10:38 -0000
@@ -559,3 +559,4 @@
 387	UNIMPL	BSD	__mac_get_file
 388	UNIMPL	BSD	__mac_set_fd
 389	UNIMPL	BSD	__mac_set_file
+390	STD	BSD	{ int lchflags(char *path, int flags); }
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.241
diff -u -r1.241 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	28 Mar 2002 13:47:32 -0000	1.241
+++ sys/kern/vfs_syscalls.c	29 Mar 2002 10:01:14 -0000
@@ -2812,7 +2812,7 @@
 }
 
 /*
- * Common implementation code for chflags() and fchflags().
+ * Common implementation code for chflags(), lchflags and fchflags().
  */
 static int
 setfflags(td, vp, flags)
@@ -2870,6 +2870,36 @@
 	struct nameidata nd;
 
 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
+	if ((error = namei(&nd)) != 0)
+		return (error);
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
+	vrele(nd.ni_vp);
+	return error;
+}
+ 
+/*
+ * Change flags of a file given a path name (don't follow links).
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct lchflags_args {
+	char	*path;
+	int	flags;
+};
+#endif
+/* ARGSUSED */
+int
+lchflags(td, uap)
+	struct thread *td;
+	register struct lchflags_args /* {
+		syscallarg(char *) path;
+		syscallarg(int) flags;
+	} */ *uap;
+{
+	int error;
+	struct nameidata nd;
+ 
+	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
Index: sys/sys/param.h
===================================================================
RCS file: /cvs/src/sys/sys/param.h,v
retrieving revision 1.119
diff -u -r1.119 param.h
--- sys/sys/param.h	19 Mar 2002 20:18:40 -0000	1.119
+++ sys/sys/param.h	29 Mar 2002 10:02:11 -0000
@@ -52,7 +52,7 @@
  * there.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 500032	/* Master, propagated to newvers */
+#define __FreeBSD_version 500033	/* Master, propagated to newvers */
 
 #ifndef NULL
 #define	NULL	0
Index: sys/sys/stat.h
===================================================================
RCS file: /cvs/src/sys/sys/stat.h,v
retrieving revision 1.23
diff -u -r1.23 stat.h
--- sys/sys/stat.h	19 Mar 2002 20:18:41 -0000	1.23
+++ sys/sys/stat.h	29 Mar 2002 10:05:49 -0000
@@ -256,6 +256,7 @@
 #ifndef _POSIX_SOURCE
 int	chflags(const char *, u_long);
 int	fchflags(int, u_long);
+int	lchflags(const char *, u_long);
 int	fchmod(int, mode_t);
 int	lchmod(const char *, mode_t);
 int	lstat(const char *, struct stat *);
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvs/src/sys/sys/syscall.h,v
retrieving revision 1.104
diff -u -r1.104 syscall.h
--- sys/sys/syscall.h	5 Mar 2002 16:13:01 -0000	1.104
+++ sys/sys/syscall.h	29 Mar 2002 10:12:20 -0000
@@ -2,7 +2,7 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/syscall.h,v 1.104 2002/03/05 16:13:01 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.107 2002/03/05 16:11:11 rwatson Exp 
  */
 
@@ -303,4 +303,5 @@
 #define	SYS_kse_new	381
 #define	SYS_thread_wakeup	382
 #define	SYS_kse_yield	383
-#define	SYS_MAXSYSCALL	390
+#define	SYS_lchflags	390
+#define	SYS_MAXSYSCALL	391
Index: sys/sys/syscall.mk
===================================================================
RCS file: /cvs/src/sys/sys/syscall.mk,v
retrieving revision 1.59
diff -u -r1.59 syscall.mk
--- sys/sys/syscall.mk	5 Mar 2002 16:13:01 -0000	1.59
+++ sys/sys/syscall.mk	29 Mar 2002 10:12:20 -0000
@@ -1,6 +1,6 @@
 # FreeBSD system call names.
 # DO NOT EDIT-- this file is automatically generated.
-# $FreeBSD: src/sys/sys/syscall.mk,v 1.59 2002/03/05 16:13:01 rwatson Exp $
+# $FreeBSD$
 # created from FreeBSD: src/sys/kern/syscalls.master,v 1.107 2002/03/05 16:11:11 rwatson Exp 
 MIASM =  \
 	syscall.o \
@@ -252,4 +252,5 @@
 	kse_wakeup.o \
 	kse_new.o \
 	thread_wakeup.o \
-	kse_yield.o
+	kse_yield.o \
+	lchflags.o
Index: sys/sys/sysproto.h
===================================================================
RCS file: /cvs/src/sys/sys/sysproto.h,v
retrieving revision 1.96
diff -u -r1.96 sysproto.h
--- sys/sys/sysproto.h	19 Mar 2002 20:18:41 -0000	1.96
+++ sys/sys/sysproto.h	29 Mar 2002 10:12:20 -0000
@@ -2,7 +2,7 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/sysproto.h,v 1.96 2002/03/19 20:18:41 alfred Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.107 2002/03/05 16:11:11 rwatson Exp 
  */
 
@@ -1105,6 +1105,10 @@
 struct kse_yield_args {
 	register_t dummy;
 };
+struct lchflags_args {
+	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+	char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
 int	nosys(struct thread *, struct nosys_args *);
 void	sys_exit(struct thread *, struct sys_exit_args *);
 int	fork(struct thread *, struct fork_args *);
@@ -1354,6 +1358,7 @@
 int	kse_new(struct thread *, struct kse_new_args *);
 int	thread_wakeup(struct thread *, struct thread_wakeup_args *);
 int	kse_yield(struct thread *, struct kse_yield_args *);
+int	lchflags(struct thread *, struct lchflags_args *);
 
 #ifdef COMPAT_43
 
Index: usr.bin/chflags/chflags.1
===================================================================
RCS file: /cvs/src/usr.bin/chflags/chflags.1,v
retrieving revision 1.14
diff -u -r1.14 chflags.1
--- usr.bin/chflags/chflags.1	15 Aug 2001 09:09:39 -0000	1.14
+++ usr.bin/chflags/chflags.1	29 Mar 2002 09:44:22 -0000
@@ -47,6 +47,7 @@
 .Fl R
 .Op Fl H | Fl L | Fl P
 .Oc
+.Op Fl h 
 .Ar flags
 .Ar
 .Sh DESCRIPTION
@@ -76,6 +77,11 @@
 .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 
+.Ar file 
+or a file encountered during directory traversal is a symbolic link, 
+the file flags of the link itself are changed. 
 .El
 .Pp
 The flags are specified as an octal number or a comma separated list
@@ -117,13 +123,6 @@
 the immutable bit should be cleared
 .El
 .Pp
-Symbolic links do not have flags, so unless the
-.Fl H
-or
-.Fl L
-option is set,
-.Nm
-on a symbolic link always succeeds and has no effect.
 The
 .Fl H ,
 .Fl L
@@ -141,6 +140,7 @@
 .Sh SEE ALSO
 .Xr ls 1 ,
 .Xr chflags 2 ,
+.Xr lchflags 2 ,
 .Xr stat 2 ,
 .Xr fts 3 ,
 .Xr symlink 7
Index: usr.bin/chflags/chflags.c
===================================================================
RCS file: /cvs/src/usr.bin/chflags/chflags.c,v
retrieving revision 1.14
diff -u -r1.14 chflags.c
--- usr.bin/chflags/chflags.c	22 Mar 2002 01:19:26 -0000	1.14
+++ usr.bin/chflags/chflags.c	29 Mar 2002 11:02:11 -0000
@@ -67,13 +67,14 @@
 {
 	FTS *ftsp;
 	FTSENT *p;
-	u_long clear, set;
+	u_long clear, set, newflags;
 	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;
+	int (*change_flags) __P((const char *, u_long));
 
-	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;
@@ -90,6 +91,9 @@
 		case 'R':
 			Rflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -109,7 +113,7 @@
 			fts_options |= FTS_LOGICAL;
 		}
 	} else
-		fts_options = FTS_LOGICAL;
+		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
 
 	flags = *argv;
 	if (*flags >= '0' && *flags <= '7') {
@@ -134,6 +138,7 @@
 		err(1, NULL);
 
 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+		change_flags = chflags;
 		switch (p->fts_info) {
 		case FTS_D:
 			if (Rflag)		/* Change it at FTS_DP. */
@@ -149,28 +154,44 @@
 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
 			rval = 1;
 			continue;
-		case FTS_SL:			/* Ignore. */
+		case FTS_SL:			/* Ignore unless -h. */ 
+			/* 
+			 * All symlinks we found while doing a physical 
+			 * walk end up here. 
+			 */ 
+			if (!hflag) 
+				continue; 
+			/* 
+			 * Note that if we follow a symlink, fts_info is 
+			 * not FTS_SL but FTS_F or whatever.  And we should 
+			 * use lchflags only for FTS_SL and should use chflags 
+			 * for others. 
+			 */ 
+			change_flags = lchflags; 
+			break; 
+
 		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.
+			 * don't point to anything. Note that if we are 
+			 * doing a physical walk, we never reach here unless 
+			 * we asked to follow explicitly (with -H or -L).
 			 */
 			continue;
 		default:
 			break;
 		}
-		if (oct) {
-			if (!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))
-				continue;
+		if (oct)
+			newflags = set;
+		else {
+			newflags = p->fts_statp->st_flags;
+			newflags |= set;
+			newflags &= clear;
+		}
+		if ((*change_flags)(p->fts_accpath, newflags)) {
+			warn("%s", p->fts_path);
+			rval = 1;
 		}
-		warn("%s", p->fts_path);
-		rval = 1;
 	}
 	if (errno)
 		err(1, "fts_read");
@@ -181,6 +202,6 @@
 usage()
 {
 	(void)fprintf(stderr,
-	    "usage: chflags [-R [-H | -L | -P]] flags file ...\n");
+	    "usage: chflags [-R [-H | -L | -P]] [-h] flags file ...\n");
 	exit(1);
 }
Index: usr.bin/find/function.c
===================================================================
RCS file: /cvs/src/usr.bin/find/function.c,v
retrieving revision 1.39
diff -u -r1.39 function.c
--- usr.bin/find/function.c	26 Mar 2002 12:05:34 -0000	1.39
+++ usr.bin/find/function.c	29 Mar 2002 09:44:22 -0000
@@ -401,7 +401,7 @@
 	if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 	    !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
 	    geteuid() == 0)
-		chflags(entry->fts_accpath,
+		lchflags(entry->fts_accpath,
 		       entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 
 	/* rmdir directories, unlink everything else */
Index: usr.sbin/mtree/compare.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/compare.c,v
retrieving revision 1.20
diff -u -r1.20 compare.c
--- usr.sbin/mtree/compare.c	6 Oct 2000 12:48:55 -0000	1.20
+++ usr.sbin/mtree/compare.c	29 Mar 2002 09:44:22 -0000
@@ -60,7 +60,7 @@
 #include "mtree.h"
 #include "extern.h"
 
-extern int uflag;
+extern int Lflag, uflag;
 extern int lineno;
 
 static char *ftype __P((u_int));
@@ -125,7 +125,7 @@
 		(void)printf("%suser expected %lu found %lu",
 		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
 		if (uflag)
-			if (chown(p->fts_accpath, s->st_uid, -1))
+			if ((Lflag ? chown : lchown)(p->fts_accpath, s->st_uid, -1))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -139,7 +139,7 @@
 		(void)printf("%sgid expected %lu found %lu",
 		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
 		if (uflag)
-			if (chown(p->fts_accpath, -1, s->st_gid))
+			if ((Lflag ? chown : lchown)(p->fts_accpath, -1, s->st_gid))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -231,7 +231,7 @@
 		free(fflags);
 
 		if (uflag)
-			if (chflags(p->fts_accpath, s->st_flags))
+			if ((Lflag ? chflags : lchflags)(p->fts_accpath, s->st_flags))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -299,7 +299,7 @@
 	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
 		LABEL;
 		(void)printf("%slink_ref expected %s found %s\n",
-		      tab, cp, s->slink);
+		      tab, s->slink, cp);
 	}
 	return (label);
 }
Index: usr.sbin/mtree/mtree.8
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.8,v
retrieving revision 1.35
diff -u -r1.35 mtree.8
--- usr.sbin/mtree/mtree.8	15 Aug 2001 09:09:46 -0000	1.35
+++ usr.sbin/mtree/mtree.8	29 Mar 2002 09:44:22 -0000
@@ -76,7 +76,7 @@
 Don't follow symbolic links in the file hierarchy, instead consider
 the symbolic link itself in any comparisons. This is the default.
 .It Fl U
-Modify the owner, group and permissions of existing files to match
+Modify the owner, group, flags and permissions of existing files to match
 the specification and create any missing directories or symbolic links.
 User, group and permissions must all be specified for missing directories
 to be created.
Index: usr.sbin/mtree/mtree.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.c,v
retrieving revision 1.18
diff -u -r1.18 mtree.c
--- usr.sbin/mtree/mtree.c	25 Sep 2000 16:24:22 -0000	1.18
+++ usr.sbin/mtree/mtree.c	29 Mar 2002 09:44:22 -0000
@@ -58,7 +58,7 @@
 extern long int crc_total;
 
 int ftsoptions = FTS_PHYSICAL;
-int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag;
+int cflag, dflag, eflag, iflag, Lflag, nflag, qflag, rflag, sflag, uflag, Uflag;
 u_int keys;
 char fullpath[MAXPATHLEN];
 
@@ -107,6 +107,7 @@
 					keys |= parsekey(p, NULL);
 			break;
 		case 'L':
+			Lflag = 1;
 			ftsoptions &= ~FTS_PHYSICAL;
 			ftsoptions |= FTS_LOGICAL;
 			break;
Index: usr.sbin/mtree/verify.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/verify.c,v
retrieving revision 1.15
diff -u -r1.15 verify.c
--- usr.sbin/mtree/verify.c	3 Oct 2000 13:13:47 -0000	1.15
+++ usr.sbin/mtree/verify.c	29 Mar 2002 09:44:22 -0000
@@ -205,6 +205,10 @@
 				if (lchown(path, p->st_uid, p->st_gid))
 					(void)printf("%s: user/group not modified: %s\n",
 					    path, strerror(errno));
+				if ((p->flags & F_FLAGS) && p->st_flags &&
+					lchflags(path, p->st_flags))
+					(void)printf("%s: symlink flags not set: %s\n",
+					    path, strerror(errno));
 				continue;
 			} else if (!(p->flags & F_MODE))
 			    (void)printf(" (directory not created: mode not specified)");
Index: usr.sbin/pkg_install/add/extract.c
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_install/add/extract.c,v
retrieving revision 1.30
diff -u -r1.30 extract.c
--- usr.sbin/pkg_install/add/extract.c	10 Oct 2001 06:58:41 -0000	1.30
+++ usr.sbin/pkg_install/add/extract.c	29 Mar 2002 09:44:22 -0000
@@ -62,7 +62,7 @@
 	if (q->type == PLIST_FILE) {
 	    snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name);
 	    if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) {
-		(void)chflags(try, 0);
+		(void)lchflags(try, 0);
 		(void)unlink(try);
 		if (rename(bup, try))
 		    warnx("rollback: unable to rename %s back to %s", bup, try);
@@ -138,7 +138,7 @@
 		/* first try to rename it into place */
 		snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name);
 		if (fexists(try)) {
-		    (void)chflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
+		    (void)lchflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
 		    if (preserve && PkgName) {
 			char pf[FILENAME_MAX];
Comment 3 Benno Rice freebsd_committer freebsd_triage 2002-04-17 07:32:04 UTC
Responsible Changed
From-To: adrian->alfred

Josh asked me to review this, but I don't feel comfortable as it's not an area 
I'm familiar with.  Alfred has offered to have a go at it.
Comment 4 Joshua Goodall 2002-05-06 02:40:20 UTC
Update of this patch to prevent bitrot.

n.b. mux has committed an incomplete variant today without credit.

Joshua

Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.c,v
retrieving revision 1.108
diff -u -u -r1.108 syscalls.c
--- sys/kern/syscalls.c	17 Apr 2002 13:06:36 -0000	1.108
+++ sys/kern/syscalls.c	18 Apr 2002 01:40:46 -0000
@@ -2,8 +2,8 @@
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/syscalls.c,v 1.108 2002/04/17 13:06:36 mux Exp $
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.109 2002/04/14 05:31:47 alc Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.110 2002/04/17 13:05:13 mux Exp 
  */
 
 char *syscallnames[] = {
@@ -398,4 +398,5 @@
 	"#388",			/* 388 = __mac_set_fd */
 	"#389",			/* 389 = __mac_set_file */
 	"kenv",			/* 390 = kenv */
+	"lchflags",			/* 391 = lchflags */
 };
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.250
diff -u -u -r1.250 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	4 May 2002 19:50:09 -0000	1.250
+++ sys/kern/vfs_syscalls.c	5 May 2002 15:12:50 -0000
@@ -2826,7 +2826,7 @@
 }
 
 /*
- * Common implementation code for chflags() and fchflags().
+ * Common implementation code for chflags(), lchflags and fchflags().
  */
 static int
 setfflags(td, vp, flags)
@@ -2884,6 +2884,36 @@
 	struct nameidata nd;
 
 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
+	if ((error = namei(&nd)) != 0)
+		return (error);
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
+	vrele(nd.ni_vp);
+	return error;
+}
+ 
+/*
+ * Change flags of a file given a path name (don't follow links).
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct lchflags_args {
+	char	*path;
+	int	flags;
+};
+#endif
+/* ARGSUSED */
+int
+lchflags(td, uap)
+	struct thread *td;
+	register struct lchflags_args /* {
+		syscallarg(char *) path;
+		syscallarg(int) flags;
+	} */ *uap;
+{
+	int error;
+	struct nameidata nd;
+ 
+	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.110
diff -u -u -r1.110 syscalls.master
--- sys/kern/syscalls.master	17 Apr 2002 13:05:13 -0000	1.110
+++ sys/kern/syscalls.master	17 Apr 2002 22:09:29 -0000
@@ -561,3 +561,4 @@
 389	UNIMPL	BSD	__mac_set_file
 390	STD	BSD	{ int kenv(int what, const char *name, char *value, \
 			    int len); }
+391	STD	BSD	{ int lchflags(char *path, int flags); }
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.121
diff -u -u -r1.121 init_sysent.c
--- sys/kern/init_sysent.c	17 Apr 2002 13:06:35 -0000	1.121
+++ sys/kern/init_sysent.c	18 Apr 2002 01:40:46 -0000
@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/init_sysent.c,v 1.121 2002/04/17 13:06:35 mux Exp $
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.109 2002/04/14 05:31:47 alc Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.110 2002/04/17 13:05:13 mux Exp 
  */
 
 #include "opt_compat.h"
@@ -413,4 +413,5 @@
 	{ 0, (sy_call_t *)nosys },			/* 388 = __mac_set_fd */
 	{ 0, (sy_call_t *)nosys },			/* 389 = __mac_set_file */
 	{ AS(kenv_args), (sy_call_t *)kenv },		/* 390 = kenv */
+	{ AS(lchflags_args), (sy_call_t *)lchflags },	/* 391 = lchflags */
 };
Index: sys/sys/stat.h
===================================================================
RCS file: /cvs/src/sys/sys/stat.h,v
retrieving revision 1.23
diff -u -u -r1.23 stat.h
--- sys/sys/stat.h	19 Mar 2002 20:18:41 -0000	1.23
+++ sys/sys/stat.h	29 Mar 2002 10:05:49 -0000
@@ -256,6 +256,7 @@
 #ifndef _POSIX_SOURCE
 int	chflags(const char *, u_long);
 int	fchflags(int, u_long);
+int	lchflags(const char *, u_long);
 int	fchmod(int, mode_t);
 int	lchmod(const char *, mode_t);
 int	lstat(const char *, struct stat *);
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvs/src/sys/sys/syscall.h,v
retrieving revision 1.107
diff -u -u -r1.107 syscall.h
--- sys/sys/syscall.h	17 Apr 2002 13:06:36 -0000	1.107
+++ sys/sys/syscall.h	18 Apr 2002 01:40:46 -0000
@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/syscall.h,v 1.107 2002/04/17 13:06:36 mux Exp $
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.109 2002/04/14 05:31:47 alc Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.110 2002/04/17 13:05:13 mux Exp 
  */
 
 #define	SYS_syscall	0
@@ -304,4 +304,5 @@
 #define	SYS_thread_wakeup	382
 #define	SYS_kse_yield	383
 #define	SYS_kenv	390
-#define	SYS_MAXSYSCALL	391
+#define	SYS_lchflags	391
+#define	SYS_MAXSYSCALL	392
Index: sys/sys/sysproto.h
===================================================================
RCS file: /cvs/src/sys/sys/sysproto.h,v
retrieving revision 1.99
diff -u -u -r1.99 sysproto.h
--- sys/sys/sysproto.h	17 Apr 2002 13:06:36 -0000	1.99
+++ sys/sys/sysproto.h	18 Apr 2002 01:40:46 -0000
@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/sysproto.h,v 1.99 2002/04/17 13:06:36 mux Exp $
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.109 2002/04/14 05:31:47 alc Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.110 2002/04/17 13:05:13 mux Exp 
  */
 
 #ifndef _SYS_SYSPROTO_H_
@@ -1111,6 +1111,10 @@
 	char value_l_[PADL_(char *)]; char * value; char value_r_[PADR_(char *)];
 	char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)];
 };
+struct lchflags_args {
+	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+	char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
 int	nosys(struct thread *, struct nosys_args *);
 void	sys_exit(struct thread *, struct sys_exit_args *);
 int	fork(struct thread *, struct fork_args *);
@@ -1361,6 +1365,7 @@
 int	thread_wakeup(struct thread *, struct thread_wakeup_args *);
 int	kse_yield(struct thread *, struct kse_yield_args *);
 int	kenv(struct thread *, struct kenv_args *);
+int	lchflags(struct thread *, struct lchflags_args *);
 
 #ifdef COMPAT_43
 
Index: sys/sys/syscall.mk
===================================================================
RCS file: /cvs/src/sys/sys/syscall.mk,v
retrieving revision 1.62
diff -u -u -r1.62 syscall.mk
--- sys/sys/syscall.mk	17 Apr 2002 13:06:36 -0000	1.62
+++ sys/sys/syscall.mk	18 Apr 2002 01:40:46 -0000
@@ -1,7 +1,7 @@
 # FreeBSD system call names.
 # DO NOT EDIT-- this file is automatically generated.
-# $FreeBSD: src/sys/sys/syscall.mk,v 1.62 2002/04/17 13:06:36 mux Exp $
-# created from FreeBSD: src/sys/kern/syscalls.master,v 1.109 2002/04/14 05:31:47 alc Exp 
+# $FreeBSD$
+# created from FreeBSD: src/sys/kern/syscalls.master,v 1.110 2002/04/17 13:05:13 mux Exp 
 MIASM =  \
 	syscall.o \
 	exit.o \
@@ -253,4 +253,5 @@
 	kse_new.o \
 	thread_wakeup.o \
 	kse_yield.o \
-	kenv.o
+	kenv.o \
+	lchflags.o
Index: bin/cp/utils.c
===================================================================
RCS file: /cvs/src/bin/cp/utils.c,v
retrieving revision 1.34
diff -u -u -r1.34 utils.c
--- bin/cp/utils.c	22 Feb 2002 21:24:14 -0000	1.34
+++ bin/cp/utils.c	29 Mar 2002 09:50:16 -0000
@@ -205,7 +205,7 @@
 		warn("symlink: %s", llink);
 		return (1);
 	}
-	return (0);
+	return (pflag ? setfile(p->fts_statp, 0) : 0);
 }
 
 int
@@ -250,11 +250,11 @@
 
 	TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
 	TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
-	if (utimes(to.p_path, tv)) {
+	if (lutimes(to.p_path, tv)) {
 		warn("utimes: %s", to.p_path);
 		rval = 1;
 	}
-	if (fd ? fstat(fd, &ts) : stat(to.p_path, &ts))
+	if (fd ? fstat(fd, &ts) : lstat(to.p_path, &ts))
 		gotstat = 0;
 	else {
 		gotstat = 1;
@@ -269,7 +269,7 @@
 	 */
 	if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
 		if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
-		    chown(to.p_path, fs->st_uid, fs->st_gid)) {
+		    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
 			if (errno != EPERM) {
 				warn("chown: %s", to.p_path);
 				rval = 1;
@@ -278,14 +278,14 @@
 		}
 
 	if (!gotstat || fs->st_mode != ts.st_mode)
-		if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+		if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
 			warn("chmod: %s", to.p_path);
 			rval = 1;
 		}
 
 	if (!gotstat || fs->st_flags != ts.st_flags)
 		if (fd ?
-		    fchflags(fd, fs->st_flags) : chflags(to.p_path, fs->st_flags)) {
+		    fchflags(fd, fs->st_flags) : lchflags(to.p_path, fs->st_flags)) {
 			warn("chflags: %s", to.p_path);
 			rval = 1;
 		}
Index: bin/ln/symlink.7
===================================================================
RCS file: /cvs/src/bin/ln/symlink.7,v
retrieving revision 1.20
diff -u -u -r1.20 symlink.7
--- bin/ln/symlink.7	14 Aug 2001 10:01:43 -0000	1.20
+++ bin/ln/symlink.7	29 Mar 2002 09:44:19 -0000
@@ -106,11 +106,14 @@
 would return a file descriptor to the file
 .Dq afile .
 .Pp
-There are six system calls that do not follow links, and which operate
+There are nine system calls that do not follow links, and which operate
 on the symbolic link itself.
 They are:
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
 .Xr lchown 2 ,
 .Xr lstat 2 ,
+.Xr lutimes 2 ,
 .Xr readlink 2 ,
 .Xr rename 2 ,
 .Xr rmdir 2 ,
@@ -126,12 +129,16 @@
 is applied to a symbolic link, it fails with the error
 .Er ENOTDIR .
 .Pp
-The owner and group of an existing symbolic link can be changed by
-means of the
-.Xr lchown 2
-system call.
-The other file attributes, such as the modification time and access
-permissions, are not used by the system and cannot be changed.
+The flags, access permissions, owner/group and modification time of
+an existing symbolic link can be changed by means of the
+.Xr lchflags 2
+.Xr lchmod 2 ,
+.Xr lchown 2 ,
+and 
+.Xr lutimes 2 ,
+system calls, respectively. Of these only the flags are used by
+the system, so a symbolic link can be made immutable. The access
+permissions and ownership are ignored.
 .Pp
 The
 .Bx 4.4
@@ -441,8 +448,11 @@
 .Xr pax 1 ,
 .Xr rm 1 ,
 .Xr tar 1 ,
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
 .Xr lchown 2 ,
 .Xr lstat 2 ,
+.Xr lutimes 2 ,
 .Xr readlink 2 ,
 .Xr rename 2 ,
 .Xr symlink 2 ,
Index: bin/rm/rm.c
===================================================================
RCS file: /cvs/src/bin/rm/rm.c,v
retrieving revision 1.36
diff -u -u -r1.36 rm.c
--- bin/rm/rm.c	14 Feb 2002 01:59:47 -0000	1.36
+++ bin/rm/rm.c	29 Mar 2002 09:44:19 -0000
@@ -237,7 +237,7 @@
 		if (!uid &&
 		    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 		    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
-			rval = chflags(p->fts_accpath,
+			rval = lchflags(p->fts_accpath,
 				       p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 		if (rval == 0) {
 			/*
@@ -327,7 +327,7 @@
 		if (!uid &&
 		    (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 		    !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
-			rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
+			rval = lchflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
 		if (rval == 0) {
 			if (S_ISWHT(sb.st_mode))
 				rval = undelete(f);
Index: contrib/gdb/gdb/proc-events.c
===================================================================
RCS file: /cvs/src/contrib/gdb/gdb/proc-events.c,v
retrieving revision 1.1.1.1
diff -u -u -r1.1.1.1 proc-events.c
--- contrib/gdb/gdb/proc-events.c	4 Aug 2000 09:34:08 -0000	1.1.1.1
+++ contrib/gdb/gdb/proc-events.c	29 Mar 2002 09:44:19 -0000
@@ -525,6 +525,12 @@
 #if defined (SYS_ksigqueue)
   syscall_table[SYS_ksigqueue] = "ksigqueue";
 #endif
+#if defined (SYS_lchflags)
+  syscall_table[SYS_lchflags] = "lchflags";
+#endif
+#if defined (SYS_lchmod)
+  syscall_table[SYS_lchmod] = "lchmod";
+#endif
 #if defined (SYS_lchown)
   syscall_table[SYS_lchown] = "lchown";
 #endif
@@ -548,6 +554,9 @@
 #endif
 #if defined (SYS_lstat64)
   syscall_table[SYS_lstat64] = "lstat64";
+#endif
+#if defined (SYS_lutimes)
+  syscall_table[SYS_lutimes] = "lutimes";
 #endif
 #if defined (SYS_lvldom)
   syscall_table[SYS_lvldom] = "lvldom";
Index: lib/libc/sys/chflags.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/chflags.2,v
retrieving revision 1.19
diff -u -u -r1.19 chflags.2
--- lib/libc/sys/chflags.2	1 Oct 2001 16:09:01 -0000	1.19
+++ lib/libc/sys/chflags.2	29 Mar 2002 09:44:19 -0000
@@ -37,7 +37,8 @@
 .Os
 .Sh NAME
 .Nm chflags ,
-.Nm fchflags
+.Nm fchflags ,
+.Nm lchflags
 .Nd set file flags
 .Sh LIBRARY
 .Lb libc
@@ -48,6 +49,8 @@
 .Fn chflags "const char *path"  "u_long flags"
 .Ft int
 .Fn fchflags "int fd" "u_long flags"
+.Ft int
+.Fn lchflags "const char *path"  "u_long flags"
 .Sh DESCRIPTION
 The file whose name
 is given by
@@ -57,6 +60,11 @@
 has its flags changed to
 .Fa flags .
 .Pp
+.Fn Lchflags
+is similar to
+.Fn chflags
+but does not follow symbolic links.
+.Pp
 The flags specified are formed by
 .Em or Ns 'ing
 the following values
@@ -171,3 +179,7 @@
 .Nm fchflags
 functions first appeared in
 .Bx 4.4 .
+The
+.Fn lchflags
+function first appeared in
+.Nx 1.5 .
Index: sbin/restore/tape.c
===================================================================
RCS file: /cvs/src/sbin/restore/tape.c,v
retrieving revision 1.32
diff -u -u -r1.32 tape.c
--- sbin/restore/tape.c	2 May 2002 17:39:19 -0000	1.32
+++ sbin/restore/tape.c	6 May 2002 01:12:31 -0000
@@ -529,6 +529,8 @@
 extractfile(char *name)
 {
 	int flags;
+	uid_t uid;
+	gid_t gid;
 	mode_t mode;
 	struct timeval timep[2];
 	struct entry *ep;
@@ -539,6 +541,8 @@
 	timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
 	timep[1].tv_sec = curfile.dip->di_mtime;
 	timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
+	uid = curfile.dip->di_uid;
+	gid = curfile.dip->di_gid;
 	mode = curfile.dip->di_mode;
 	flags = curfile.dip->di_flags;
 	switch (mode & IFMT) {
@@ -565,14 +569,6 @@
 		return (genliteraldir(name, curfile.ino));
 
 	case IFLNK:
-	  {
-		uid_t uid;
-		gid_t gid;
-		int ret;
-
-		uid = curfile.dip->di_uid;
-		gid = curfile.dip->di_gid;
-
 		lnkbuf[0] = '\0';
 		pathlen = 0;
 		getfile(xtrlnkfile, xtrlnkskip);
@@ -581,17 +577,14 @@
 			    "%s: zero length symbolic link (ignored)\n", name);
 			return (GOOD);
 		}
-		ret = linkit(lnkbuf, name, SYMLINK);
-		if (ret == GOOD) {
-			if (lchown(name, uid, gid))
-				perror(name);
-			if (lchmod(name, mode))
-				perror(name);
-			lutimes(name, timep);
-		}
-		/* symbolic link doesn't have any flags */
-		return (ret);
-	  }
+		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
+			(void) lchown(name, uid, gid);
+			(void) lchmod(name, mode);
+			(void) lutimes(name, timep);
+			(void) lchflags(name, flags);
+			return (GOOD);
+		}
+		return (FAIL);
 
 	case IFIFO:
 		vprintf(stdout, "extract fifo %s\n", name);
@@ -607,9 +600,9 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+		(void) chown(name, uid, gid);
 		(void) chmod(name, mode);
-		utimes(name, timep);
+		(void) utimes(name, timep);
 		(void) chflags(name, flags);
 		skipfile();
 		return (GOOD);
@@ -629,9 +622,9 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+		(void) chown(name, uid, gid);
 		(void) chmod(name, mode);
-		utimes(name, timep);
+		(void) utimes(name, timep);
 		(void) chflags(name, flags);
 		skipfile();
 		return (GOOD);
@@ -651,7 +644,7 @@
 			skipfile();
 			return (FAIL);
 		}
-		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
+		(void) fchown(ofile, uid, gid);
 		(void) fchmod(ofile, mode);
 		getfile(xtrfile, xtrskip);
 		(void) close(ofile);
Index: usr.bin/chflags/chflags.1
===================================================================
RCS file: /cvs/src/usr.bin/chflags/chflags.1,v
retrieving revision 1.14
diff -u -u -r1.14 chflags.1
--- usr.bin/chflags/chflags.1	15 Aug 2001 09:09:39 -0000	1.14
+++ usr.bin/chflags/chflags.1	29 Mar 2002 09:44:22 -0000
@@ -47,6 +47,7 @@
 .Fl R
 .Op Fl H | Fl L | Fl P
 .Oc
+.Op Fl h 
 .Ar flags
 .Ar
 .Sh DESCRIPTION
@@ -76,6 +77,11 @@
 .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 
+.Ar file 
+or a file encountered during directory traversal is a symbolic link, 
+the file flags of the link itself are changed. 
 .El
 .Pp
 The flags are specified as an octal number or a comma separated list
@@ -117,13 +123,6 @@
 the immutable bit should be cleared
 .El
 .Pp
-Symbolic links do not have flags, so unless the
-.Fl H
-or
-.Fl L
-option is set,
-.Nm
-on a symbolic link always succeeds and has no effect.
 The
 .Fl H ,
 .Fl L
@@ -141,6 +140,7 @@
 .Sh SEE ALSO
 .Xr ls 1 ,
 .Xr chflags 2 ,
+.Xr lchflags 2 ,
 .Xr stat 2 ,
 .Xr fts 3 ,
 .Xr symlink 7
Index: usr.bin/chflags/chflags.c
===================================================================
RCS file: /cvs/src/usr.bin/chflags/chflags.c,v
retrieving revision 1.14
diff -u -u -r1.14 chflags.c
--- usr.bin/chflags/chflags.c	22 Mar 2002 01:19:26 -0000	1.14
+++ usr.bin/chflags/chflags.c	29 Mar 2002 11:02:11 -0000
@@ -67,13 +67,14 @@
 {
 	FTS *ftsp;
 	FTSENT *p;
-	u_long clear, set;
+	u_long clear, set, newflags;
 	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;
+	int (*change_flags) __P((const char *, u_long));
 
-	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;
@@ -90,6 +91,9 @@
 		case 'R':
 			Rflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -109,7 +113,7 @@
 			fts_options |= FTS_LOGICAL;
 		}
 	} else
-		fts_options = FTS_LOGICAL;
+		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
 
 	flags = *argv;
 	if (*flags >= '0' && *flags <= '7') {
@@ -134,6 +138,7 @@
 		err(1, NULL);
 
 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+		change_flags = chflags;
 		switch (p->fts_info) {
 		case FTS_D:
 			if (Rflag)		/* Change it at FTS_DP. */
@@ -149,28 +154,44 @@
 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
 			rval = 1;
 			continue;
-		case FTS_SL:			/* Ignore. */
+		case FTS_SL:			/* Ignore unless -h. */ 
+			/* 
+			 * All symlinks we found while doing a physical 
+			 * walk end up here. 
+			 */ 
+			if (!hflag) 
+				continue; 
+			/* 
+			 * Note that if we follow a symlink, fts_info is 
+			 * not FTS_SL but FTS_F or whatever.  And we should 
+			 * use lchflags only for FTS_SL and should use chflags 
+			 * for others. 
+			 */ 
+			change_flags = lchflags; 
+			break; 
+
 		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.
+			 * don't point to anything. Note that if we are 
+			 * doing a physical walk, we never reach here unless 
+			 * we asked to follow explicitly (with -H or -L).
 			 */
 			continue;
 		default:
 			break;
 		}
-		if (oct) {
-			if (!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))
-				continue;
+		if (oct)
+			newflags = set;
+		else {
+			newflags = p->fts_statp->st_flags;
+			newflags |= set;
+			newflags &= clear;
+		}
+		if ((*change_flags)(p->fts_accpath, newflags)) {
+			warn("%s", p->fts_path);
+			rval = 1;
 		}
-		warn("%s", p->fts_path);
-		rval = 1;
 	}
 	if (errno)
 		err(1, "fts_read");
@@ -181,6 +202,6 @@
 usage()
 {
 	(void)fprintf(stderr,
-	    "usage: chflags [-R [-H | -L | -P]] flags file ...\n");
+	    "usage: chflags [-R [-H | -L | -P]] [-h] flags file ...\n");
 	exit(1);
 }
Index: usr.bin/find/function.c
===================================================================
RCS file: /cvs/src/usr.bin/find/function.c,v
retrieving revision 1.42
diff -u -u -r1.42 function.c
--- usr.bin/find/function.c	2 Apr 2002 10:45:34 -0000	1.42
+++ usr.bin/find/function.c	8 Apr 2002 12:00:38 -0000
@@ -400,7 +400,7 @@
 	if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 	    !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
 	    geteuid() == 0)
-		chflags(entry->fts_accpath,
+		lchflags(entry->fts_accpath,
 		       entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 
 	/* rmdir directories, unlink everything else */
Index: usr.sbin/mtree/compare.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/compare.c,v
retrieving revision 1.20
diff -u -u -r1.20 compare.c
--- usr.sbin/mtree/compare.c	6 Oct 2000 12:48:55 -0000	1.20
+++ usr.sbin/mtree/compare.c	29 Mar 2002 09:44:22 -0000
@@ -60,7 +60,7 @@
 #include "mtree.h"
 #include "extern.h"
 
-extern int uflag;
+extern int Lflag, uflag;
 extern int lineno;
 
 static char *ftype __P((u_int));
@@ -125,7 +125,7 @@
 		(void)printf("%suser expected %lu found %lu",
 		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
 		if (uflag)
-			if (chown(p->fts_accpath, s->st_uid, -1))
+			if ((Lflag ? chown : lchown)(p->fts_accpath, s->st_uid, -1))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -139,7 +139,7 @@
 		(void)printf("%sgid expected %lu found %lu",
 		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
 		if (uflag)
-			if (chown(p->fts_accpath, -1, s->st_gid))
+			if ((Lflag ? chown : lchown)(p->fts_accpath, -1, s->st_gid))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -231,7 +231,7 @@
 		free(fflags);
 
 		if (uflag)
-			if (chflags(p->fts_accpath, s->st_flags))
+			if ((Lflag ? chflags : lchflags)(p->fts_accpath, s->st_flags))
 				(void)printf(" not modified: %s\n",
 				    strerror(errno));
 			else
@@ -299,7 +299,7 @@
 	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
 		LABEL;
 		(void)printf("%slink_ref expected %s found %s\n",
-		      tab, cp, s->slink);
+		      tab, s->slink, cp);
 	}
 	return (label);
 }
Index: usr.sbin/mtree/mtree.8
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.8,v
retrieving revision 1.35
diff -u -u -r1.35 mtree.8
--- usr.sbin/mtree/mtree.8	15 Aug 2001 09:09:46 -0000	1.35
+++ usr.sbin/mtree/mtree.8	29 Mar 2002 09:44:22 -0000
@@ -76,7 +76,7 @@
 Don't follow symbolic links in the file hierarchy, instead consider
 the symbolic link itself in any comparisons. This is the default.
 .It Fl U
-Modify the owner, group and permissions of existing files to match
+Modify the owner, group, flags and permissions of existing files to match
 the specification and create any missing directories or symbolic links.
 User, group and permissions must all be specified for missing directories
 to be created.
Index: usr.sbin/mtree/mtree.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.c,v
retrieving revision 1.18
diff -u -u -r1.18 mtree.c
--- usr.sbin/mtree/mtree.c	25 Sep 2000 16:24:22 -0000	1.18
+++ usr.sbin/mtree/mtree.c	29 Mar 2002 09:44:22 -0000
@@ -58,7 +58,7 @@
 extern long int crc_total;
 
 int ftsoptions = FTS_PHYSICAL;
-int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag;
+int cflag, dflag, eflag, iflag, Lflag, nflag, qflag, rflag, sflag, uflag, Uflag;
 u_int keys;
 char fullpath[MAXPATHLEN];
 
@@ -107,6 +107,7 @@
 					keys |= parsekey(p, NULL);
 			break;
 		case 'L':
+			Lflag = 1;
 			ftsoptions &= ~FTS_PHYSICAL;
 			ftsoptions |= FTS_LOGICAL;
 			break;
Index: usr.sbin/mtree/verify.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/verify.c,v
retrieving revision 1.15
diff -u -u -r1.15 verify.c
--- usr.sbin/mtree/verify.c	3 Oct 2000 13:13:47 -0000	1.15
+++ usr.sbin/mtree/verify.c	29 Mar 2002 09:44:22 -0000
@@ -205,6 +205,10 @@
 				if (lchown(path, p->st_uid, p->st_gid))
 					(void)printf("%s: user/group not modified: %s\n",
 					    path, strerror(errno));
+				if ((p->flags & F_FLAGS) && p->st_flags &&
+					lchflags(path, p->st_flags))
+					(void)printf("%s: symlink flags not set: %s\n",
+					    path, strerror(errno));
 				continue;
 			} else if (!(p->flags & F_MODE))
 			    (void)printf(" (directory not created: mode not specified)");
Index: usr.sbin/pkg_install/add/extract.c
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_install/add/extract.c,v
retrieving revision 1.31
diff -u -u -r1.31 extract.c
--- usr.sbin/pkg_install/add/extract.c	1 Apr 2002 09:39:05 -0000	1.31
+++ usr.sbin/pkg_install/add/extract.c	8 Apr 2002 12:01:19 -0000
@@ -60,7 +60,7 @@
 	if (q->type == PLIST_FILE) {
 	    snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name);
 	    if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) {
-		(void)chflags(try, 0);
+		(void)lchflags(try, 0);
 		(void)unlink(try);
 		if (rename(bup, try))
 		    warnx("rollback: unable to rename %s back to %s", bup, try);
@@ -136,7 +136,7 @@
 		/* first try to rename it into place */
 		snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name);
 		if (fexists(try)) {
-		    (void)chflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
+		    (void)lchflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
 		    if (preserve && PkgName) {
 			char pf[FILENAME_MAX];
Comment 5 Robert Watson freebsd_committer freebsd_triage 2002-05-06 04:09:20 UTC
Responsible Changed
From-To: alfred->mux

Maxime committed a parallel (and largely identical) version of the kernel 
code, but didn't know about this PR.  He should go ahead and do the userland 
stuff documented here.
Comment 6 Joshua Goodall 2002-12-04 01:17:42 UTC
Latest rev of this patch attached.

J
Comment 7 Alexander Best freebsd_committer freebsd_triage 2010-08-21 01:22:46 UTC
State Changed
From-To: open->feedback

It appears lchflags support has now been fully integrated into FreeBSD. 
However this needs to be confirmed. Also it is unclear, if lchflags support is 
present in all branches.
Comment 8 gcooper freebsd_committer freebsd_triage 2011-01-17 21:55:25 UTC
    lchflags was added to base over 8 yerars ago [1]. Please close this PR.
Thanks,
-Garrett

1. http://svn.freebsd.org/viewvc/base?view=revision&revision=96085
Comment 9 Joshua Goodall 2011-01-18 00:07:12 UTC
 On Mon, 17 Jan 2011 13:55:25 -0800, Garrett Cooper 
 <gcooper@FreeBSD.org> wrote:
> lchflags was added to base over 8 yerars ago [1]. Please close this 
> PR.
> Thanks,
> -Garrett
>
> 1. http://svn.freebsd.org/viewvc/base?view=revision&revision=96085

 Yet after all these years the PR has still not been fully committed. 
 The gap in mtree's -L implementation may still remain and pkg_install 
 was not updated.

 Had it been fully committed at the time then PRs bin/111226 and 
 bin/101660 may not have arisen.

 The syscall committed has a signature different to that in the PR, but 
 I doubt this will be fixed.

 Thanks
 Josh
Comment 10 gcooper freebsd_committer freebsd_triage 2011-01-18 00:46:14 UTC
On Mon, Jan 17, 2011 at 4:07 PM, Joshua Goodall <joshua@roughtrade.net> wrote:
>
> On Mon, 17 Jan 2011 13:55:25 -0800, Garrett Cooper <gcooper@FreeBSD.org>
> wrote:
>>
>> lchflags was added to base over 8 years ago [1]. Please close this PR.
>>
>> 1. http://svn.freebsd.org/viewvc/base?view=revision&revision=96085
>
> Yet after all these years the PR has still not been fully committed. The gap
> in mtree's -L implementation may still remain and pkg_install was not
> updated.

    Some of this logic is in the right direction, but it warrants
closer inspection as this may break utilities by accident. I'll see
whether or not it's the case and open another PR and/or attach it to
the one I have open for mtree -L not doing the right thing.

> Had it been fully committed at the time then PRs bin/111226 and bin/101660
> may not have arisen.

    You may be right, but unfortunately I can't change mistakes made
in the past :(.

> The syscall committed has a signature different to that in the PR, but I
> doubt this will be fixed.

    Well, that awesome inconsistency is going to be fixed soon (I
hope) via a patch I sent to fs@ as the calls should all be the same
and there's a bi-arch issue when using unsigned long as the flags
argument in chflags(2) / fchflags(2). It should be listed in the
archives in ~12 hours:
http://lists.freebsd.org/pipermail/freebsd-fs/2011-January/thread.html
.
Thanks,
-Garrett
Comment 11 Mark Linimon freebsd_committer freebsd_triage 2011-06-23 19:03:56 UTC
Responsible Changed
From-To: mux->freebsd-bugs

mux has returned his commit bit for safekeeping.
Comment 12 Eitan Adler freebsd_committer freebsd_triage 2012-11-13 20:50:19 UTC
State Changed
From-To: feedback->closed

at this point mtree will be  replaced with      the netbsd one and so 
many other changes have or will be made that this PR need not be open