From owner-svn-src-all@FreeBSD.ORG Sat Jun 1 20:19:17 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 0B0DC6FC; Sat, 1 Jun 2013 20:19:17 +0000 (UTC) (envelope-from sobomax@sippysoft.com) Received: from mail.sippysoft.com (hub.sippysoft.com [174.36.24.17]) by mx1.freebsd.org (Postfix) with ESMTP id BD090DC3; Sat, 1 Jun 2013 20:19:16 +0000 (UTC) Received: from s173-180-43-49.bc.hsia.telus.net ([173.180.43.49] helo=[192.168.22.32]) by mail.sippysoft.com with esmtpsa (TLSv1:DHE-RSA-CAMELLIA256-SHA:256) (Exim 4.80 (FreeBSD)) (envelope-from ) id 1Uirz9-0007EX-NO; Sat, 01 Jun 2013 13:01:08 -0700 Message-ID: <51AA52FD.9090303@FreeBSD.org> Date: Sat, 01 Jun 2013 13:01:01 -0700 From: Maxim Sobolev Organization: Sippy Software, Inc. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130509 Thunderbird/17.0.6 MIME-Version: 1.0 To: Brooks Davis Subject: Re: svn: stable/9: . usr.bin/xinstall References: <201303151519.r2FFJYjS060493@svn.freebsd.org> In-Reply-To: <201303151519.r2FFJYjS060493@svn.freebsd.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Sender: sobomax@sippysoft.com X-ssp-trusted: yes Cc: svn-src-stable@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, svn-src-stable-9@freebsd.org X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 01 Jun 2013 20:19:17 -0000 Hmm, I believe this breaks build for me. Any ideas why? ===> usr.bin/xinstall (all) cc -O2 -pipe -I/usr/src/usr.bin/xinstall/../../contrib/mtree -I/usr/src/usr.bin/xinstall/../../lib/libnetbsd -I/usr/src/usr.bin/xinstall/../../lib/libmd -std=gnu99 -fstack-protector -Wsystem-headers -Werror -Wall -Wno-format-y2k -W -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wunused-parameter -Wcast-align -Wchar-subscripts -Winline -Wnested-externs -Wredundant-decls -Wold-style-definition -Wno-pointer-sign -c /usr/src/usr.bin/xinstall/xinstall.c cc1: warnings being treated as errors /usr/src/usr.bin/xinstall/xinstall.c: In function 'metadata_log': /usr/src/usr.bin/xinstall/xinstall.c:1331: warning: implicit declaration of function 'strsvis' /usr/src/usr.bin/xinstall/xinstall.c:1331: warning: nested extern declaration of 'strsvis' *** [xinstall.o] Error code 1 Stop in /usr/src/usr.bin/xinstall. *** [all] Error code 1 uname -a FreeBSD dal09 9.1-RELEASE FreeBSD 9.1-RELEASE #2: Thu Dec 27 09:39:03 UTC 2012 root@pioneer:/usr/obj/usr/src91/sys/SSP-PRODUCTION9_X64 amd64 On 3/15/2013 8:19 AM, Brooks Davis wrote: > Author: brooks > Date: Fri Mar 15 15:19:33 2013 > New Revision: 248331 > URL: http://svnweb.freebsd.org/changeset/base/248331 > > Log: > MFC all changes to install(1) through r246784. Notable functional > changes are: > > r245617: > Introduce six new options from NetBSD: > * -M Log metadata in mtree format. > * -D Log paths relative to . > * -h Log digest of type . > * -T Specify which mtree tags to log. > * -l Create hard or symbolic links (allows logging). > * -U Install without root privileges (owner, group, mode, > and flags can be logged via -M > > NOTE: In the interest of compatibility with NetBSD and because it is the > obvious letter, the nearly useless -M option (disable mmap) has been > repurposed. > > Sponsored by: DARPA, AFRL > Obtained from: NetBSD > Reviewed by: bz > > r245312: > Implement the -N option which allows an alternate passwd and > group file to be used. This is useful for installing on systems where > a user or group does not currently exist. > > Sponsored by: DARPA, AFRL > Obtained from: NetBSD > > Modified: > stable/9/UPDATING (contents, props changed) > stable/9/usr.bin/xinstall/Makefile > stable/9/usr.bin/xinstall/install.1 > stable/9/usr.bin/xinstall/xinstall.c > Directory Properties: > stable/9/usr.bin/xinstall/ (props changed) > > Modified: stable/9/UPDATING > ============================================================================== > --- stable/9/UPDATING Fri Mar 15 14:53:29 2013 (r248330) > +++ stable/9/UPDATING Fri Mar 15 15:19:33 2013 (r248331) > @@ -11,6 +11,15 @@ handbook: > Items affecting the ports and packages system can be found in > /usr/ports/UPDATING. Please read that file before running portupgrade. > > +20130315: > + The install(1) option -M has changed meaning and now takes an > + argument that is a file or path to append logs to. In the > + unlikely event that -M was the last option on the command line > + and the command line contained at least two files and a target > + directory the first file will have logs appended to it. The -M > + option served little practical purpose in the last decade so it's > + used expected to be extremely rare. > + > 20130225: > A new compression method (lz4) has been merged to. Please refer to > zpool-features(7) for more information. > > Modified: stable/9/usr.bin/xinstall/Makefile > ============================================================================== > --- stable/9/usr.bin/xinstall/Makefile Fri Mar 15 14:53:29 2013 (r248330) > +++ stable/9/usr.bin/xinstall/Makefile Fri Mar 15 15:19:33 2013 (r248331) > @@ -3,6 +3,16 @@ > > PROG= xinstall > PROGNAME= install > +SRCS= xinstall.c getid.c > MAN= install.1 > > +.PATH: ${.CURDIR}/../../contrib/mtree > +.PATH: ${.CURDIR}/../../lib/libmd > +CFLAGS+= -I${.CURDIR}/../../contrib/mtree > +CFLAGS+= -I${.CURDIR}/../../lib/libnetbsd > +CFLAGS+= -I${.CURDIR}/../../lib/libmd > + > +DPADD+= ${LIBMD} > +LDADD+= -lmd > + > .include > > Modified: stable/9/usr.bin/xinstall/install.1 > ============================================================================== > --- stable/9/usr.bin/xinstall/install.1 Fri Mar 15 14:53:29 2013 (r248330) > +++ stable/9/usr.bin/xinstall/install.1 Fri Mar 15 15:19:33 2013 (r248331) > @@ -28,7 +28,7 @@ > .\" From: @(#)install.1 8.1 (Berkeley) 6/6/93 > .\" $FreeBSD$ > .\" > -.Dd March 6, 2006 > +.Dd January 18, 2013 > .Dt INSTALL 1 > .Os > .Sh NAME > @@ -36,31 +36,50 @@ > .Nd install binaries > .Sh SYNOPSIS > .Nm > -.Op Fl bCcMpSsv > +.Op Fl bCcpSsUv > .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 bCcMpSsv > +.Op Fl bCcpSsUv > .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 v > +.Op Fl Uv > +.Op Fl D Ar destdir > .Op Fl g Ar group > +.Op Fl h Ar hash > +.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 > -to the target file or directory. > +(or linked if the > +.Fl l > +option is specified) to the target file or directory. > If the destination is a directory, then the > .Ar file > is copied into > @@ -105,6 +124,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. > @@ -115,15 +145,82 @@ for a list of possible flags and their m > .It Fl g > Specify a group. > A numeric GID is allowed. > -.It Fl M > -Disable all use of > -.Xr mmap 2 . > +.It Fl h Ar hash > +When copying, calculate the digest of the files with > +.Ar hash > +to store in the > +.Fl M Ar metalog . > +When > +.Fl d > +is given no hash is emitted. > +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 > +.Ar linkflags > +argument. > +Valid > +.Ar linkflags > +are: > +.Ar a > +(absolute), > +.Ar r > +(relative), > +.Ar h > +(hard), > +.Ar s > +(symbolic), > +.Ar m > +(mixed). > +Absolute and relative have effect only for symbolic links. > +Mixed links > +are hard links for files on the same filesystem, symbolic otherwise. > +.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). > The specified mode may be either an octal or symbolic value; see > .Xr chmod 1 > for a description of possible mode values. > +.It Fl N > +Use the user database text file > +.Pa master.passwd > +and group database text file > +.Pa group > +from > +.Ar dbdir , > +rather than using the results from the system's > +.Xr getpwnam 3 > +and > +.Xr getgrnam 3 > +(and related) library calls. > .It Fl o > Specify an owner. > A numeric UID is allowed. > @@ -156,6 +253,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 > @@ -231,6 +339,8 @@ The default was changed to copy in > .Xr mv 1 , > .Xr strip 1 , > .Xr mmap 2 , > +.Xr getgrnam 3 , > +.Xr getpwnam 3 , > .Xr chown 8 > .Sh HISTORY > The > @@ -238,6 +348,16 @@ The > utility appeared in > .Bx 4.2 . > .Sh BUGS > +The meaning of the > +.Fl M > +option has changed as of > +.Fx 10 > +and it now takes an argument. > +Command lines that used the old > +.Fl M > +will get an error or in rare cases will append logs to the first of > +multiple source files rather than installing it. > +.Pp > Temporary files may be left in the target directory if > .Nm > exits abnormally. > > Modified: stable/9/usr.bin/xinstall/xinstall.c > ============================================================================== > --- stable/9/usr.bin/xinstall/xinstall.c Fri Mar 15 14:53:29 2013 (r248330) > +++ stable/9/usr.bin/xinstall/xinstall.c Fri Mar 15 15:19:33 2013 (r248331) > @@ -1,4 +1,5 @@ > /* > + * Copyright (c) 2012, 2013 SRI International > * Copyright (c) 1987, 1993 > * The Regents of the University of California. All rights reserved. > * > @@ -53,14 +54,23 @@ __FBSDID("$FreeBSD$"); > #include > #include > #include > +#include > +#include > #include > #include > +#include > +#include > +#include > +#include > #include > #include > #include > #include > #include > #include > +#include > + > +#include "mtree.h" > > /* Bootstrap aid - this doesn't exist in most older releases */ > #ifndef MAP_FAILED > @@ -69,26 +79,63 @@ __FBSDID("$FreeBSD$"); > > #define MAX_CMP_SIZE (16 * 1024 * 1024) > > +#define LN_ABSOLUTE 0x01 > +#define LN_RELATIVE 0x02 > +#define LN_HARD 0x04 > +#define LN_SYMBOLIC 0x08 > +#define LN_MIXED 0x10 > + > #define DIRECTORY 0x01 /* Tell install it's a directory. */ > #define SETFLAGS 0x02 /* Tell install to set flags. */ > #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) > #define BACKUP_SUFFIX ".old" > > -struct passwd *pp; > -struct group *gp; > -gid_t gid; > -uid_t uid; > -int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose; > -mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; > -const char *suffix = BACKUP_SUFFIX; > - > -static int compare(int, const char *, size_t, int, const char *, size_t); > -static void copy(int, const char *, int, const char *, off_t); > +typedef union { > + MD5_CTX MD5; > + RIPEMD160_CTX RIPEMD160; > + SHA1_CTX SHA1; > + SHA256_CTX SHA256; > + SHA512_CTX SHA512; > +} DIGEST_CTX; > + > +static enum { > + DIGEST_NONE = 0, > + DIGEST_MD5, > + DIGEST_RIPEMD160, > + DIGEST_SHA1, > + DIGEST_SHA256, > + DIGEST_SHA512, > +} digesttype = DIGEST_NONE; > + > +static gid_t gid; > +static uid_t uid; > +static int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, > + safecopy, verbose; > +static int haveopt_f, haveopt_g, haveopt_m, haveopt_o; > +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, > + 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 u_long numeric_id(const char *, const 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); > static void usage(void); > @@ -101,12 +148,13 @@ main(int argc, char *argv[]) > u_long fset; > int ch, no_target; > u_int iflags; > - char *flags; > - const char *group, *owner, *to_name; > + char *p; > + const char *to_name; > > iflags = 0; > group = owner = NULL; > - while ((ch = getopt(argc, argv, "B:bCcdf:g:Mm:o:pSsv")) != -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; > @@ -120,29 +168,69 @@ 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; > - if (strtofflags(&flags, &fset, NULL)) > - errx(EX_USAGE, "%s: invalid flag", flags); > - iflags |= SETFLAGS; > + haveopt_f = 1; > + fflags = optarg; > break; > case 'g': > + haveopt_g = 1; > group = optarg; > break; > + case 'h': > + digest = optarg; > + break; > + case 'l': > + for (p = optarg; *p != '\0'; p++) > + switch (*p) { > + case 's': > + dolink &= ~(LN_HARD|LN_MIXED); > + dolink |= LN_SYMBOLIC; > + break; > + case 'h': > + dolink &= ~(LN_SYMBOLIC|LN_MIXED); > + dolink |= LN_HARD; > + break; > + case 'm': > + dolink &= ~(LN_SYMBOLIC|LN_HARD); > + dolink |= LN_MIXED; > + break; > + case 'a': > + dolink &= ~LN_RELATIVE; > + dolink |= LN_ABSOLUTE; > + break; > + case 'r': > + dolink &= ~LN_ABSOLUTE; > + dolink |= LN_RELATIVE; > + break; > + default: > + errx(1, "%c: invalid link type", *p); > + /* NOTREACHED */ > + } > + break; > case 'M': > - nommap = 1; > + metafile = optarg; > break; > case 'm': > + haveopt_m = 1; > if (!(set = setmode(optarg))) > errx(EX_USAGE, "invalid file mode: %s", > optarg); > mode = getmode(set, 0); > free(set); > break; > + case 'N': > + if (!setup_getid(optarg)) > + err(EX_OSERR, "Unable to use user and group " > + "databases in `%s'", optarg); > + break; > case 'o': > + haveopt_o = 1; > owner = optarg; > break; > case 'p': > @@ -154,6 +242,12 @@ main(int argc, char *argv[]) > case 's': > dostrip = 1; > break; > + case 'T': > + tags = optarg; > + break; > + case 'U': > + dounpriv = 1; > + break; > case 'v': > verbose = 1; > break; > @@ -179,27 +273,62 @@ main(int argc, char *argv[]) > if (argc == 0 || (argc == 1 && !dodir)) > usage(); > > + if (digest != NULL) { > + 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; > > /* get group and owner id's */ > - if (group != NULL) { > - if ((gp = getgrnam(group)) != NULL) > - gid = gp->gr_gid; > - else > - gid = (gid_t)numeric_id(group, "group"); > + if (group != NULL && !dounpriv) { > + if (gid_from_group(group, &gid) == -1) { > + id_t id; > + if (!parseid(group, &id)) > + errx(1, "unknown group %s", group); > + gid = id; > + } > } else > gid = (gid_t)-1; > > - if (owner != NULL) { > - if ((pp = getpwnam(owner)) != NULL) > - uid = pp->pw_uid; > - else > - uid = (uid_t)numeric_id(owner, "user"); > + if (owner != NULL && !dounpriv) { > + if (uid_from_user(owner, &uid) == -1) { > + id_t id; > + if (!parseid(owner, &id)) > + errx(1, "unknown user %s", owner); > + uid = id; > + } > } else > uid = (uid_t)-1; > > + 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); > @@ -207,8 +336,21 @@ main(int argc, char *argv[]) > /* NOTREACHED */ > } > > - no_target = stat(to_name = argv[argc - 1], &to_sb); > + to_name = argv[argc - 1]; > + no_target = stat(to_name, &to_sb); > if (!no_target && S_ISDIR(to_sb.st_mode)) { > + if (dolink & LN_SYMBOLIC) { > + if (lstat(to_name, &to_sb) != 0) > + err(EX_OSERR, "%s vanished", to_name); > + if (S_ISLNK(to_sb.st_mode)) { > + if (argc != 2) { > + errno = ENOTDIR; > + err(EX_USAGE, "%s", to_name); > + } > + install(*argv, to_name, fset, iflags); > + exit(EX_OK); > + } > + } > for (; *argv != to_name; ++argv) > install(*argv, to_name, fset, iflags | DIRECTORY); > exit(EX_OK); > @@ -226,7 +368,7 @@ main(int argc, char *argv[]) > usage(); > } > > - if (!no_target) { > + if (!no_target && !dolink) { > if (stat(*argv, &from_sb)) > err(EX_OSERR, "%s", *argv); > if (!S_ISREG(to_sb.st_mode)) { > @@ -243,23 +385,327 @@ main(int argc, char *argv[]) > /* NOTREACHED */ > } > > -static u_long > -numeric_id(const char *name, const char *type) > +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 > + */ > +static int > +parseid(const char *name, id_t *id) > +{ > + char *ep; > + errno = 0; > + *id = (id_t)strtoul(name, &ep, 10); > + if (errno || *ep != '\0') > + return (0); > + return (1); > +} > + > +/* > + * quiet_mktemp -- > + * mktemp implementation used mkstemp to avoid mktemp warnings. We > + * really do need mktemp semantics here as we will be creating a link. > + */ > +static char * > +quiet_mktemp(char *template) > +{ > + int fd; > + > + if ((fd = mkstemp(template)) == -1) > + return (NULL); > + close (fd); > + if (unlink(template) == -1) > + err(EX_OSERR, "unlink %s", template); > + return (template); > +} > + > +/* > + * do_link -- > + * make a hard link, obeying dorename if set > + * return -1 on failure > + */ > +static int > +do_link(const char *from_name, const char *to_name, > + const struct stat *target_sb) > +{ > + char tmpl[MAXPATHLEN]; > + int ret; > + > + if (safecopy && target_sb != NULL) { > + (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); > + /* This usage is safe. */ > + if (quiet_mktemp(tmpl) == NULL) > + err(EX_OSERR, "%s: mktemp", tmpl); > + ret = link(from_name, tmpl); > + if (ret == 0) { > + if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == > + -1) { > + unlink(tmpl); > + err(EX_OSERR, "%s", to_name); > + } > + if (target_sb->st_flags & NOCHANGEBITS) > + (void)chflags(to_name, target_sb->st_flags & > + ~NOCHANGEBITS); > + unlink(to_name); > + ret = rename(tmpl, to_name); > + /* > + * If rename has posix semantics, then the temporary > + * file may still exist when from_name and to_name point > + * to the same file, so unlink it unconditionally. > + */ > + (void)unlink(tmpl); > + } > + return (ret); > + } else > + return (link(from_name, to_name)); > +} > + > +/* > + * do_symlink -- > + * Make a symbolic link, obeying dorename if set. Exit on failure. > + */ > +static void > +do_symlink(const char *from_name, const char *to_name, > + const struct stat *target_sb) > +{ > + char tmpl[MAXPATHLEN]; > + > + if (safecopy && target_sb != NULL) { > + (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); > + /* This usage is safe. */ > + if (quiet_mktemp(tmpl) == NULL) > + err(EX_OSERR, "%s: mktemp", tmpl); > + > + if (symlink(from_name, tmpl) == -1) > + err(EX_OSERR, "symlink %s -> %s", from_name, tmpl); > + > + if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == -1) { > + (void)unlink(tmpl); > + err(EX_OSERR, "%s", to_name); > + } > + if (target_sb->st_flags & NOCHANGEBITS) > + (void)chflags(to_name, target_sb->st_flags & > + ~NOCHANGEBITS); > + unlink(to_name); > + > + if (rename(tmpl, to_name) == -1) { > + /* Remove temporary link before exiting. */ > + (void)unlink(tmpl); > + err(EX_OSERR, "%s: rename", to_name); > + } > + } else { > + if (symlink(from_name, to_name) == -1) > + err(EX_OSERR, "symlink %s -> %s", from_name, to_name); > + } > +} > + > +/* > + * makelink -- > + * make a link from source to destination > + */ > +static void > +makelink(const char *from_name, const char *to_name, > + const struct stat *target_sb) > { > - u_long val; > - char *ep; > + char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; > + struct stat to_sb; > + > + /* Try hard links first. */ > + if (dolink & (LN_HARD|LN_MIXED)) { > + if (do_link(from_name, to_name, target_sb) == -1) { > + if ((dolink & LN_HARD) || errno != EXDEV) > + err(EX_OSERR, "link %s -> %s", from_name, to_name); > + } else { > + if (stat(to_name, &to_sb)) > + err(EX_OSERR, "%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; > + const char *oowner, *ogroup; > + char *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; > + } > + return; > + } > + } > + > + /* Symbolic links. */ > + if (dolink & LN_ABSOLUTE) { > + /* Convert source path to absolute. */ > + if (realpath(from_name, src) == NULL) > + err(EX_OSERR, "%s: realpath", from_name); > + do_symlink(src, to_name, target_sb); > + /* XXX: src may point outside of destdir */ > + metadata_log(to_name, "link", NULL, src, NULL, 0); > + return; > + } > + > + if (dolink & LN_RELATIVE) { > + char *cp, *d, *s; > + > + /* Resolve pathnames. */ > + if (realpath(from_name, src) == NULL) > + err(EX_OSERR, "%s: realpath", from_name); > + > + /* > + * The last component of to_name may be a symlink, > + * so use realpath to resolve only the directory. > + */ > + cp = dirname(to_name); > + if (realpath(cp, dst) == NULL) > + err(EX_OSERR, "%s: realpath", cp); > + /* .. and add the last component. */ > + if (strcmp(dst, "/") != 0) { > + if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst)) > + errx(1, "resolved pathname too long"); > + } > + cp = basename(to_name); > + if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst)) > + errx(1, "resolved pathname too long"); > + > + /* Trim common path components. */ > + for (s = src, d = dst; *s == *d; s++, d++) > + continue; > + while (*s != '/') > + s--, d--; > + > + /* Count the number of directories we need to backtrack. */ > + for (++d, lnk[0] = '\0'; *d; d++) > + if (*d == '/') > + (void)strlcat(lnk, "../", sizeof(lnk)); > + > + (void)strlcat(lnk, ++s, sizeof(lnk)); > + > + do_symlink(lnk, to_name, target_sb); > + /* XXX: Link may point outside of destdir. */ > + metadata_log(to_name, "link", NULL, lnk, NULL, 0); > + return; > + } > > /* > - * XXX > - * We know that uid_t's and gid_t's are unsigned longs. > + * If absolute or relative was not specified, try the names the > + * user provided. > */ > - errno = 0; > - val = strtoul(name, &ep, 10); > - if (errno) > - err(EX_NOUSER, "%s", name); > - if (*ep != '\0') > - errx(EX_NOUSER, "unknown %s %s", type, name); > - return (val); > + do_symlink(from_name, to_name, target_sb); > + /* XXX: from_name may point outside of destdir. */ > + metadata_log(to_name, "link", NULL, from_name, NULL, 0); > } > > /* > @@ -274,6 +720,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; > @@ -281,11 +728,13 @@ install(const char *from_name, const cha > > /* If try to install NULL file to a directory, fails. */ > if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { > - if (stat(from_name, &from_sb)) > - err(EX_OSERR, "%s", from_name); > - if (!S_ISREG(from_sb.st_mode)) { > - errno = EFTYPE; > - err(EX_OSERR, "%s", from_name); > + if (!dolink) { > + if (stat(from_name, &from_sb)) > + err(EX_OSERR, "%s", from_name); > + if (!S_ISREG(from_sb.st_mode)) { > + errno = EFTYPE; > + err(EX_OSERR, "%s", from_name); > + } > } > /* Build the target path. */ > if (flags & DIRECTORY) { > @@ -299,7 +748,23 @@ install(const char *from_name, const cha > devnull = 1; > } > > - target = stat(to_name, &to_sb) == 0; > + if (!dolink) > + target = (stat(to_name, &to_sb) == 0); > + else > + target = (lstat(to_name, &to_sb) == 0); > + > + if (dolink) { > + if (target && !safecopy) { > + if (to_sb.st_mode & S_IFDIR && rmdir(to_name) == -1) > + err(EX_OSERR, "%s", to_name); > + if (to_sb.st_flags & NOCHANGEBITS) > + (void)chflags(to_name, > + to_sb.st_flags & ~NOCHANGEBITS); > + unlink(to_name); > + } > + makelink(from_name, to_name, target ? &to_sb : NULL); > + return; > + } > > /* Only install to regular files. */ > if (target && !S_ISREG(to_sb.st_mode)) { > @@ -323,7 +788,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) > @@ -345,8 +810,10 @@ 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); > + else > + digestresult = NULL; > } > > if (dostrip) { > @@ -380,7 +847,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. > @@ -400,6 +868,9 @@ install(const char *from_name, const cha > } > } > > + if (dostrip && (!docompare || !target)) > + digestresult = digest_file(tempfile); > + > /* > > *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** > >