Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Dec 2002 12:38:17 +1100
From:      Joshua Goodall <joshua@roughtrade.net>
To:        current@freebsd.org
Cc:        mux@freebsd.org
Subject:   [PATCH] lchflags userland
Message-ID:  <20021204013816.GA54075@roughtrade.net>

next in thread | raw e-mail | index | archive | help

--2oS5YaxWCcQjTEyO
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

These are the userland updates (and kernel consistency fixes) to
use the lchflags syscall.

Also sent to PR kern/29355, but I don't know if anyone was listening.

This was once described as "a textbook example of adding a new
syscall", but what's in the tree is only half the chapter.

Joshua

-- 
Joshua Goodall
joshua@roughtrade.net               "Your byte hit ratio is weak, old man"
"If you cache me now, I will dump more core than you can possibly imagine"

--2oS5YaxWCcQjTEyO
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="lchflags.diff"

Index: bin/cp/utils.c
===================================================================
RCS file: /cvs/src/bin/cp/utils.c,v
retrieving revision 1.39
diff -u -r1.39 utils.c
--- bin/cp/utils.c	18 Oct 2002 14:45:00 -0000	1.39
+++ bin/cp/utils.c	30 Nov 2002 13:02:57 -0000
@@ -211,7 +211,7 @@
 		warn("symlink: %s", llink);
 		return (1);
 	}
-	return (0);
+	return (pflag ? setfile(p->fts_statp, 0) : 0);
 }
 
 int
@@ -256,11 +256,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;
@@ -275,7 +275,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;
@@ -284,14 +284,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/rm/rm.c
===================================================================
RCS file: /cvs/src/bin/rm/rm.c,v
retrieving revision 1.42
diff -u -r1.42 rm.c
--- bin/rm/rm.c	21 Aug 2002 17:32:42 -0000	1.42
+++ bin/rm/rm.c	10 Sep 2002 13:41:37 -0000
@@ -239,7 +239,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) {
 			/*
@@ -329,7 +329,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: lib/libc/sys/chflags.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/chflags.2,v
retrieving revision 1.22
diff -u -r1.22 chflags.2
--- lib/libc/sys/chflags.2	15 Jul 2002 20:59:12 -0000	1.22
+++ lib/libc/sys/chflags.2	10 Sep 2002 13:41:37 -0000
@@ -48,9 +48,9 @@
 .Ft int
 .Fn chflags "const char *path"  "u_long flags"
 .Ft int
-.Fn lchflags "const char *path" "int 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
@@ -186,3 +186,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.37
diff -u -r1.37 tape.c
--- sbin/restore/tape.c	25 Sep 2002 04:06:37 -0000	1.37
+++ sbin/restore/tape.c	30 Nov 2002 13:09:50 -0000
@@ -574,6 +574,7 @@
 			(void) lchmod(name, mode);
 			(void) lutimes(name, ctimep);
 			(void) lutimes(name, mtimep);
+			(void) lchflags(name, flags);
 			return (GOOD);
 		}
 		return (FAIL);
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.297
diff -u -r1.297 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	27 Oct 2002 23:23:51 -0000	1.297
+++ sys/kern/vfs_syscalls.c	30 Nov 2002 13:11:52 -0000
@@ -1908,7 +1908,7 @@
 }
 
 /*
- * Common implementation code for chflags() and fchflags().
+ * Common implementation code for chflags(), lchflags and fchflags().
  */
 static int
 setfflags(td, vp, flags)
@@ -1982,8 +1982,15 @@
 }
 
 /*
- * Same as chflags() but doesn't follow symlinks.
+ * 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;
Index: sys/sys/stat.h
===================================================================
RCS file: /cvs/src/sys/sys/stat.h,v
retrieving revision 1.30
diff -u -r1.30 stat.h
--- sys/sys/stat.h	11 Oct 2002 15:52:14 -0000	1.30
+++ sys/sys/stat.h	1 Dec 2002 08:31:40 -0000
@@ -273,7 +273,7 @@
 
 #ifndef _POSIX_SOURCE
 int	chflags(const char *, unsigned long);
-int	lchflags(const char *, int);
+int	lchflags(const char *, unsigned long);
 int	fchflags(int, unsigned long);
 int	fchmod(int, mode_t);
 int	lchmod(const char *, mode_t);
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	10 Sep 2002 13:41:38 -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.16
diff -u -r1.16 chflags.c
--- usr.bin/chflags/chflags.c	4 Sep 2002 23:28:58 -0000	1.16
+++ usr.bin/chflags/chflags.c	10 Sep 2002 13:41:38 -0000
@@ -64,13 +64,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;
@@ -87,6 +88,9 @@
 		case 'R':
 			Rflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -106,7 +110,7 @@
 			fts_options |= FTS_LOGICAL;
 		}
 	} else
-		fts_options = FTS_LOGICAL;
+		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
 
 	flags = *argv;
 	if (*flags >= '0' && *flags <= '7') {
@@ -131,6 +135,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. */
@@ -146,28 +151,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");
@@ -178,6 +199,6 @@
 usage(void)
 {
 	(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.47
diff -u -r1.47 function.c
--- usr.bin/find/function.c	10 Aug 2002 20:19:03 -0000	1.47
+++ usr.bin/find/function.c	10 Sep 2002 13:41:38 -0000
@@ -403,7 +403,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.23
diff -u -r1.23 compare.c
--- usr.sbin/mtree/compare.c	15 Jul 2002 12:17:31 -0000	1.23
+++ usr.sbin/mtree/compare.c	10 Sep 2002 13:41:38 -0000
@@ -61,7 +61,7 @@
 #include "mtree.h"
 #include "extern.h"
 
-extern int uflag;
+extern int Lflag, uflag;
 extern int lineno;
 
 static const char *ftype(u_int);
@@ -127,7 +127,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
@@ -141,7 +141,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
@@ -233,7 +233,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
@@ -301,7 +301,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.38
diff -u -r1.38 mtree.8
--- usr.sbin/mtree/mtree.8	14 Jul 2002 14:44:30 -0000	1.38
+++ usr.sbin/mtree/mtree.8	10 Sep 2002 13:41:38 -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.20
diff -u -r1.20 mtree.c
--- usr.sbin/mtree/mtree.c	11 Jul 2002 18:42:53 -0000	1.20
+++ usr.sbin/mtree/mtree.c	10 Sep 2002 13:41:38 -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];
 
@@ -105,6 +105,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.17
diff -u -r1.17 verify.c
--- usr.sbin/mtree/verify.c	11 Jul 2002 18:42:53 -0000	1.17
+++ usr.sbin/mtree/verify.c	10 Sep 2002 13:41:38 -0000
@@ -206,6 +206,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.35
diff -u -r1.35 extract.c
--- usr.sbin/pkg_install/add/extract.c	2 Aug 2002 17:28:02 -0000	1.35
+++ usr.sbin/pkg_install/add/extract.c	10 Sep 2002 13:41:38 -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];
 

--2oS5YaxWCcQjTEyO--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




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