Date: Mon, 19 Feb 2007 12:14:03 +0100 From: "Raphael H. Becker" <rabe@p-i-n.com> To: freebsd-ports@freebsd.org Subject: Re: rsync with --flags patch: unable to rsync hardlinks to files w/ schg Message-ID: <20070219111403.GA27069@p-i-n.com>
next in thread | raw e-mail | index | archive | help
--+HP7ph2BbKc20aGI Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi *, i've contacted Rolf Grossmann, the maintainer of net/rsync/work/rsync-2.6.9/patches/flags.diff He enhanced this patch to handle hardlinks to schg-files gracefully. This patch is expected to get into 2.6.10. I've attached the patch to this mail, it works for me. Just copy it over work/rsync-2.6.9/patches/flags.diff after "make extract" and before "make patch" and "make". Regards Raphael Becker On Fri, Dec 08, 2006 at 01:24:22PM +0100, Raphael H. Becker wrote: > > Hi *, > > we're running two jail-hosts with some jails in it. The two hosts (will) > replicate the active jails to each other to have a fallback. > > On the backup-host I run the following command: > > rsync -avHWx -e ssh --flags --delete root@jailhost1.dmz:/data/jails/ /data/jails > > Doing so brings me the following errors for each jail: > > rsync: link "/data/jails/jail4711/usr/bin/chfn" => jail4711/usr/bin/ypchsh failed: Operation not permitted (1) > rsync: link "/data/jails/jail4711/usr/bin/chpass" => jail4711/usr/bin/ypchsh failed: Operation not permitted (1) > rsync: link "/data/jails/jail4711/usr/bin/chsh" => jail4711/usr/bin/ypchsh failed: Operation not permitted (1) > rsync: link "/data/jails/jail4711/usr/bin/ypchfn" => jail4711/usr/bin/ypchsh failed: Operation not permitted (1) > rsync: link "/data/jails/jail4711/usr/bin/ypchpass" => jail4711/usr/bin/ypchsh failed: Operation not permitted (1) > rsync: link "/data/jails/jail4711/usr/bin/passwd" => jail4711/usr/bin/yppasswd failed: Operation not permitted (1) > > These files have the "schg" flag on jailhost1, which get rsynced to > jailhost2. Theese files are not present on jailhost2 after this: > > ls: /data/jails/jail4711/usr/bin/passwd: No such file or directory > > Any idea how to get rid of this? > > Regards > Raphael Becker --+HP7ph2BbKc20aGI Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="rsync-2.6.9.flags.diff" diff -bru rsync-2.6.9/backup.c rsync-2.6.9.chflags/backup.c --- rsync-2.6.9/backup.c Wed Apr 26 01:51:12 2006 +++ rsync-2.6.9.chflags/backup.c Mon Jan 29 16:09:26 2007 @@ -61,7 +61,17 @@ return 0; while (1) { - if (do_rename(fname, fnamebak) == 0) { +#ifdef SUPPORT_FLAGS + STRUCT_STAT st2; + + link_stat(fname, &st2, 0); + make_mutable(fname, st2.st_mode, st2.st_flags); +#endif + if (do_rename(fname, fnamebak) == 0) + { +#ifdef SUPPORT_FLAGS + undo_make_mutable(fnamebak, st2.st_mode, st2.st_flags); +#endif if (verbose > 1) { rprintf(FINFO, "backed up %s to %s\n", fname, fnamebak); diff -bru rsync-2.6.9/config.h.in rsync-2.6.9.chflags/config.h.in --- rsync-2.6.9/config.h.in Tue Nov 7 05:39:47 2006 +++ rsync-2.6.9.chflags/config.h.in Tue Jan 9 15:25:04 2007 @@ -49,6 +49,9 @@ /* Define to 1 if vsprintf has a C99-compatible return value */ #undef HAVE_C99_VSNPRINTF +/* Define if you have the `chflags' function. */ +#undef HAVE_CHFLAGS + /* Define to 1 if you have the `chmod' function. */ #undef HAVE_CHMOD diff -bru rsync-2.6.9/configure rsync-2.6.9.chflags/configure --- rsync-2.6.9/configure Tue Nov 7 05:39:47 2006 +++ rsync-2.6.9.chflags/configure Sat Dec 9 01:28:24 2006 @@ -13474,7 +13474,7 @@ -for ac_func in waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ +for ac_func in waitpid wait4 getcwd strdup chown chflags chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \ strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ diff -bru rsync-2.6.9/configure.in rsync-2.6.9.chflags/configure.in --- rsync-2.6.9/configure.in Tue Nov 7 05:39:47 2006 +++ rsync-2.6.9.chflags/configure.in Sat Dec 9 01:29:17 2006 @@ -522,7 +522,7 @@ AC_FUNC_UTIME_NULL AC_FUNC_ALLOCA -AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ +AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chflags chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \ strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ diff -bru rsync-2.6.9/flist.c rsync-2.6.9.chflags/flist.c --- rsync-2.6.9/flist.c Sat Oct 14 03:17:36 2006 +++ rsync-2.6.9.chflags/flist.c Mon Jan 29 16:24:16 2007 @@ -44,6 +44,7 @@ extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; +extern int preserve_flags; extern int preserve_uid; extern int preserve_gid; extern int relative_paths; @@ -303,6 +304,9 @@ unsigned short flags; static time_t modtime; static mode_t mode; +#ifdef SUPPORT_FLAGS + static uint32 fileflags; +#endif static int64 dev; static dev_t rdev; static uint32 rdev_major; @@ -321,6 +325,9 @@ dev = 0, rdev = MAKEDEV(0, 0); rdev_major = 0; uid = 0, gid = 0; +#ifdef SUPPORT_FLAGS + fileflags = 0; +#endif *lastname = '\0'; return; } @@ -333,6 +340,12 @@ flags |= XMIT_SAME_MODE; else mode = file->mode; +#ifdef SUPPORT_FLAGS + if (file->fileflags == fileflags) + flags |= XMIT_SAME_FLAGS; + else + fileflags = file->fileflags; +#endif if ((preserve_devices && IS_DEVICE(mode)) || (preserve_specials && IS_SPECIAL(mode))) { if (protocol_version < 28) { @@ -416,6 +429,10 @@ write_int(f, modtime); if (!(flags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); +#if SUPPORT_FLAGS + if (preserve_flags && !(flags & XMIT_SAME_FLAGS)) + write_int(f, fileflags); +#endif if (preserve_uid && !(flags & XMIT_SAME_UID)) { if (!numeric_ids) add_uid(uid); @@ -483,6 +500,9 @@ { static time_t modtime; static mode_t mode; +#ifdef SUPPORT_FLAGS + static uint32 fileflags; +#endif static int64 dev; static dev_t rdev; static uint32 rdev_major; @@ -501,6 +521,9 @@ if (!flist) { modtime = 0, mode = 0; +#ifdef SUPPORT_FLAGS + fileflags = 0; +#endif dev = 0, rdev = MAKEDEV(0, 0); rdev_major = 0; uid = 0, gid = 0; @@ -560,6 +583,11 @@ if (chmod_modes && !S_ISLNK(mode)) mode = tweak_mode(mode, chmod_modes); +#ifdef SUPPORT_FLAGS + if (preserve_flags && !(flags & XMIT_SAME_FLAGS)) + fileflags = (uint32)read_int(f); +#endif + if (preserve_uid && !(flags & XMIT_SAME_UID)) uid = (uid_t)read_int(f); if (preserve_gid && !(flags & XMIT_SAME_GID)) @@ -609,6 +637,9 @@ file->modtime = modtime; file->length = file_length; file->mode = mode; +#ifdef SUPPORT_FLAGS + file->fileflags = fileflags; +#endif file->uid = uid; file->gid = gid; @@ -862,6 +893,9 @@ file->modtime = st.st_mtime; file->length = st.st_size; file->mode = st.st_mode; +#if SUPPORT_FLAGS + file->fileflags = st.st_flags; +#endif file->uid = st.st_uid; file->gid = st.st_gid; diff -bru rsync-2.6.9/hlink.c rsync-2.6.9.chflags/hlink.c --- rsync-2.6.9/hlink.c Tue Oct 17 20:49:04 2006 +++ rsync-2.6.9.chflags/hlink.c Tue Jan 9 23:53:43 2007 @@ -253,6 +253,12 @@ int statret, STRUCT_STAT *st, char *toname, int terse, int itemizing, enum logcode code) { +#if SUPPORT_FLAGS + STRUCT_STAT st2; + + link_stat(toname, &st2, 0); + make_mutable(toname, st2.st_mode, st2.st_flags); +#endif if (do_link(toname, fname)) { if (terse) { if (!verbose) @@ -264,6 +270,9 @@ full_fname(fname), toname); return -1; } +#if SUPPORT_FLAGS + undo_make_mutable(toname, st2.st_mode, st2.st_flags); +#endif if (itemizing) { itemize(file, ndx, statret, st, diff -bru rsync-2.6.9/options.c rsync-2.6.9.chflags/options.c --- rsync-2.6.9/options.c Tue Oct 24 02:36:38 2006 +++ rsync-2.6.9.chflags/options.c Tue Jan 9 17:46:57 2007 @@ -48,6 +48,7 @@ int preserve_links = 0; int preserve_hard_links = 0; int preserve_perms = 0; +int preserve_flags = 0; int preserve_executability = 0; int preserve_devices = 0; int preserve_specials = 0; @@ -201,6 +202,7 @@ char const *hardlinks = "no "; char const *links = "no "; char const *ipv6 = "no "; + char const *fflags = "no "; STRUCT_STAT *dumstat; #ifdef HAVE_SOCKETPAIR @@ -223,6 +225,10 @@ ipv6 = ""; #endif +#if SUPPORT_FLAGS + fflags = ""; +#endif + rprintf(f, "%s version %s protocol version %d\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION); rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n"); @@ -235,9 +241,9 @@ /* Note that this field may not have type ino_t. It depends * on the complicated interaction between largefile feature * macros. */ - rprintf(f, " %sinplace, %sIPv6, " + rprintf(f, " %sinplace, %sIPv6, %sfile flags, " "%d-bit system inums, %d-bit internal inums\n", - have_inplace, ipv6, + have_inplace, ipv6, fflags, (int) (sizeof dumstat->st_ino * 8), (int) (sizeof (int64) * 8)); #ifdef MAINTAINER_MODE @@ -304,6 +310,7 @@ rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -H, --hard-links preserve hard links\n"); rprintf(F," -p, --perms preserve permissions\n"); + rprintf(F," --flags preserve file flags\n"); rprintf(F," -E, --executability preserve the file's executability\n"); rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); rprintf(F," -o, --owner preserve owner (super-user only)\n"); @@ -424,6 +431,8 @@ {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 }, {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, + {"flags", 0, POPT_ARG_VAL, &preserve_flags, 1, 0, 0 }, + {"no-flags", 0, POPT_ARG_VAL, &preserve_flags, 0, 0, 0 }, {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, @@ -943,6 +952,9 @@ preserve_uid = 1; preserve_devices = 1; preserve_specials = 1; +#if 0 && SUPPORT_FLAGS /* XXX maybe with the next major release */ + preserve_flags=1; +#endif break; case 'D': @@ -1128,6 +1140,15 @@ } #endif +#ifndef SUPPORT_FLAGS + if (preserve_flags) { + snprintf(err_buf,sizeof err_buf, + "file flags are not supported on this %s\n", + am_server ? "server" : "client"); + return 0; + } +#endif + if (write_batch && read_batch) { snprintf(err_buf, sizeof err_buf, "--write-batch and --read-batch can not be used together\n"); @@ -1580,6 +1601,9 @@ * sans -r because the --no-r option was added at the same time. */ if (xfer_dirs && !recurse && delete_mode && am_sender) args[ac++] = "--no-r"; + + if (preserve_flags) + args[ac++] = "--flags"; if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) { if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0) diff -bru rsync-2.6.9/proto.h rsync-2.6.9.chflags/proto.h --- rsync-2.6.9/proto.h Tue Nov 7 05:39:47 2006 +++ rsync-2.6.9.chflags/proto.h Tue Jan 9 23:51:45 2007 @@ -224,6 +224,8 @@ void setup_iconv(); void free_sums(struct sum_struct *s); mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists); +void make_mutable(const char *fname, mode_t mode, uint32 fileflags); +void undo_make_mutable(const char *fname, mode_t mode, uint32 fileflags); int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st, int flags); RETSIGTYPE sig_int(UNUSED(int val)); @@ -254,6 +256,7 @@ int do_rmdir(const char *pathname); int do_open(const char *pathname, int flags, mode_t mode); int do_chmod(const char *path, mode_t mode); +int do_chflags(const char *path, uint32 flags); int do_rename(const char *fname1, const char *fname2); void trim_trailing_slashes(char *name); int do_mkdir(char *fname, mode_t mode); diff -bru rsync-2.6.9/rsync.1 rsync-2.6.9.chflags/rsync.1 --- rsync-2.6.9/rsync.1 Tue Nov 7 05:39:51 2006 +++ rsync-2.6.9.chflags/rsync.1 Tue Jan 9 18:22:24 2007 @@ -387,6 +387,7 @@ \-K, \-\-keep\-dirlinks treat symlinked dir on receiver as dir \-H, \-\-hard\-links preserve hard links \-p, \-\-perms preserve permissions + \-\-flags preserve file flags \-E, \-\-executability preserve executability \-\-chmod=CHMOD affect file and/or directory permissions \-o, \-\-owner preserve owner (super-user only) @@ -591,7 +592,9 @@ .IP Note that \fB\-a\fP \fBdoes not preserve hardlinks\fP, because finding multiply-linked files is expensive\&. You must separately -specify \fB\-H\fP\&. +specify \fB\-H\fP\&. Note also that for compatibility, \fB\-a\fP +currently \fBdoes not include \-\-flags\fP (see there) to include preserving +change file flags (if supported by the OS)\&. .IP .IP "\-\-no\-OPTION" You may turn off one or more implied options by prefixing @@ -931,6 +934,14 @@ .IP If \fB\-\-perms\fP is enabled, this option is ignored\&. +.IP +.IP "\fB\-\-flags\fP" +This option causes rsync to update the change file flags +to be the same as the source file, if your OS supports the \fBchflags\fP(2) +system call\&. In any case, an attempt is made to remove flags that would +prevent a file to be altered\&. Some flags can only be altered by the +super-user and can only be unset below a certain secure-level (usually +single-user mode)\&. .IP .IP "\fB\-\-chmod\fP" This option tells rsync to apply one or more diff -bru rsync-2.6.9/rsync.c rsync-2.6.9.chflags/rsync.c --- rsync-2.6.9/rsync.c Mon Oct 9 00:02:13 2006 +++ rsync-2.6.9.chflags/rsync.c Mon Jan 29 17:15:23 2007 @@ -33,6 +33,7 @@ extern int verbose; extern int dry_run; extern int preserve_perms; +extern int preserve_flags; extern int preserve_executability; extern int preserve_times; extern int omit_dir_times; @@ -123,6 +124,41 @@ return new_mode; } +#ifdef SUPPORT_FLAGS +/* Set a file's st_flags. */ +static int set_fileflags(const char *fname, uint32 fileflags) +{ + if (do_chflags(fname, fileflags) != 0) { + rsyserr(FERROR, errno, "failed to set file flags on %s", + full_fname(fname)); + return 0; + } + + return 1; +} + +#define NOCHANGE_FLAGS (UF_IMMUTABLE | UF_APPEND | UF_NOUNLINK | SF_IMMUTABLE | SF_APPEND | SF_NOUNLINK) +/* Remove immutable flags from an object, so it can be altered. */ +void make_mutable(const char *fname, mode_t mode, uint32 fileflags) +{ + if (!preserve_flags || S_ISLNK(mode)) + return; + + if (fileflags & NOCHANGE_FLAGS) + do_chflags(fname, fileflags & ~NOCHANGE_FLAGS); +} + +/* Undo a prior make_mutable() call. */ +void undo_make_mutable(const char *fname, mode_t mode, uint32 fileflags) +{ + if (!preserve_flags || S_ISLNK(mode)) + return; + + if (fileflags & NOCHANGE_FLAGS) + set_fileflags(fname, fileflags); +} +#endif + int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st, int flags) { @@ -152,6 +188,9 @@ flags |= ATTRS_SKIP_MTIME; if (!(flags & ATTRS_SKIP_MTIME) && cmp_time(st->st_mtime, file->modtime) != 0) { +#ifdef SUPPORT_FLAGS + make_mutable(fname, st->st_mode, st->st_flags); +#endif int ret = set_modtime(fname, file->modtime, st->st_mode); if (ret < 0) { rsyserr(FERROR, errno, "failed to set times on %s", @@ -185,6 +224,9 @@ (long)st->st_gid, (long)file->gid); } } +#ifdef SUPPORT_FLAGS + make_mutable(fname, st->st_mode, st->st_flags); +#endif if (do_lchown(fname, change_uid ? file->uid : st->st_uid, change_gid ? file->gid : st->st_gid) != 0) { @@ -209,6 +251,9 @@ new_mode = tweak_mode(new_mode, daemon_chmod_modes); #ifdef HAVE_CHMOD if ((st->st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) { +#ifdef SUPPORT_FLAGS + make_mutable(fname, st->st_mode, st->st_flags); +#endif int ret = do_chmod(fname, new_mode); if (ret < 0) { rsyserr(FERROR, errno, @@ -221,6 +266,18 @@ } #endif +#ifdef SUPPORT_FLAGS + /* must be last change, because flags can forbid other changes */ + if (preserve_flags && !S_ISLNK(st->st_mode) && + (st->st_flags != file->fileflags || file->fileflags != 0)) { + if (set_fileflags(fname, file->fileflags) != 0) { + return 0; + } + if (st->st_flags != file->fileflags) + updated = 1; + } +#endif + if (verbose > 1 && flags & ATTRS_REPORT) { if (updated) rprintf(FCLIENT, "%s\n", fname); @@ -268,6 +325,9 @@ set_file_attrs(fnametmp, file, NULL, ok_to_set_time ? 0 : ATTRS_SKIP_MTIME); +#ifdef SUPPORT_FLAGS + make_mutable(fnametmp, file->mode, file->fileflags); +#endif /* move tmp file over real file */ if (verbose > 2) rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname); @@ -282,6 +342,9 @@ } if (ret == 0) { /* The file was moved into place (not copied), so it's done. */ +#ifdef SUPPORT_FLAGS + undo_make_mutable(fname, file->mode, file->fileflags); +#endif return; } /* The file was copied, so tweak the perms of the copied file. If it diff -bru rsync-2.6.9/rsync.h rsync-2.6.9.chflags/rsync.h --- rsync-2.6.9/rsync.h Tue Oct 24 05:31:30 2006 +++ rsync-2.6.9.chflags/rsync.h Mon Jan 29 17:15:57 2007 @@ -54,6 +54,7 @@ #define XMIT_HAS_IDEV_DATA (1<<9) #define XMIT_SAME_DEV (1<<10) #define XMIT_RDEV_MINOR_IS_SMALL (1<<11) +#define XMIT_SAME_FLAGS (1<<12) /* These flags are used in the live flist data. */ @@ -344,6 +345,10 @@ #define schar char #endif +#ifdef HAVE_CHFLAGS +#define SUPPORT_FLAGS 1 +#endif + /* Find a variable that is either exactly 32-bits or longer. * If some code depends on 32-bit truncation, it will need to * take special action in a "#if SIZEOF_INT32 > 4" section. */ @@ -530,6 +535,9 @@ uid_t uid; gid_t gid; mode_t mode; +#ifdef SUPPORT_FLAGS + uint32 fileflags; +#endif uchar flags; /* this item MUST remain last */ }; diff -bru rsync-2.6.9/rsync.yo rsync-2.6.9.chflags/rsync.yo --- rsync-2.6.9/rsync.yo Tue Nov 7 05:39:47 2006 +++ rsync-2.6.9.chflags/rsync.yo Tue Jan 9 18:17:13 2007 @@ -321,6 +321,7 @@ -K, --keep-dirlinks treat symlinked dir on receiver as dir -H, --hard-links preserve hard links -p, --perms preserve permissions + --flags preserve file flags -E, --executability preserve executability --chmod=CHMOD affect file and/or directory permissions -o, --owner preserve owner (super-user only) @@ -509,7 +510,9 @@ Note that bf(-a) bf(does not preserve hardlinks), because finding multiply-linked files is expensive. You must separately -specify bf(-H). +specify bf(-H). Note also that for compatibility, bf(-a) +currently bf(does not include --flags) (see there) to include preserving +change file flags (if supported by the OS). dit(--no-OPTION) You may turn off one or more implied options by prefixing the option name with "no-". Not all options may be prefixed with a "no-": @@ -804,6 +807,13 @@ If bf(--perms) is enabled, this option is ignored. +dit(bf(--flags)) This option causes rsync to update the change file flags +to be the same as the source file, if your OS supports the chflags(2) +system call. In any case, an attempt is made to remove flags that would +prevent a file to be altered. Some flags can only be altered by the +super-user and can only be unset below a certain securelevel (usually +single-user mode). + dit(bf(--chmod)) This option tells rsync to apply one or more comma-separated "chmod" strings to the permission of the files in the transfer. The resulting value is treated as though it was the permissions diff -bru rsync-2.6.9/syscall.c rsync-2.6.9.chflags/syscall.c --- rsync-2.6.9/syscall.c Wed Apr 26 01:51:15 2006 +++ rsync-2.6.9.chflags/syscall.c Sat Dec 9 03:07:15 2006 @@ -46,6 +46,9 @@ { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; +#if SUPPORT_FLAGS + chflags(fname, 0); +#endif return unlink(fname); } @@ -119,6 +122,9 @@ { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; +#if SUPPORT_FLAGS + chflags(pathname, 0); +#endif return rmdir(pathname); } @@ -152,10 +158,22 @@ } #endif +#if SUPPORT_FLAGS +int do_chflags(const char *path, uint32 flags) +{ + if (dry_run) return 0; + RETURN_ERROR_IF_RO_OR_LO; + return chflags(path, flags); +} +#endif + int do_rename(const char *fname1, const char *fname2) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; +#if SUPPORT_FLAGS + chflags(fname2, 0); +#endif return rename(fname1, fname2); } --+HP7ph2BbKc20aGI--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070219111403.GA27069>