From owner-svn-src-user@FreeBSD.ORG Fri Apr 2 05:14:58 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0C95E106566C; Fri, 2 Apr 2010 05:14:58 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id EEFD58FC12; Fri, 2 Apr 2010 05:14:57 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o325Ev6M057561; Fri, 2 Apr 2010 05:14:57 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o325Ev7f057558; Fri, 2 Apr 2010 05:14:57 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <201004020514.o325Ev7f057558@svn.freebsd.org> From: Warner Losh Date: Fri, 2 Apr 2010 05:14:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r206070 - user/imp/nopriv/usr.bin/xinstall X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Apr 2010 05:14:58 -0000 Author: imp Date: Fri Apr 2 05:14:57 2010 New Revision: 206070 URL: http://svn.freebsd.org/changeset/base/206070 Log: First cut at merging some features from NetBSD's install: o add ability to generate mtree meta files based on what's installed. o add ability to set destdir, so the metadata in the above file can filter that o add some rudamentary support for generating digests of the files there's still some problems with this code (sizes that are generated seem to be wrong) and there's some additional pieces that are needed from NetBSD's install as well as hacks to the build system. We're installing about 17k files now. 10k are recorded in the metadata file, while 7k aren't. The vast majority of which are links of some flavor or another. Pieces to merge still: nopriv install and support for using install to manage links rather than using ln. Also, ee installs its nls files to the wrong place, which will need to be fixed. The metadata shows this. Modified: user/imp/nopriv/usr.bin/xinstall/Makefile user/imp/nopriv/usr.bin/xinstall/xinstall.c Modified: user/imp/nopriv/usr.bin/xinstall/Makefile ============================================================================== --- user/imp/nopriv/usr.bin/xinstall/Makefile Fri Apr 2 05:12:46 2010 (r206069) +++ user/imp/nopriv/usr.bin/xinstall/Makefile Fri Apr 2 05:14:57 2010 (r206070) @@ -5,4 +5,9 @@ PROG= xinstall PROGNAME= install MAN= install.1 +.PATH: ${.CURDIR}/../../usr.sbin/mtree +CFLAGS+= -I${.CURDIR}/../../usr.sbin/mtree +LDADD+= -lmd +DPADD+= ${LIBMD} + .include Modified: user/imp/nopriv/usr.bin/xinstall/xinstall.c ============================================================================== --- user/imp/nopriv/usr.bin/xinstall/xinstall.c Fri Apr 2 05:12:46 2010 (r206069) +++ user/imp/nopriv/usr.bin/xinstall/xinstall.c Fri Apr 2 05:14:57 2010 (r206070) @@ -64,6 +64,16 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + +#include +#if 0 +#include +#include +#include +#endif + +#include "mtree.h" /* Bootstrap aid - this doesn't exist in most older releases */ #ifndef MAP_FAILED @@ -82,11 +92,29 @@ struct group *gp; gid_t gid; uid_t uid; int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose; +char *group, *owner, *fflags, *tags; mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; const char *suffix = BACKUP_SUFFIX; +const char *metafile = NULL; +FILE *metafp; +char *destdir; + +enum { + DIGEST_NONE = 0, + DIGEST_MD5, +#if 0 + DIGEST_RMD160, + DIGEST_SHA1, + DIGEST_SHA256, + DIGEST_SHA384, + DIGEST_SHA512, +#endif +} digesttype = DIGEST_NONE; +char *digest; + static int compare(int, const char *, size_t, int, const char *, size_t); -static void copy(int, const char *, int, const char *, off_t); +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 void install(const char *, const char *, u_long, u_int); @@ -95,6 +123,8 @@ static u_long numeric_id(const char *, c static void strip(const char *); static int trymmap(int); static void usage(void); +static void metadata_log(const char *, const char *, struct timeval *, + const char *, const char *, off_t); int main(int argc, char *argv[]) @@ -104,13 +134,15 @@ main(int argc, char *argv[]) u_long fset; int ch, no_target; u_int iflags; - char *flags; - const char *group, *owner, *to_name; + 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, "a:B:bCcdf:g:Mm:o:pSsv")) != -1) switch((char)ch) { + case 'a': + metafile = optarg; + break; case 'B': suffix = optarg; /* FALLTHROUGH */ @@ -127,14 +159,17 @@ main(int argc, char *argv[]) dodir = 1; break; case 'f': - flags = optarg; - if (strtofflags(&flags, &fset, NULL)) - errx(EX_USAGE, "%s: invalid flag", flags); + fflags = optarg; + if (strtofflags(&fflags, &fset, NULL)) + errx(EX_USAGE, "%s: invalid flag", fflags); iflags |= SETFLAGS; break; case 'g': group = optarg; break; + case 'h': + digest = optarg; + break; case 'M': nommap = 1; break; @@ -160,6 +195,9 @@ main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'T': + tags = optarg; + break; case '?': default: usage(); @@ -182,6 +220,30 @@ main(int argc, char *argv[]) if (argc == 0 || (argc == 1 && !dodir)) usage(); + if (digest) { + if (0) { + } else if (strcmp(digest, "none") == 0) { + digesttype = DIGEST_NONE; + } else if (strcmp(digest, "md5") == 0) { + digesttype = DIGEST_MD5; +#if 0 + } else if (strcmp(digest, "rmd160") == 0) { + digesttype = DIGEST_RMD160; + } else if (strcmp(digest, "sha1") == 0) { + digesttype = DIGEST_SHA1; + } else if (strcmp(digest, "sha256") == 0) { + digesttype = DIGEST_SHA256; + } else if (strcmp(digest, "sha384") == 0) { + digesttype = DIGEST_SHA384; + } else if (strcmp(digest, "sha512") == 0) { + digesttype = DIGEST_SHA512; + } else { +#endif + warnx("unknown digest `%s'", digest); + usage(); + } + } + /* need to make a temp copy so we can compare stripped version */ if (docompare && dostrip) safecopy = 1; @@ -203,6 +265,12 @@ main(int argc, char *argv[]) } else uid = (uid_t)-1; + if (metafile) { + if ((metafp = fopen(metafile, "a")) == NULL) + warn("open %s", metafile); + } else + digesttype = DIGEST_NONE; + if (dodir) { for (; *argv != NULL; ++argv) install_dir(*argv); @@ -277,11 +345,20 @@ 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 = NULL; + struct timeval tv[2]; + off_t size; files_match = 0; from_fd = -1; to_fd = -1; + if (stat(from_name, &from_sb)) + err(1, "%s: stat", from_name); + size = from_sb.st_size; + TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec); + /* If try to install NULL file to a directory, fails. */ if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { if (stat(from_name, &from_sb)) @@ -348,7 +425,7 @@ install(const char *from_name, const cha from_name, to_name); } if (!devnull) - copy(from_fd, from_name, to_fd, + digestresult = copy(from_fd, from_name, to_fd, tempcopy ? tempfile : to_name, from_sb.st_size); } @@ -514,6 +591,8 @@ install(const char *from_name, const cha } } + metadata_log(to_name, "file", /* tv */NULL, NULL, digestresult, size); + free(digestresult); (void)close(to_fd); if (!devnull) (void)close(from_fd); @@ -650,7 +729,7 @@ create_newfile(const char *path, int tar * copy -- * copy from one file to another */ -static void +static char * copy(int from_fd, const char *from_name, int to_fd, const char *to_name, off_t size) { @@ -658,6 +737,42 @@ copy(int from_fd, const char *from_name, int serrno; char *p, buf[MAXBSIZE]; int done_copy; + MD5_CTX ctxMD5; +#if 0 + RMD160_CTX ctxRMD160; + SHA1_CTX ctxSHA1; + SHA256_CTX ctxSHA256; + SHA384_CTX ctxSHA384; + SHA512_CTX ctxSHA512; +#endif + + switch (digesttype) { + case DIGEST_MD5: + MD5Init(&ctxMD5); + break; +#if 0 + case DIGEST_RMD160: + RMD160Init(&ctxRMD160); + break; + case DIGEST_SHA1: + SHA1Init(&ctxSHA1); + break; + case DIGEST_SHA256: + SHA256_Init(&ctxSHA256); + break; + case DIGEST_SHA384: + SHA384_Init(&ctxSHA384); + break; + case DIGEST_SHA512: + SHA512_Init(&ctxSHA512); + break; +#endif + case DIGEST_NONE: + if (to_fd < 0) + return NULL; /* no need to do anything */ + default: + break; + } /* Rewind file descriptors. */ if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) @@ -680,6 +795,30 @@ copy(int from_fd, const char *from_name, errno = nw > 0 ? EIO : serrno; err(EX_OSERR, "%s", to_name); } + switch (digesttype) { + case DIGEST_MD5: + MD5Update(&ctxMD5, p, size); + break; +#if 0 + case DIGEST_RMD160: + RMD160Update(&ctxRMD160, p, size); + break; + case DIGEST_SHA1: + SHA1Update(&ctxSHA1, p, size); + break; + case DIGEST_SHA256: + SHA256_Update(&ctxSHA256, p, size); + break; + case DIGEST_SHA384: + SHA384_Update(&ctxSHA384, p, size); + break; + case DIGEST_SHA512: + SHA512_Update(&ctxSHA512, p, size); + break; +#endif + default: + break; + } done_copy = 1; } if (!done_copy) { @@ -690,6 +829,30 @@ copy(int from_fd, const char *from_name, errno = nw > 0 ? EIO : serrno; err(EX_OSERR, "%s", to_name); } + switch (digesttype) { + case DIGEST_MD5: + MD5Update(&ctxMD5, buf, nr); + break; +#if 0 + case DIGEST_RMD160: + RMD160Update(&ctxRMD160, buf, nr); + break; + case DIGEST_SHA1: + SHA1Update(&ctxSHA1, buf, nr); + break; + case DIGEST_SHA256: + SHA256_Update(&ctxSHA256, buf, nr); + break; + case DIGEST_SHA384: + SHA384_Update(&ctxSHA384, buf, nr); + break; + case DIGEST_SHA512: + SHA512_Update(&ctxSHA512, buf, nr); + break; +#endif + default: + break; + } if (nr != 0) { serrno = errno; (void)unlink(to_name); @@ -697,6 +860,24 @@ copy(int from_fd, const char *from_name, err(EX_OSERR, "%s", from_name); } } + switch (digesttype) { + case DIGEST_MD5: + return MD5End(&ctxMD5, NULL); +#if 0 + case DIGEST_RMD160: + return RMD160End(&ctxRMD160, NULL); + case DIGEST_SHA1: + return SHA1End(&ctxSHA1, NULL); + case DIGEST_SHA256: + return SHA256_End(&ctxSHA256, NULL); + case DIGEST_SHA384: + return SHA384_End(&ctxSHA384, NULL); + case DIGEST_SHA512: + return SHA512_End(&ctxSHA512, NULL); +#endif + default: + return NULL; + } } /* @@ -804,3 +985,91 @@ trymmap(int fd) #endif return (0); } + +/* + * metadata_log -- + * if metafp is not NULL, output mtree(8) full path name and settings to + * metafp, to allow permissions to be set correctly by other tools, + * or to allow integrity checks to be performed. + */ +static void +metadata_log(const char *path, const char *type, struct timeval *tv, + const char *slink, const char *digestresult, off_t size) +{ +#if 0 + static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; +#endif + const char *p; + char *buf; + size_t destlen; + struct flock metalog_lock; + + if (!metafp) + return; + buf = (char *)malloc(4 * strlen(path) + 1); /* buf for strsvis(3) */ + if (buf == NULL) { + warnx("%s", strerror(ENOMEM)); + return; + } + /* lock log file */ + metalog_lock.l_start = 0; + metalog_lock.l_len = 0; + metalog_lock.l_whence = SEEK_SET; + metalog_lock.l_type = F_WRLCK; + if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { + warn("can't lock %s", metafile); + free(buf); + return; + } + + p = path; /* remove destdir */ + if (destdir) { + destlen = strlen(destdir); + if (strncmp(p, destdir, destlen) == 0 && + (p[destlen] == '/' || p[destlen] == '\0')) + p += destlen; + } + while (*p && *p == '/') /* remove leading /s */ + p++; +#if 0 + /* Need to import this to do things totally right */ + strsvis(buf, p, VIS_CSTYLE, extra); /* encode name */ +#else + strvis(buf, p, VIS_CSTYLE); /* encode name */ +#endif + p = buf; + /* print details */ + fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type); + if (owner) + fprintf(metafp, " uname=%s", owner); + if (group) + fprintf(metafp, " gname=%s", group); + fprintf(metafp, " mode=%#o", mode); + if (slink) { +#if 0 + strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */ +#else + strvis(buf, slink, VIS_CSTYLE); /* encode link */ +#endif + fprintf(metafp, " link=%s", buf); + } + if (*type == 'f') /* type=file */ + fprintf(metafp, " size=%lld", (long long)size); + if (tv != NULL && dopreserve) + fprintf(metafp, " time=%lld.%ld", + (long long)tv[1].tv_sec, (long)tv[1].tv_usec); + if (digestresult && digest) + fprintf(metafp, " %s=%s", digest, digestresult); + if (fflags) + fprintf(metafp, " flags=%s", fflags); + if (tags) + fprintf(metafp, " tags=%s", tags); + fputc('\n', metafp); + fflush(metafp); /* flush output */ + /* unlock log file */ + metalog_lock.l_type = F_UNLCK; + if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { + warn("can't unlock %s", metafile); + } + free(buf); +}