From f3fa78b0b5918dc84a408b1b217d81b27db2b896 Mon Sep 17 00:00:00 2001 From: Maxim Sobolev Date: Wed, 10 Oct 2001 08:21:41 +0000 Subject: [PATCH] - Introduce a notion of `packing list format version'. This allows making non-backward compatible changes in the format of packing list and handle them gracefully; - fix a longstanding issue with symlinks handling. Instead of recording checksum for the file symlink points to, record checksum for the value returned by readlink(2). For backward compatibility increase packing list format minor version number and provide a fallback to a previous behaviour, if package in question was created with older version of pkg_* tools; Submitted by: Alec Wolman , sobomax - don't record MD5 checksum for device nodes, fifo's and other non-regular files. Submitted by: nbm MFC in: 2 weeks --- usr.sbin/pkg_install/create/perform.c | 7 ++++ usr.sbin/pkg_install/create/pl.c | 14 ++++++- usr.sbin/pkg_install/info/info.h | 2 + usr.sbin/pkg_install/info/main.c | 8 +++- usr.sbin/pkg_install/info/perform.c | 2 + usr.sbin/pkg_install/info/pkg_info.1 | 4 +- usr.sbin/pkg_install/info/show.c | 9 ++++ usr.sbin/pkg_install/lib/Makefile | 3 +- usr.sbin/pkg_install/lib/lib.h | 8 ++++ usr.sbin/pkg_install/lib/plist.c | 60 +++++++++++++++++++++------ usr.sbin/pkg_install/lib/version.c | 48 +++++++++++++++++++++ 11 files changed, 147 insertions(+), 18 deletions(-) create mode 100644 usr.sbin/pkg_install/lib/version.c diff --git a/usr.sbin/pkg_install/create/perform.c b/usr.sbin/pkg_install/create/perform.c index cd1f8a5011d..8265e268577 100644 --- a/usr.sbin/pkg_install/create/perform.c +++ b/usr.sbin/pkg_install/create/perform.c @@ -163,6 +163,13 @@ pkg_perform(char **pkgs) if (find_plist(&plist, PLIST_NAME) == NULL) add_plist_top(&plist, PLIST_NAME, basename(pkg)); + if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR, + PLIST_FMT_VER_MINOR) == -1) { + errx(2, "%s: asprintf() failed", __FUNCTION__); + } + add_plist_top(&plist, PLIST_COMMENT, cp); + free(cp); + /* * We're just here for to dump out a revised plist for the FreeBSD ports * hack. It's not a real create in progress. diff --git a/usr.sbin/pkg_install/create/pl.c b/usr.sbin/pkg_install/create/pl.c index 028b49c7166..a12ce625d46 100644 --- a/usr.sbin/pkg_install/create/pl.c +++ b/usr.sbin/pkg_install/create/pl.c @@ -50,8 +50,20 @@ check_list(const char *home, Package *pkg) there = p->name; break; case PLIST_FILE: + cp = NULL; sprintf(name, "%s/%s", there ? there : where, p->name); - if ((cp = MD5File(name, buf)) != NULL) { + if (issymlink(name)) { + int len; + char lnk[FILENAME_MAX]; + + if ((len = readlink(name, lnk, FILENAME_MAX)) > 0) + cp = MD5Data((unsigned char *)lnk, len, buf); + } else if (isfile(name)) { + /* Don't record MD5 checksum for device nodes and such */ + cp = MD5File(name, buf); + } + + if (cp != NULL) { PackingList tmp = new_plist_entry(); tmp->name = copy_string(strconcat("MD5:", cp)); diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h index 9b3804aec4a..3f0bb9a627d 100644 --- a/usr.sbin/pkg_install/info/info.h +++ b/usr.sbin/pkg_install/info/info.h @@ -48,6 +48,7 @@ #define SHOW_SIZE 0x1000 #define SHOW_ORIGIN 0x2000 #define SHOW_CKSUM 0x4000 +#define SHOW_FMTREV 0x8000 struct which_entry { TAILQ_ENTRY(which_entry) next; @@ -72,5 +73,6 @@ extern void show_index(const char *, const char *); extern void show_size(const char *, Package *); extern void show_cksum(const char *, Package *); extern void show_origin(const char *, Package *); +extern void show_fmtrev(const char *, Package *); #endif /* _INST_INFO_H_INCLUDE */ diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c index 6e4e855f5eb..3c78c2fdf7e 100644 --- a/usr.sbin/pkg_install/info/main.c +++ b/usr.sbin/pkg_install/info/main.c @@ -28,7 +28,7 @@ static const char rcsid[] = "$FreeBSD$"; #endif -static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vW:x"; +static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vVW:x"; int Flags = 0; match_t MatchType = MATCH_GLOB; @@ -134,6 +134,10 @@ main(int argc, char **argv) Flags |= SHOW_ORIGIN; break; + case 'V': + Flags |= SHOW_FMTREV; + break; + case 'l': InfoPrefix = optarg; break; @@ -216,7 +220,7 @@ static void usage() { fprintf(stderr, "%s\n%s\n%s\n", - "usage: pkg_info [-cdDfGiIkLmopqrRsvx] [-e package] [-l prefix]", + "usage: pkg_info [-cdDfGiIkLmopqrRsvVx] [-e package] [-l prefix]", " [-t template] [-W filename] [pkg-name ...]", " pkg_info -a [flags]"); exit(1); diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c index 1b5d2d8496a..9c5c927beae 100644 --- a/usr.sbin/pkg_install/info/perform.c +++ b/usr.sbin/pkg_install/info/perform.c @@ -214,6 +214,8 @@ pkg_do(char *pkg) show_cksum("Mismatched Checksums:\n", &plist); if (Flags & SHOW_ORIGIN) show_origin("Origin:\n", &plist); + if (Flags & SHOW_FMTREV) + show_fmtrev("Packing list format revision:\n", &plist); if (!Quiet) puts(InfoPrefix); } diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1 index ac2d4483825..37b52536de8 100644 --- a/usr.sbin/pkg_install/info/pkg_info.1 +++ b/usr.sbin/pkg_install/info/pkg_info.1 @@ -25,7 +25,7 @@ .Nd a utility for displaying information on software packages .Sh SYNOPSIS .Nm -.Op Fl cdDfgGiIkLmopqrRsvx +.Op Fl cdDfgGiIkLmopqrRsvVx .Op Fl e Ar package .Op Fl l Ar prefix .Op Fl t Ar template @@ -163,6 +163,8 @@ and one would have to have a very small .Pa /tmp indeed to overflow it. .Ed +.It Fl V +Show revision number of the packing list format. .El .Sh TECHNICAL DETAILS Package info is either extracted from package files named on the diff --git a/usr.sbin/pkg_install/info/show.c b/usr.sbin/pkg_install/info/show.c index 91432e5a1e2..03b1a537159 100644 --- a/usr.sbin/pkg_install/info/show.c +++ b/usr.sbin/pkg_install/info/show.c @@ -307,3 +307,12 @@ show_origin(const char *title, Package *plist) break; } } + +/* Show revision number of the packing list */ +void +show_fmtrev(const char *title, Package *plist) +{ + if (!Quiet) + printf("%s%s", InfoPrefix, title); + printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr); +} diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile index 78bedc4a26b..5d78e2c31cc 100644 --- a/usr.sbin/pkg_install/lib/Makefile +++ b/usr.sbin/pkg_install/lib/Makefile @@ -3,7 +3,8 @@ LIB= install NOPROFILE= yes NOPIC= yes -SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c match.c deps.c +SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c match.c \ + deps.c version.c CFLAGS+= ${DEBUG} diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h index 70a14080ca3..55fd2fa52e4 100644 --- a/usr.sbin/pkg_install/lib/lib.h +++ b/usr.sbin/pkg_install/lib/lib.h @@ -82,6 +82,10 @@ /* The name of the "prefix" environment variable given to scripts */ #define PKG_PREFIX_VNAME "PKG_PREFIX" +/* Version numbers to assist with changes in package file format */ +#define PLIST_FMT_VER_MAJOR 1 +#define PLIST_FMT_VER_MINOR 1 + enum _plist_t { PLIST_FILE, PLIST_CWD, PLIST_CMD, PLIST_CHMOD, PLIST_CHOWN, PLIST_CHGRP, PLIST_COMMENT, PLIST_IGNORE, @@ -109,6 +113,7 @@ typedef struct _plist *PackingList; struct _pack { struct _plist *head, *tail; + int fmtver_maj, fmtver_mnr; }; typedef struct _pack Package; @@ -192,6 +197,9 @@ int sortdeps(char **); int chkifdepends(const char *, const char *); int requiredby(const char *, struct reqr_by_head **, Boolean, Boolean); +/* Version */ +int verscmp(Package *, int, int); + /* Externs */ extern Boolean Verbose; extern Boolean Fake; diff --git a/usr.sbin/pkg_install/lib/plist.c b/usr.sbin/pkg_install/lib/plist.c index c7b37381441..4e3fd46d3d5 100644 --- a/usr.sbin/pkg_install/lib/plist.c +++ b/usr.sbin/pkg_install/lib/plist.c @@ -239,8 +239,10 @@ void read_plist(Package *pkg, FILE *fp) { char *cp, pline[FILENAME_MAX]; - int cmd; + int cmd, major, minor; + pkg->fmtver_maj = 1; + pkg->fmtver_mnr = 0; while (fgets(pline, FILENAME_MAX, fp)) { int len = strlen(pline); @@ -249,17 +251,35 @@ read_plist(Package *pkg, FILE *fp) if (!len) continue; cp = pline; - if (pline[0] == CMD_CHAR) { - cmd = plist_cmd(pline + 1, &cp); - if (cmd == FAIL) { - cleanup(0); - errx(2, __FUNCTION__ ": bad command '%s'", pline); - } - if (*cp == '\0') - cp = NULL; - } - else + if (pline[0] != CMD_CHAR) { cmd = PLIST_FILE; + goto bottom; + } + cmd = plist_cmd(pline + 1, &cp); + if (cmd == FAIL) { + cleanup(0); + errx(2, __FUNCTION__ ": bad command '%s'", pline); + } + if (*cp == '\0') { + cp = NULL; + goto bottom; + } + if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n", + &major, &minor) == 2) { + pkg->fmtver_maj = major; + pkg->fmtver_mnr = minor; + if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0) + goto bottom; + + warnx("plist format revision (%d.%d) is higher than supported" + "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr, + PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR); + if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) { + cleanup(0); + exit(2); + } + } +bottom: add_plist(pkg, cmd, cp); } } @@ -397,9 +417,23 @@ delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg) } else { if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { - char *cp, buf[33]; + char *cp = NULL, buf[33]; - if ((cp = MD5File(tmp, buf)) != NULL) { + /* + * For packing lists whose version is 1.1 or greater, the md5 + * hash for a symlink is calculated on the string returned + * by readlink(). + */ + if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) { + int len; + char linkbuf[FILENAME_MAX]; + + if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0) + cp = MD5Data((unsigned char *)linkbuf, len, buf); + } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0) + cp = MD5File(tmp, buf); + + if (cp != NULL) { /* Mismatch? */ if (strcmp(cp, p->next->name + 4)) { warnx("'%s' fails original MD5 checksum - %s", diff --git a/usr.sbin/pkg_install/lib/version.c b/usr.sbin/pkg_install/lib/version.c new file mode 100644 index 00000000000..1348fe8a52e --- /dev/null +++ b/usr.sbin/pkg_install/lib/version.c @@ -0,0 +1,48 @@ +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif + +/* + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Maxim Sobolev + * 31 July 2001 + * + * Routines to assist with PLIST_FMT_VER numbers in the packing + * lists. + * + * Following is the PLIST_FMT_VER history: + * 1.0 - Initial revision; + * 1.1 - When recording/checking checksum of symlink use hash of readlink() + * value insted of the hash of an object this links points to. + * + */ + +#include "lib.h" +#include + +int +verscmp(Package *pkg, int major, int minor) +{ + int rval = 0; + + if ((pkg->fmtver_maj < major) || (pkg->fmtver_maj == major && + pkg->fmtver_mnr < minor)) + rval = -1; + else if ((pkg->fmtver_maj > major) || (pkg->fmtver_maj == major && + pkg->fmtver_mnr > minor)) + rval = 1; + + return rval; +}