teknoraver / rpms / rpm

Forked from rpms/rpm 4 months ago
Clone
Blob Blame History Raw
From 6328e1e0da3ba26885f095ccbd83d223d5830527 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 5 Jan 2017 13:47:28 +0200
Subject: [PATCH 27/49] Unbreak short-circuited binary builds

Commit bbfe1f86b2e4b5c0bd499d9f3dd9de9c9c20fff2 broke short-circuited
binary builds (which can be handy for testing when working on large
packages), eg:
     rpmbuild -bi foo.spec; rpmbuild -bb --short-circuit foo.spec

The problem is that in a short-circuited build all the links already
exist and point to the right place, but the code doesn't realize this
and creates new links instead, which leaves the old links unowned
in the buildroot which ultimately causes the build to fail with
"Installed (but unpackaged) file(s) found" for the previously created
build-id links.

When checking for pre-existing links see if they already point to
the right file and in that case just reuse it instead of creating new ones.
Keep track of duplicate build-ids found by noticing existing links that
point to different targets. But don't do this for compat links, they should
just point to the last (duplicate) main build-id symlink found.

Signed-off-by: Mark Wielaard <mark@klomp.org>
(cherry picked from commit eea78b023539875309b7d38e4c8924f647644924)
---
 build/files.c | 71 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 51 insertions(+), 20 deletions(-)

diff --git a/build/files.c b/build/files.c
index 9f7def78c..2f02587f0 100644
--- a/build/files.c
+++ b/build/files.c
@@ -1565,11 +1565,12 @@ exit:
 
 static int addNewIDSymlink(FileList fl,
 			   char *targetpath, char *idlinkpath,
-			   int isDbg, int isCompat)
+			   int isDbg, int *dups)
 {
     const char *linkerr = _("failed symlink");
     int rc = 0;
     int nr = 0;
+    int exists = 0;
     char *origpath, *linkpath;
 
     if (isDbg)
@@ -1579,6 +1580,26 @@ static int addNewIDSymlink(FileList fl,
     origpath = linkpath;
 
     while (faccessat(AT_FDCWD, linkpath, F_OK, AT_SYMLINK_NOFOLLOW) == 0) {
+        /* We don't care about finding dups for compat links, they are
+	   OK as is.  Otherwise we will need to double check if
+	   existing link points to the correct target. */
+	if (dups == NULL)
+	  {
+	    exists = 1;
+	    break;
+	  }
+
+	char ltarget[PATH_MAX];
+	ssize_t llen;
+	/* In short-circuited builds the link might already exist  */
+	if ((llen = readlink(linkpath, ltarget, sizeof(ltarget)-1)) != -1) {
+	    ltarget[llen] = '\0';
+	    if (rstreq(ltarget, targetpath)) {
+		exists = 1;
+		break;
+	    }
+	}
+
 	if (nr > 0)
 	    free(linkpath);
 	nr++;
@@ -1586,21 +1607,16 @@ static int addNewIDSymlink(FileList fl,
 		  isDbg ? ".debug" : "");
     }
 
-    char *symtarget = targetpath;
-    if (nr > 0 && isCompat)
-	rasprintf (&symtarget, "%s.%d", targetpath, nr);
-
-    if (symlink(symtarget, linkpath) < 0) {
+    if (!exists && symlink(targetpath, linkpath) < 0) {
 	rc = 1;
 	rpmlog(RPMLOG_ERR, "%s: %s -> %s: %m\n",
-	       linkerr, linkpath, symtarget);
+	       linkerr, linkpath, targetpath);
     } else {
 	fl->cur.isDir = 0;
 	rc = addFile(fl, linkpath, NULL);
     }
 
-    /* Don't warn (again) if this is a compat id-link, we retarget it. */
-    if (nr > 0 && !isCompat) {
+    if (nr > 0) {
 	/* Lets see why there are multiple build-ids. If the original
 	   targets are hard linked, then it is OK, otherwise warn
 	   something fishy is going on. Would be nice to call
@@ -1629,8 +1645,8 @@ static int addNewIDSymlink(FileList fl,
 	free(origpath);
     if (nr > 0)
 	free(linkpath);
-    if (nr > 0 && isCompat)
-	free(symtarget);
+    if (dups != NULL)
+      *dups = nr;
 
     return rc;
 }
@@ -1872,6 +1888,7 @@ static int generateBuildIDs(FileList fl)
 			|| (rc = addFile(fl, buildidsubdir, NULL)) == 0) {
 			char *linkpattern, *targetpattern;
 			char *linkpath, *targetpath;
+			int dups = 0;
 			if (isDbg) {
 			    linkpattern = "%s/%s";
 			    targetpattern = "../../../../..%s";
@@ -1883,7 +1900,7 @@ static int generateBuildIDs(FileList fl)
 				  buildidsubdir, &ids[i][2]);
 			rasprintf(&targetpath, targetpattern, paths[i]);
 			rc = addNewIDSymlink(fl, targetpath, linkpath,
-					     isDbg, 0);
+					     isDbg, &dups);
 
 			/* We might want to have a link from the debug
 			   build_ids dir to the main one. We create it
@@ -1906,16 +1923,30 @@ static int generateBuildIDs(FileList fl)
 			    && build_id_links == BUILD_IDS_COMPAT) {
 			    /* buildidsubdir already points to the
 			       debug buildid. We just need to setup
-			       the symlink to the main one.  */
+			       the symlink to the main one. There
+			       might be duplicate IDs, those are found
+			       by the addNewIDSymlink above. Target
+			       the last found duplicate, if any. */
 			    free(linkpath);
 			    free(targetpath);
-			    rasprintf(&linkpath, "%s/%s",
-				      buildidsubdir, &ids[i][2]);
-			    rasprintf(&targetpath,
-				      "../../../.build-id%s/%s",
-				      subdir, &ids[i][2]);
+			    if (dups == 0)
+			      {
+				rasprintf(&linkpath, "%s/%s",
+					  buildidsubdir, &ids[i][2]);
+				rasprintf(&targetpath,
+					  "../../../.build-id%s/%s",
+					  subdir, &ids[i][2]);
+			      }
+			    else
+			      {
+				rasprintf(&linkpath, "%s/%s.%d",
+					  buildidsubdir, &ids[i][2], dups);
+				rasprintf(&targetpath,
+					  "../../../.build-id%s/%s.%d",
+					  subdir, &ids[i][2], dups);
+			      }
 			    rc = addNewIDSymlink(fl, targetpath, linkpath,
-						 0, 1);
+						 0, NULL);
 			}
 
 			if (rc == 0 && isDbg
@@ -1953,7 +1984,7 @@ static int generateBuildIDs(FileList fl)
 				rasprintf(&targetpath, "../../../../..%s",
 					  targetstr);
 				rc = addNewIDSymlink(fl, targetpath,
-						     linkpath, 0, 0);
+						     linkpath, 0, &dups);
 				free(targetstr);
 			    }
 			}
-- 
2.13.2