From owner-svn-src-projects@FreeBSD.ORG Mon Jan 7 23:35:41 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id CA634D8A; Mon, 7 Jan 2013 23:35:41 +0000 (UTC) (envelope-from brooks@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id BCD30D49; Mon, 7 Jan 2013 23:35:41 +0000 (UTC) Received: from svn.freebsd.org (svn.FreeBSD.org [8.8.178.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r07NZf2Z027627; Mon, 7 Jan 2013 23:35:41 GMT (envelope-from brooks@svn.freebsd.org) Received: (from brooks@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r07NZfUw027620; Mon, 7 Jan 2013 23:35:41 GMT (envelope-from brooks@svn.freebsd.org) Message-Id: <201301072335.r07NZfUw027620@svn.freebsd.org> From: Brooks Davis Date: Mon, 7 Jan 2013 23:35:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r245138 - projects/mtree/usr.bin/xinstall X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Jan 2013 23:35:41 -0000 Author: brooks Date: Mon Jan 7 23:35:40 2013 New Revision: 245138 URL: http://svnweb.freebsd.org/changeset/base/245138 Log: Implement the -M option and related -D , -h , and -T options from NetBSD. Obtained from: NetBSD Modified: projects/mtree/usr.bin/xinstall/Makefile projects/mtree/usr.bin/xinstall/install.1 projects/mtree/usr.bin/xinstall/xinstall.c Modified: projects/mtree/usr.bin/xinstall/Makefile ============================================================================== --- projects/mtree/usr.bin/xinstall/Makefile Mon Jan 7 23:30:53 2013 (r245137) +++ projects/mtree/usr.bin/xinstall/Makefile Mon Jan 7 23:35:40 2013 (r245138) @@ -10,7 +10,7 @@ MAN= install.1 CFLAGS+= -I${.CURDIR}/../../contrib/mtree CFLAGS+= -I${.CURDIR}/../../lib/libnetbsd -DPADD+= ${LIBUTIL} -LDADD+= -lutil +DPADD+= ${LIBUTIL} ${LIBMD} +LDADD+= -lutil -lmd .include Modified: projects/mtree/usr.bin/xinstall/install.1 ============================================================================== --- projects/mtree/usr.bin/xinstall/install.1 Mon Jan 7 23:30:53 2013 (r245137) +++ projects/mtree/usr.bin/xinstall/install.1 Mon Jan 7 23:35:40 2013 (r245138) @@ -38,30 +38,41 @@ .Nm .Op Fl bCcMpSsUv .Op Fl B Ar suffix +.Op Fl D Ar destdir .Op Fl f Ar flags .Op Fl g Ar group +.Op Fl h Ar hash .Op Fl l Ar linkflags +.Op Fl M Ar metalog .Op Fl m Ar mode .Op Fl N Ar dbdir .Op Fl o Ar owner +.Op Fl T Ar tags .Ar file1 file2 .Nm .Op Fl bCcMpSsUv .Op Fl B Ar suffix +.Op Fl D Ar destdir .Op Fl f Ar flags .Op Fl g Ar group +.Op Fl h Ar hash .Op Fl l Ar linkflags +.Op Fl M Ar metalog .Op Fl m Ar mode .Op Fl N Ar dbdir .Op Fl o Ar owner +.Op Fl T Ar tags .Ar file1 ... fileN directory .Nm .Fl d .Op Fl Uv +.Op Fl D Ar destdir .Op Fl g Ar group +.Op Fl M Ar metalog .Op Fl m Ar mode .Op Fl N Ar dbdir .Op Fl o Ar owner +.Op Fl T Ar tags .Ar directory ... .Sh DESCRIPTION The file(s) are copied @@ -112,6 +123,17 @@ This is actually the default. The .Fl c option is only included for backwards compatibility. +.It Fl D Ar destdir +Specify the +.Ev DESTDIR +(top of the file hierarchy) that the items are installed in to. +If +.Fl M Ar metalog +is in use, a leading string of +.Dq Ar destdir +will be removed from the file names logged to the +.Ar metalog . +This option does not affect where the actual files are installed. .It Fl d Create directories. Missing parent directories are created as required. @@ -122,6 +144,31 @@ for a list of possible flags and their m .It Fl g Specify a group. A numeric GID is allowed. +.It Fl h Ar hash +When copying, calculate the digest of the files with +.Ar hash +to store in the +.Fl M Ar metalog . +Supported digests: +.Bl -tag -width rmd160 -offset indent +.It Sy none +No hash. +This is the default. +.It Sy md5 +The MD5 cryptographic message digest. +.It Sy rmd160 +The RMD-160 cryptographic message digest. +.It Sy sha1 +The SHA-1 cryptographic message digest. +.It Sy sha256 +The 256-bits +.Tn SHA-2 +cryptographic message digest of the file. +.It Sy sha512 +The 512-bits +.Tn SHA-2 +cryptographic message digest of the file. +.El .It Fl l Ar linkflags Instead of copying the file make a link to the source. The type of the link is determined by the @@ -146,6 +193,15 @@ are hard links for files on the same fil .It Fl M Disable all use of .Xr mmap 2 . +.It Fl M Ar metalog +Write the metadata associated with each item installed to +.Ar metalog +in an +.Xr mtree 8 +.Dq full path +specification line. +The metadata includes: the file name and file type, and depending upon +other options, the owner, group, file flags, modification time, and tags. .It Fl m Specify an alternate mode. The default mode is set to rwxr-xr-x (0755). @@ -196,9 +252,17 @@ number of systems and binary types. See below for how .Nm can be instructed to use another program to strip binaries. +.It Fl T Ar tags +Specify the +.Xr mtree 8 +tags to write out for the file when using +.Fl M Ar metalog . .It Fl U Indicate that install is running unprivileged, and that it should not try to change the owner, the group, or the file flags of the destination. +The information that would have been updated can be stored in a log +file with +.Fl M Ar metalog . .It Fl v Cause .Nm Modified: projects/mtree/usr.bin/xinstall/xinstall.c ============================================================================== --- projects/mtree/usr.bin/xinstall/xinstall.c Mon Jan 7 23:30:53 2013 (r245137) +++ projects/mtree/usr.bin/xinstall/xinstall.c Mon Jan 7 23:35:40 2013 (r245138) @@ -54,14 +54,20 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +#include +#include +#include +#include #include #include #include #include #include #include +#include #include "mtree.h" @@ -83,22 +89,50 @@ __FBSDID("$FreeBSD$"); #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) #define BACKUP_SUFFIX ".old" +typedef union { + MD5_CTX MD5; + RIPEMD160_CTX RIPEMD160; + SHA1_CTX SHA1; + SHA256_CTX SHA256; + SHA512_CTX SHA512; +} DIGEST_CTX; + static gid_t gid; static uid_t uid; static int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, - nommap, safecopy, verbose; + safecopy, verbose; static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +static FILE *metafp; +static const char *group, *owner; static const char *suffix = BACKUP_SUFFIX; +static char *destdir, *digest, *fflags, *metafile, *tags; -static int compare(int, const char *, size_t, int, const char *, size_t); -static void copy(int, const char *, int, const char *, off_t); +enum { + DIGEST_NONE = 0, + DIGEST_MD5, + DIGEST_RIPEMD160, + DIGEST_SHA1, + DIGEST_SHA256, + DIGEST_SHA512, +} digesttype = DIGEST_NONE; + +static int compare(int, const char *, size_t, int, const char *, size_t, + char **); +static char *copy(int, const char *, int, const char *, off_t); static int create_newfile(const char *, int, struct stat *); static int create_tempfile(const char *, char *, size_t); +static char *quiet_mktemp(char *template); +static char *digest_file(const char *); +static void digest_init(DIGEST_CTX *); +static void digest_update(DIGEST_CTX *, const unsigned char *, size_t); +static char *digest_end(DIGEST_CTX *, char *); static int do_link(const char *, const char *, const struct stat *); static void do_symlink(const char *, const char *, const struct stat *); static void makelink(const char *, const char *, const struct stat *); static void install(const char *, const char *, u_long, u_int); static void install_dir(char *); +static void metadata_log(const char *, const char *, struct timeval *, + const char *, const char *, off_t); static int parseid(const char *, id_t *); static void strip(const char *); static int trymmap(int); @@ -112,13 +146,13 @@ main(int argc, char *argv[]) u_long fset; int ch, no_target; u_int iflags; - char *flags, *p; - const char *group, *owner, *to_name; + char *p; + const char *to_name; - flags = NULL; iflags = 0; group = owner = NULL; - while ((ch = getopt(argc, argv, "B:bCcdf:g:l:Mm:N:o:pSsUv")) != -1) + while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != + -1) switch((char)ch) { case 'B': suffix = optarg; @@ -132,15 +166,21 @@ main(int argc, char *argv[]) case 'c': /* For backwards compatibility. */ break; + case 'D': + destdir = optarg; + break; case 'd': dodir = 1; break; case 'f': - flags = optarg; + fflags = optarg; break; case 'g': group = optarg; break; + case 'h': + digest = optarg; + break; case 'l': for (p = optarg; *p; p++) switch (*p) { @@ -170,7 +210,7 @@ main(int argc, char *argv[]) } break; case 'M': - nommap = 1; + metafile = optarg; break; case 'm': if (!(set = setmode(optarg))) @@ -196,6 +236,9 @@ main(int argc, char *argv[]) case 's': dostrip = 1; break; + case 'T': + tags = optarg; + break; case 'U': dounpriv = 1; break; @@ -224,6 +267,26 @@ main(int argc, char *argv[]) if (argc == 0 || (argc == 1 && !dodir)) usage(); + if (digest != NULL) { + if (0) { + } else if (strcmp(digest, "none") == 0) { + digesttype = DIGEST_NONE; + } else if (strcmp(digest, "md5") == 0) { + digesttype = DIGEST_MD5; + } else if (strcmp(digest, "rmd160") == 0) { + digesttype = DIGEST_RIPEMD160; + } else if (strcmp(digest, "sha1") == 0) { + digesttype = DIGEST_SHA1; + } else if (strcmp(digest, "sha256") == 0) { + digesttype = DIGEST_SHA256; + } else if (strcmp(digest, "sha512") == 0) { + digesttype = DIGEST_SHA512; + } else { + warnx("unknown digest `%s'", digest); + usage(); + } + } + /* need to make a temp copy so we can compare stripped version */ if (docompare && dostrip) safecopy = 1; @@ -249,12 +312,18 @@ main(int argc, char *argv[]) } else uid = (uid_t)-1; - if (flags != NULL && !dounpriv) { - if (strtofflags(&flags, &fset, NULL)) - errx(EX_USAGE, "%s: invalid flag", flags); + if (fflags != NULL && !dounpriv) { + if (strtofflags(&fflags, &fset, NULL)) + errx(EX_USAGE, "%s: invalid flag", fflags); iflags |= SETFLAGS; } + if (metafile != NULL) { + if ((metafp = fopen(metafile, "a")) == NULL) + warn("open %s", metafile); + } else + digesttype = DIGEST_NONE; + if (dodir) { for (; *argv != NULL; ++argv) install_dir(*argv); @@ -298,6 +367,97 @@ main(int argc, char *argv[]) /* NOTREACHED */ } +static char * +digest_file(const char *name) +{ + + switch (digesttype) { + case DIGEST_MD5: + return (MD5File(name, NULL)); + case DIGEST_RIPEMD160: + return (RIPEMD160_File(name, NULL)); + case DIGEST_SHA1: + return (SHA1_File(name, NULL)); + case DIGEST_SHA256: + return (SHA256_File(name, NULL)); + case DIGEST_SHA512: + return (SHA512_File(name, NULL)); + default: + return (NULL); + } +} + +static void +digest_init(DIGEST_CTX *c) +{ + + switch (digesttype) { + case DIGEST_NONE: + break; + case DIGEST_MD5: + MD5Init(&(c->MD5)); + break; + case DIGEST_RIPEMD160: + RIPEMD160_Init(&(c->RIPEMD160)); + break; + case DIGEST_SHA1: + SHA1_Init(&(c->SHA1)); + break; + case DIGEST_SHA256: + SHA256_Init(&(c->SHA256)); + break; + case DIGEST_SHA512: + SHA512_Init(&(c->SHA512)); + break; + + } +} + +static void +digest_update(DIGEST_CTX *c, const unsigned char *data, size_t len) +{ + + switch (digesttype) { + case DIGEST_NONE: + break; + case DIGEST_MD5: + MD5Update(&(c->MD5), data, len); + break; + case DIGEST_RIPEMD160: + RIPEMD160_Update(&(c->RIPEMD160), data, len); + break; + case DIGEST_SHA1: + SHA1_Update(&(c->SHA1), data, len); + break; + case DIGEST_SHA256: + SHA256_Update(&(c->SHA256), data, len); + break; + case DIGEST_SHA512: + SHA512_Update(&(c->SHA512), data, len); + break; + } +} + +static char * +digest_end(DIGEST_CTX *c, char *buf) +{ + + switch (digesttype) { + case DIGEST_MD5: + return (MD5End(&(c->MD5), buf)); + case DIGEST_RIPEMD160: + return (RIPEMD160_End(&(c->RIPEMD160), buf)); + case DIGEST_SHA1: + return (SHA1_End(&(c->SHA1), buf)); + case DIGEST_SHA256: + return (SHA256_End(&(c->SHA256), buf)); + case DIGEST_SHA512: + return (SHA512_End(&(c->SHA512), buf)); + default: + return (NULL); + } +} + /* * parseid -- * parse uid or gid from arg into id, returning non-zero if successful @@ -411,6 +571,9 @@ makelink(const char *from_name, const ch const struct stat *target_sb) { char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; +#ifdef NOTYET + struct stat to_sb; +#endif /* Try hard links first */ if (dolink & (LN_HARD|LN_MIXED)) { @@ -418,6 +581,43 @@ makelink(const char *from_name, const ch if ((dolink & LN_HARD) || errno != EXDEV) err(1, "link %s -> %s", from_name, to_name); } else { +#ifdef NOTYET + if (stat(to_name, &to_sb)) + err(1, "%s: stat", to_name); + if (S_ISREG(to_sb.st_mode)) { + /* XXX: hard links to anything + * other than plain files are not + * metalogged + */ + int omode; + char *oowner, *ogroup, *offlags; + char *dres; + + /* XXX: use underlying perms, + * unless overridden on command line. + */ + omode = mode; + if (!haveopt_m) + mode = (to_sb.st_mode & 0777); + oowner = owner; + if (!haveopt_o) + owner = NULL; + ogroup = group; + if (!haveopt_g) + group = NULL; + offlags = fflags; + if (!haveopt_f) + fflags = NULL; + dres = digest_file(from_name); + metadata_log(to_name, "file", NULL, NULL, + dres, to_sb.st_size); + free(dres); + mode = omode; + owner = oowner; + group = ogroup; + fflags = offlags; + } +#endif return; } } @@ -428,6 +628,10 @@ makelink(const char *from_name, const ch if (realpath(from_name, src) == NULL) err(1, "%s: realpath", from_name); do_symlink(src, to_name, target_sb); +#ifdef NOTYET + /* XXX: src may point outside of destdir */ + metadata_log(to_name, "link", NULL, src, NULL, 0); +#endif return; } @@ -468,6 +672,10 @@ makelink(const char *from_name, const ch (void)strlcat(lnk, ++s, sizeof(lnk)); do_symlink(lnk, to_name, target_sb); +#ifdef NOTYET + /* XXX: lnk may point outside of destdir */ + metadata_log(to_name, "link", NULL, lnk, NULL, 0); +#endif return; } @@ -476,6 +684,10 @@ makelink(const char *from_name, const ch * try the names the user provided */ do_symlink(from_name, to_name, target_sb); +#ifdef NOTYET + /* XXX: from_name may point outside of destdir */ + metadata_log(to_name, "link", NULL, from_name, NULL, 0); +#endif } /* @@ -490,6 +702,7 @@ install(const char *from_name, const cha int devnull, files_match, from_fd, serrno, target; int tempcopy, temp_fd, to_fd; char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; + char *digestresult; files_match = 0; from_fd = -1; @@ -557,7 +770,7 @@ install(const char *from_name, const cha else files_match = !(compare(from_fd, from_name, (size_t)from_sb.st_size, to_fd, - to_name, (size_t)to_sb.st_size)); + to_name, (size_t)to_sb.st_size, &digestresult)); /* Close "to" file unless we match. */ if (!files_match) @@ -579,7 +792,7 @@ install(const char *from_name, const cha from_name, to_name); } if (!devnull) - copy(from_fd, from_name, to_fd, + digestresult = copy(from_fd, from_name, to_fd, tempcopy ? tempfile : to_name, from_sb.st_size); } @@ -614,7 +827,8 @@ install(const char *from_name, const cha } if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd, - to_name, (size_t)to_sb.st_size) == 0) { + to_name, (size_t)to_sb.st_size, &digestresult) + == 0) { /* * If target has more than one link we need to * replace it in order to snap the extra links. @@ -634,6 +848,10 @@ install(const char *from_name, const cha } } + if (dostrip && (!docompare || !target)) { + digestresult = digest_file(tempfile); + } + /* * Move the new file into place if doing a safe copy * and the files are different (or just not compared). @@ -752,6 +970,9 @@ install(const char *from_name, const cha (void)close(to_fd); if (!devnull) (void)close(from_fd); + + metadata_log(to_name, "file", tvb, NULL, digestresult, to_sb.st_size); + free(digestresult); } /* @@ -760,29 +981,37 @@ install(const char *from_name, const cha */ static int compare(int from_fd, const char *from_name __unused, size_t from_len, - int to_fd, const char *to_name __unused, size_t to_len) + int to_fd, const char *to_name __unused, size_t to_len, + char **dresp) { char *p, *q; int rv; int done_compare; + DIGEST_CTX ctx; rv = 0; if (from_len != to_len) return 1; if (from_len <= MAX_CMP_SIZE) { + if (dresp != NULL) + digest_init(&ctx); done_compare = 0; if (trymmap(from_fd) && trymmap(to_fd)) { - p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, from_fd, (off_t)0); + p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, + from_fd, (off_t)0); if (p == (char *)MAP_FAILED) goto out; - q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, to_fd, (off_t)0); + q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, + to_fd, (off_t)0); if (q == (char *)MAP_FAILED) { munmap(p, from_len); goto out; } rv = memcmp(p, q, from_len); + if (dresp != NULL) + digest_update(&ctx, p, from_len); munmap(p, from_len); munmap(q, from_len); done_compare = 1; @@ -808,6 +1037,7 @@ compare(int from_fd, const char *from_na rv = 1; /* out of sync */ } else rv = 1; /* read failure */ + digest_update(&ctx, buf1, n1); } lseek(from_fd, 0, SEEK_SET); lseek(to_fd, 0, SEEK_SET); @@ -815,6 +1045,13 @@ compare(int from_fd, const char *from_na } else rv = 1; /* don't bother in this case */ + if (dresp != NULL) { + if (rv == 0) + *dresp = digest_end(&ctx, NULL); + else + (void)digest_end(&ctx, NULL); + } + return rv; } @@ -885,7 +1122,7 @@ create_newfile(const char *path, int tar * copy -- * copy from one file to another */ -static void +static char * copy(int from_fd, const char *from_name, int to_fd, const char *to_name, off_t size) { @@ -893,6 +1130,7 @@ copy(int from_fd, const char *from_name, int serrno; char *p, buf[MAXBSIZE]; int done_copy; + DIGEST_CTX ctx; /* Rewind file descriptors. */ if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) @@ -900,6 +1138,8 @@ copy(int from_fd, const char *from_name, if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) err(EX_OSERR, "lseek: %s", to_name); + digest_init(&ctx); + /* * Mmap and write if less than 8M (the limit is so we don't totally * trash memory on big files. This is really a minor hack, but it @@ -922,10 +1162,12 @@ copy(int from_fd, const char *from_name, err(EX_OSERR, "%s", to_name); } } + digest_update(&ctx, p, size); + (void)munmap(p, size); done_copy = 1; } if (!done_copy) { - while ((nr = read(from_fd, buf, sizeof(buf))) > 0) + while ((nr = read(from_fd, buf, sizeof(buf))) > 0) { if ((nw = write(to_fd, buf, nr)) != nr) { serrno = errno; (void)unlink(to_name); @@ -939,6 +1181,8 @@ copy(int from_fd, const char *from_name, err(EX_OSERR, "%s", to_name); } } + digest_update(&ctx, buf, nr); + } if (nr != 0) { serrno = errno; (void)unlink(to_name); @@ -946,6 +1190,7 @@ copy(int from_fd, const char *from_name, err(EX_OSERR, "%s", from_name); } } + return digest_end(&ctx, NULL); } /* @@ -1016,6 +1261,84 @@ install_dir(char *path) if (chmod(path, mode)) warn("chmod %o %s", mode, path); } + metadata_log(path, "dir", NULL, NULL, NULL, 0); +} + +/* + * metadata_log -- + * if metafp is not NULL, output mtree(8) full path name and settings to + * metafp, to allow permissions to be set correctly by other tools, + * or to allow integrity checks to be performed. + */ +static void +metadata_log(const char *path, const char *type, struct timeval *tv, + const char *slink, const char *digestresult, off_t size) +{ + static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; + const char *p; + char *buf; + size_t destlen; + struct flock metalog_lock; + + if (!metafp) + return; + buf = (char *)malloc(4 * strlen(path) + 1); /* buf for strsvis(3) */ + if (buf == NULL) { + warnx("%s", strerror(ENOMEM)); + return; + } + /* lock log file */ + metalog_lock.l_start = 0; + metalog_lock.l_len = 0; + metalog_lock.l_whence = SEEK_SET; + metalog_lock.l_type = F_WRLCK; + if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { + warn("can't lock %s", metafile); + free(buf); + return; + } + + p = path; /* remove destdir */ + if (destdir) { + destlen = strlen(destdir); + if (strncmp(p, destdir, destlen) == 0 && + (p[destlen] == '/' || p[destlen] == '\0')) + p += destlen; + } + while (*p && *p == '/') /* remove leading /s */ + p++; + strsvis(buf, p, VIS_CSTYLE, extra); /* encode name */ + p = buf; + /* print details */ + fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type); + if (owner) + fprintf(metafp, " uname=%s", owner); + if (group) + fprintf(metafp, " gname=%s", group); + fprintf(metafp, " mode=%#o", mode); + if (slink) { + strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */ + fprintf(metafp, " link=%s", buf); + } + if (*type == 'f') /* type=file */ + fprintf(metafp, " size=%lld", (long long)size); + if (tv != NULL && dopreserve) + fprintf(metafp, " time=%lld.%ld", + (long long)tv[1].tv_sec, (long)tv[1].tv_usec); + if (digestresult && digest) + fprintf(metafp, " %s=%s", digest, digestresult); + if (fflags) + fprintf(metafp, " flags=%s", fflags); + if (tags) + fprintf(metafp, " tags=%s", tags); + fputc('\n', metafp); + fflush(metafp); /* flush output */ + /* unlock log file */ + metalog_lock.l_type = F_UNLCK; + if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { + warn("can't unlock %s", metafile); + } + free(buf); } /* @@ -1026,11 +1349,16 @@ static void usage(void) { (void)fprintf(stderr, -"usage: install [-bCcMpSsUv] [-B suffix] [-f flags] [-g group] [-l linkflags]\n" -" [-m mode] [-N dbdir] [-o owner] file1 file2\n" -" install [-bCcMpSsUv] [-B suffix] [-f flags] [-g group] [-l linkflags]\n" -" [-m mode] [-N dbdir] [-o owner] file1 ... fileN directory\n" +"usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" +" [-M log] [-D dest] [-h hash] [-T tags]\n" +" [-B suffix] [-l linkflags] [-N dbdir]\n" +" file1 file2\n" +" install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" +" [-M log] [-D dest] [-h hash] [-T tags]\n" +" [-B suffix] [-l linkflags] [-N dbdir]\n" +" file1 ... fileN directory\n" " install -dU [-vU] [-g group] [-m mode] [-N dbdir] [-o owner]\n" +" [-M log] [-D dest] [-h hash] [-T tags]\n" " directory ...\n"); exit(EX_USAGE); /* NOTREACHED */ @@ -1050,7 +1378,7 @@ trymmap(int fd) #ifdef MFSNAMELEN struct statfs stfs; - if (nommap || fstatfs(fd, &stfs) != 0) + if (fstatfs(fd, &stfs) != 0) return (0); if (strcmp(stfs.f_fstypename, "ufs") == 0 || strcmp(stfs.f_fstypename, "cd9660") == 0)