Skip site navigation (1)Skip section navigation (2)
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>