From owner-svn-src-stable-9@FreeBSD.ORG Mon Mar 18 02:49:24 2013 Return-Path: Delivered-To: svn-src-stable-9@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id AA7DACD4 for ; Mon, 18 Mar 2013 02:49:24 +0000 (UTC) (envelope-from jdc@koitsu.org) Received: from qmta01.emeryville.ca.mail.comcast.net (qmta01.emeryville.ca.mail.comcast.net [IPv6:2001:558:fe2d:43:76:96:30:16]) by mx1.freebsd.org (Postfix) with ESMTP id 8DAFDF76 for ; Mon, 18 Mar 2013 02:49:24 +0000 (UTC) Received: from omta06.emeryville.ca.mail.comcast.net ([76.96.30.51]) by qmta01.emeryville.ca.mail.comcast.net with comcast id CjJs1l00816AWCUA1qpQQd; Mon, 18 Mar 2013 02:49:24 +0000 Received: from koitsu.strangled.net ([67.180.84.87]) by omta06.emeryville.ca.mail.comcast.net with comcast id CqpP1l0031t3BNj8SqpPTU; Mon, 18 Mar 2013 02:49:23 +0000 Received: by icarus.home.lan (Postfix, from userid 1000) id DBD8073A1C; Sun, 17 Mar 2013 19:49:22 -0700 (PDT) Date: Sun, 17 Mar 2013 19:49:22 -0700 From: Jeremy Chadwick To: Brooks Davis Subject: Re: svn commit: r248331 - in stable/9: . usr.bin/xinstall Message-ID: <20130318024922.GA24535@icarus.home.lan> References: <201303151519.r2FFJYjS060493@svn.freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <201303151519.r2FFJYjS060493@svn.freebsd.org> User-Agent: Mutt/1.5.21 (2010-09-15) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=comcast.net; s=q20121106; t=1363574964; bh=fstX/Whi4zbUmVC21RU3Pc8yzaKt55o1pZuuTN5XGe8=; h=Received:Received:Received:Date:From:To:Subject:Message-ID: MIME-Version:Content-Type; b=Jk4gaZnnWC4NlUFnUZbXgwev5AH1aVffgyJ8x3B+prN/+MNrRZ6bLpJw6vUgUnUgh oib7eK7FI1n9zOwJBB5OKbwjughox0QUUlQwXYmIffXfQ8ziomlzKEqrXmXOhV2CyX RbFode4L3WPWRq0odGdFirxBU0aIrcfRJRucTsbKIMLb2MwZWUd7hpLO3KGRLh+sdL P+pxYxDductc6MFkcJ1plP1unht+EAi+B+HU9zxJSooSXzZ2Kg/cwCxMtozRl3z3hZ tDomKkGP+wRZh4u5YDveKr04gnPelW09Gi3PChBq7X5xg4FPqqaVDmnFHe3QhMRknT aeNzhJwzcuB+w== 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-stable-9@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for only the 9-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Mar 2013 02:49:24 -0000 Please see PR 177055. This MFC has broken mergmaster for at least a couple people. The PR should really be rated high priority: http://www.freebsd.org/cgi/query-pr.cgi?pr=177055 http://lists.freebsd.org/pipermail/freebsd-stable/2013-March/072848.html -- | Jeremy Chadwick jdc@koitsu.org | | UNIX Systems Administrator http://jdc.koitsu.org/ | | Mountain View, CA, US | | Making life hard for others since 1977. PGP 4BD6C0CB | On Fri, Mar 15, 2013 at 03:19:34PM +0000, 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 *** > _______________________________________________ > svn-src-stable-9@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9 > To unsubscribe, send any mail to "svn-src-stable-9-unsubscribe@freebsd.org"