Date: Tue, 10 Apr 2001 19:50:31 -0700 From: "Alec Wolman" <wolman@cs.washington.edu> To: ports@freebsd.org Cc: sobomax@freebsd.org Subject: [PATCH] fix the package tools symlink handling Message-ID: <200104110250.TAA10241@miles.cs.washington.edu>
next in thread | raw e-mail | index | archive | help
This is a multipart MIME message. --==_Exmh_7243708620 Content-Type: text/plain; charset=us-ascii The package tools currently do not handle symbolic links gracefully. In particular, the md5 hash for symlinks is calculated on the target of symlink rather than the link itself. While this strategy can work for plain files, it breaks for directories - each time the contents of a directory change, so does the md5 hash. Therefore, pkg_delete will often fail to delete symlinks to directories when removing a package. To deal with this, I have modified the package tools to calculate the md5 hash for symbolic links based on the link (i.e. the string returned by readlink()). This potentially introduces a compatibility problem (the newer package tools wouldn't know if the md5 value in the package was calculated based on the link or the target), so in addition I have added a packing-list format version number to disambiguate this situation. This version number can also be used to handle future changes to packing lists. These patches have been reviewed by Maxim Sobolev (sobomax@freebsd.org). -Alec --==_Exmh_7243708620 Content-Type: text/plain ; name="patch.symlink"; charset=us-ascii Content-Description: patch.symlink Content-Disposition: attachment; filename="patch.symlink" Index: create/perform.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/create/perform.c,v retrieving revision 1.54 diff -d -u -r1.54 perform.c --- create/perform.c 2001/03/15 10:47:00 1.54 +++ create/perform.c 2001/03/29 17:44:42 @@ -156,6 +156,13 @@ if (find_plist(&plist, PLIST_NAME) == NULL) add_plist_top(&plist, PLIST_NAME, basename_of(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. Index: create/pl.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/create/pl.c,v retrieving revision 1.15 diff -d -u -r1.15 pl.c --- create/pl.c 2001/01/12 11:36:12 1.15 +++ create/pl.c 2001/03/29 17:44:42 @@ -51,7 +51,16 @@ break; case PLIST_FILE: sprintf(name, "%s/%s", there ? there : where, p->name); - if ((cp = MD5File(name, buf)) != NULL) { + if (issymlink(name)) { + int len; + char link[FILENAME_MAX]; + + cp = (len = readlink(name, link, FILENAME_MAX)) > 0 ? + MD5Data((unsigned char *)link, len, buf) : NULL; + } else + cp = MD5File(name, buf); + + if (cp != NULL) { PackingList tmp = new_plist_entry(); tmp->name = copy_string(strconcat("MD5:", cp)); Index: info/info.h =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/info.h,v retrieving revision 1.19 diff -d -u -r1.19 info.h --- info/info.h 2001/03/23 18:45:24 1.19 +++ info/info.h 2001/03/29 17:44:44 @@ -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_size(char *, Package *); extern void show_cksum(char *, Package *); extern void show_origin(char *, Package *); +extern void show_fmtrev(char *, Package *); #endif /* _INST_INFO_H_INCLUDE */ Index: info/main.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/main.c,v retrieving revision 1.31 diff -d -u -r1.31 main.c --- info/main.c 2001/03/23 18:45:24 1.31 +++ info/main.c 2001/03/29 17:44:44 @@ -28,7 +28,7 @@ "$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 @@ Flags |= SHOW_ORIGIN; break; + case 'V': + Flags |= SHOW_FMTREV; + break; + case 'l': InfoPrefix = optarg; break; @@ -216,7 +220,7 @@ 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); Index: info/perform.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/perform.c,v retrieving revision 1.39 diff -d -u -r1.39 perform.c --- info/perform.c 2001/03/26 09:57:26 1.39 +++ info/perform.c 2001/03/29 17:44:47 @@ -218,6 +218,8 @@ 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); } Index: info/show.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/show.c,v retrieving revision 1.21 diff -d -u -r1.21 show.c --- info/show.c 2001/03/23 18:45:24 1.21 +++ info/show.c 2001/03/29 17:44:47 @@ -301,3 +301,12 @@ break; } } + +/* Show revision number of the packing list */ +void +show_fmtrev(char *title, Package *plist) +{ + if (!Quiet) + printf("%s%s", InfoPrefix, title); + printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr); +} Index: lib/Makefile =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/Makefile,v retrieving revision 1.8 diff -d -u -r1.8 Makefile --- lib/Makefile 2001/03/15 10:47:00 1.8 +++ lib/Makefile 2001/03/29 17:44:47 @@ -2,7 +2,7 @@ LIB= install SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c match.c \ - deps.c + deps.c version.c CFLAGS+= ${DEBUG} NOPROFILE= yes NOPIC= yes Index: lib/lib.h =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/lib.h,v retrieving revision 1.34 diff -d -u -r1.34 lib.h --- lib/lib.h 2001/03/23 18:45:24 1.34 +++ lib/lib.h 2001/03/29 17:44:49 @@ -79,6 +79,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, @@ -106,6 +110,7 @@ struct _pack { struct _plist *head, *tail; + int fmtver_maj, fmtver_mnr; }; typedef struct _pack Package; @@ -182,6 +187,9 @@ /* Dependencies */ int sortdeps(char **); int chkifdepends(char *, char *); + +/* Version */ +int verscmp(Package *, int, int); /* Externs */ extern Boolean Verbose; Index: lib/plist.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/plist.c,v retrieving revision 1.32 diff -d -u -r1.32 plist.c --- lib/plist.c 2001/01/22 12:01:55 1.32 +++ lib/plist.c 2001/03/29 17:44:49 @@ -238,8 +238,10 @@ 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); @@ -248,17 +250,35 @@ if (!len) continue; cp = pline; - if (pline[0] == CMD_CHAR) { - cmd = plist_cmd(pline + 1, &cp); - if (cmd == FAIL) { + 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); - errx(2, __FUNCTION__ ": bad command '%s'", pline); + exit(2); } - if (*cp == '\0') - cp = NULL; } - else - cmd = PLIST_FILE; +bottom: add_plist(pkg, cmd, cp); } } @@ -398,7 +418,22 @@ if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { char *cp, 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 link[FILENAME_MAX]; + + cp = (len = readlink(tmp, link, FILENAME_MAX)) > 0 ? + MD5Data((unsigned char *)link, len, buf) : NULL; + } else + cp = MD5File(tmp, buf); + + if (cp != NULL) { /* Mismatch? */ if (strcmp(cp, p->next->name + 4)) { if (Verbose) Index: lib/version.c =================================================================== RCS file: version.c diff -N version.c --- /dev/null Thu Mar 29 09:39:38 2001 +++ version.c Thu Mar 29 09:44:49 2001 @@ -0,0 +1,36 @@ +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif + +/* + * Copyright (c) 2001 Alec Wolman + * + * 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 <err.h> + +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; +} + --==_Exmh_7243708620-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200104110250.TAA10241>