| Summary: | [kernel] [patch] add lchflags support | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | Joshua Goodall <joshua> | ||||
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | Unspecified | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
|
Description
Joshua Goodall
2001-08-01 01:30:00 UTC
Responsible Changed From-To: freebsd-bugs->adrian I already told Joshua that I'd take care of this. (when I get home. :-) [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]; 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. 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];
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. Latest rev of this patch attached. J 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. 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 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 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 Responsible Changed From-To: mux->freebsd-bugs mux has returned his commit bit for safekeeping. 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 |