Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Mar 2013 19:49:22 -0700
From:      Jeremy Chadwick <jdc@koitsu.org>
To:        Brooks Davis <brooks@FreeBSD.org>
Cc:        svn-src-stable@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   Re: svn commit: r248331 - in stable/9: . usr.bin/xinstall
Message-ID:  <20130318024922.GA24535@icarus.home.lan>
In-Reply-To: <201303151519.r2FFJYjS060493@svn.freebsd.org>
References:  <201303151519.r2FFJYjS060493@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
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 <metalog>   Log metadata in mtree format.
>    * -D <destdir>   Log paths relative to <destdir>.
>    * -h <hash>      Log digest of type <hash>.
>    * -T <tags>      Specify which mtree tags to log.
>    * -l <linkflag>  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 <dbdir> 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 <bsd.prog.mk>
> 
> 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 <errno.h>
>  #include <fcntl.h>
>  #include <grp.h>
> +#include <libgen.h>
> +#include <md5.h>
>  #include <paths.h>
>  #include <pwd.h>
> +#include <ripemd.h>
> +#include <sha.h>
> +#include <sha256.h>
> +#include <sha512.h>
>  #include <stdint.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <sysexits.h>
>  #include <unistd.h>
> +#include <vis.h>
> +
> +#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"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130318024922.GA24535>