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 [EMAIL PROTECTED] "Your byte hit ratio is weak, old man" "If you cache me now, I will dump more core than you can possibly imagine"
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];