summaryrefslogtreecommitdiff
path: root/build/files.c
diff options
context:
space:
mode:
Diffstat (limited to 'build/files.c')
-rw-r--r--build/files.c1794
1 files changed, 1288 insertions, 506 deletions
diff --git a/build/files.c b/build/files.c
index 71d12729d..c641528a4 100644
--- a/build/files.c
+++ b/build/files.c
@@ -9,11 +9,17 @@
#define MYALLPERMS 07777
#include <errno.h>
+#include <stdlib.h>
#include <regex.h>
#if WITH_CAP
#include <sys/capability.h>
#endif
+#if HAVE_LIBDW
+#include <libelf.h>
+#include <elfutils/libdwelf.h>
+#endif
+
#include <rpm/rpmpgp.h>
#include <rpm/argv.h>
#include <rpm/rpmfc.h>
@@ -21,13 +27,8 @@
#include <rpm/rpmlog.h>
#include <rpm/rpmbase64.h>
-#if HAVE_GELF_H
-#include <gelf.h>
-#endif
-
#include "rpmio/rpmio_internal.h" /* XXX rpmioSlurp */
#include "misc/rpmfts.h"
-#include "lib/cpio.h"
#include "lib/rpmfi_internal.h" /* XXX fi->apath */
#include "lib/rpmug.h"
#include "build/rpmbuild_internal.h"
@@ -37,8 +38,29 @@
#include <libgen.h>
#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
-#define SKIPWHITE(_x) {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
-#define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+#define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
+#define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+
+/* the following defines must be in sync with the equally hardcoded paths from
+ * scripts/find-debuginfo.sh
+ */
+#define BUILD_ID_DIR "/usr/lib/.build-id"
+#define DEBUG_SRC_DIR "/usr/src/debug"
+#define DEBUG_LIB_DIR "/usr/lib/debug"
+#define DEBUG_LIB_PREFIX "/usr/lib/debug/"
+#define DEBUG_ID_DIR "/usr/lib/debug/.build-id"
+#define DEBUG_DWZ_DIR "/usr/lib/debug/.dwz"
+
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE fileRenameHash
+#define HTKEYTYPE const char *
+#define HTDATATYPE const char *
+#include "lib/rpmhash.C"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
/**
*/
@@ -85,8 +107,8 @@ typedef struct FileListRec_s {
char *diskPath; /* get file from here */
char *cpioPath; /* filename in cpio archive */
- const char *uname;
- const char *gname;
+ rpmsid uname;
+ rpmsid gname;
unsigned flags;
specfFlags specdFlags; /* which attributes have been explicitly specified. */
rpmVerifyFlags verifyFlags;
@@ -97,26 +119,19 @@ typedef struct FileListRec_s {
/**
*/
typedef struct AttrRec_s {
- char *ar_fmodestr;
- char *ar_dmodestr;
- char *ar_user;
- char *ar_group;
+ rpmsid ar_fmodestr;
+ rpmsid ar_dmodestr;
+ rpmsid ar_user;
+ rpmsid ar_group;
mode_t ar_fmode;
mode_t ar_dmode;
} * AttrRec;
-static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
-
/* list of files */
static StringBuf check_fileList = NULL;
-typedef struct specialDir_s {
- char * dirname;
- ARGV_t files;
- struct AttrRec_s ar;
- struct AttrRec_s def_ar;
- rpmFlags sdtype;
-} * specialDir;
+/*backup of maindb->fileList*/
+ARGV_t maindb_fileList_bakup = NULL;
typedef struct FileEntry_s {
rpmfileAttrs attrFlags;
@@ -134,6 +149,23 @@ typedef struct FileEntry_s {
int isDir;
} * FileEntry;
+typedef struct specialDir_s {
+ char * dirname;
+ ARGV_t files;
+ struct AttrRec_s ar;
+ struct AttrRec_s def_ar;
+ rpmFlags sdtype;
+
+ int entriesCount;
+ int entriesAlloced;
+
+ struct {
+ struct FileEntry_s defEntry;
+ struct FileEntry_s curEntry;
+ } *entries;
+
+} * specialDir;
+
typedef struct FileRecords_s {
FileListRec recs;
int alloced;
@@ -146,11 +178,13 @@ typedef struct FileRecords_s {
typedef struct FileList_s {
/* global filelist state */
char * buildRoot;
+ size_t buildRootLen;
int processingFailed;
int haveCaps;
int largeFiles;
ARGV_t docDirs;
rpmBuildPkgFlags pkgFlags;
+ rpmstrPool pool;
/* actual file records */
struct FileRecords_s files;
@@ -162,63 +196,45 @@ typedef struct FileList_s {
struct FileEntry_s cur;
} * FileList;
-/**
- */
static void nullAttrRec(AttrRec ar)
{
- ar->ar_fmodestr = NULL;
- ar->ar_dmodestr = NULL;
- ar->ar_user = NULL;
- ar->ar_group = NULL;
- ar->ar_fmode = 0;
- ar->ar_dmode = 0;
+ memset(ar, 0, sizeof(*ar));
}
-/**
- */
-static void freeAttrRec(AttrRec ar)
-{
- ar->ar_fmodestr = _free(ar->ar_fmodestr);
- ar->ar_dmodestr = _free(ar->ar_dmodestr);
- ar->ar_user = _free(ar->ar_user);
- ar->ar_group = _free(ar->ar_group);
- /* XXX doesn't free ar (yet) */
- return;
-}
-
-/**
- */
static void dupAttrRec(const AttrRec oar, AttrRec nar)
{
if (oar == nar)
return;
- freeAttrRec(nar);
- nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
- nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
- nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
- nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
- nar->ar_fmode = oar->ar_fmode;
- nar->ar_dmode = oar->ar_dmode;
+ *nar = *oar; /* struct assignment */
}
-#if 0
-/**
- */
-static void dumpAttrRec(const char * msg, AttrRec ar)
+/* Creates a default $defattr string. Can be used with argvAdd().
+ Caller owns the new string which needs to be freed when done. */
+static char *mkattr(void)
{
- if (msg)
- fprintf(stderr, "%s:\t", msg);
- fprintf(stderr, "(%s, %s, %s, %s)\n",
- ar->ar_fmodestr,
- ar->ar_user,
- ar->ar_group,
- ar->ar_dmodestr);
+ char *s = NULL;
+ rasprintf(&s, "%s(644,%s,%s,755)", "%defattr", UID_0_USER, GID_0_GROUP);
+ return s;
+}
+
+static void copyFileEntry(FileEntry src, FileEntry dest)
+{
+ /* Copying struct makes just shallow copy */
+ *dest = *src;
+
+ /* Do also deep copying */
+ if (src->langs != NULL) {
+ dest->langs = argvNew();
+ argvAppend(&dest->langs, src->langs);
+ }
+
+ if (src->caps != NULL) {
+ dest->caps = xstrdup(src->caps);
+ }
}
-#endif
static void FileEntryFree(FileEntry entry)
{
- freeAttrRec(&(entry->ar));
argvFree(entry->langs);
memset(entry, 0, sizeof(*entry));
}
@@ -377,7 +393,11 @@ exit:
return rc;
}
-#define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
+static int isAttrDefault(rpmstrPool pool, rpmsid arsid)
+{
+ const char *ars = rpmstrPoolStr(pool, arsid);
+ return (ars && ars[0] == '-' && ars[1] == '\0');
+}
/**
* Parse %dev from file manifest.
@@ -391,6 +411,7 @@ static rpmRC parseForDev(char * buf, FileEntry cur)
const char * errstr = NULL;
char *p, *pe, *q = NULL;
rpmRC rc = RPMRC_FAIL; /* assume error */
+ char *attr_parameters = NULL;
if ((p = strstr(buf, (name = "%dev"))) == NULL)
return RPMRC_OK;
@@ -416,6 +437,10 @@ static rpmRC parseForDev(char * buf, FileEntry cur)
/* Localize. Erase parsed string */
q = xmalloc((pe-p) + 1);
rstrlcpy(q, p, (pe-p) + 1);
+
+ attr_parameters = xmalloc((pe-p) + 1);
+ rstrlcpy(attr_parameters, p, (pe-p) + 1);
+
while (p <= pe)
*p++ = ' ';
@@ -465,23 +490,26 @@ static rpmRC parseForDev(char * buf, FileEntry cur)
exit:
if (rc) {
- rpmlog(RPMLOG_ERR, _("Missing %s in %s %s\n"), errstr, name, p);
+ rpmlog(RPMLOG_ERR, _("Missing %s in %s(%s)\n"), errstr, name, attr_parameters);
}
+ free(attr_parameters);
free(q);
return rc;
}
/**
* Parse %attr and %defattr from file manifest.
+ * @param pool string pool
* @param buf current spec file line
* @param def parse for %defattr or %attr?
* @param entry file entry data (current / default)
* @return 0 on success
*/
-static rpmRC parseForAttr(char * buf, int def, FileEntry entry)
+static rpmRC parseForAttr(rpmstrPool pool, char * buf, int def, FileEntry entry)
{
const char *name = def ? "%defattr" : "%attr";
char *p, *pe, *q = NULL;
+ char *attr_parameters = NULL;
int x;
struct AttrRec_s arbuf;
AttrRec ar = &arbuf;
@@ -519,6 +547,10 @@ static rpmRC parseForAttr(char * buf, int def, FileEntry entry)
/* Localize. Erase parsed string */
q = xmalloc((pe-p) + 1);
rstrlcpy(q, p, (pe-p) + 1);
+
+ attr_parameters = xmalloc((pe-p) + 1);
+ rstrlcpy(attr_parameters, p, (pe-p) + 1);
+
while (p <= pe)
*p++ = ' ';
@@ -527,61 +559,61 @@ static rpmRC parseForAttr(char * buf, int def, FileEntry entry)
p = q; SKIPWHITE(p);
if (*p != '\0') {
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
- ar->ar_fmodestr = p;
+ ar->ar_fmodestr = rpmstrPoolId(pool, p, 1);
p = pe; SKIPWHITE(p);
}
if (*p != '\0') {
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
- ar->ar_user = p;
+ ar->ar_user = rpmstrPoolId(pool, p, 1);
p = pe; SKIPWHITE(p);
}
if (*p != '\0') {
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
- ar->ar_group = p;
+ ar->ar_group = rpmstrPoolId(pool, p, 1);
p = pe; SKIPWHITE(p);
}
if (*p != '\0' && def) { /* %defattr */
pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
- ar->ar_dmodestr = p;
+ ar->ar_dmodestr = rpmstrPoolId(pool, p, 1);
p = pe; SKIPWHITE(p);
}
if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
- rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n"), name, q);
+ rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n"), name, attr_parameters);
goto exit;
}
/* Do a quick test on the mode argument and adjust for "-" */
- if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
+ if (ar->ar_fmodestr && !isAttrDefault(pool, ar->ar_fmodestr)) {
unsigned int ui;
- x = sscanf(ar->ar_fmodestr, "%o", &ui);
+ x = sscanf(rpmstrPoolStr(pool, ar->ar_fmodestr), "%o", &ui);
if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
- rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n"), name, q);
+ rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n"), name, attr_parameters);
goto exit;
}
ar->ar_fmode = ui;
} else {
- ar->ar_fmodestr = NULL;
+ ar->ar_fmodestr = 0;
}
- if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
+ if (ar->ar_dmodestr && !isAttrDefault(pool, ar->ar_dmodestr)) {
unsigned int ui;
- x = sscanf(ar->ar_dmodestr, "%o", &ui);
+ x = sscanf(rpmstrPoolStr(pool, ar->ar_dmodestr), "%o", &ui);
if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
- rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n"), name, q);
+ rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n"), name, attr_parameters);
goto exit;
}
ar->ar_dmode = ui;
} else {
- ar->ar_dmodestr = NULL;
+ ar->ar_dmodestr = 0;
}
- if (!(ar->ar_user && !isAttrDefault(ar->ar_user))) {
- ar->ar_user = NULL;
+ if (!(ar->ar_user && !isAttrDefault(pool, ar->ar_user))) {
+ ar->ar_user = 0;
}
- if (!(ar->ar_group && !isAttrDefault(ar->ar_group))) {
- ar->ar_group = NULL;
+ if (!(ar->ar_group && !isAttrDefault(pool, ar->ar_group))) {
+ ar->ar_group = 0;
}
dupAttrRec(ar, &(entry->ar));
@@ -592,6 +624,7 @@ static rpmRC parseForAttr(char * buf, int def, FileEntry entry)
exit:
free(q);
+ free(attr_parameters);
return rc;
}
@@ -826,7 +859,9 @@ static VFA_t const virtualAttrs[] = {
{ "%readme", RPMFILE_README },
{ "%license", RPMFILE_LICENSE },
{ "%pubkey", RPMFILE_PUBKEY },
- { "%manifest", RPMFILE_SECMANIFEST },
+ { "%missingok", RPMFILE_MISSINGOK },
+ { "%artifact", RPMFILE_ARTIFACT },
+ { "%manifest", RPMFILE_SECMANIFEST },
{ NULL, 0 }
};
@@ -907,7 +942,7 @@ static int isHardLink(FileListRec flp, FileListRec tlp)
/**
* Verify that file attributes scope over hardlinks correctly.
* If partial hardlink sets are possible, then add tracking dependency.
- * @param fl package file records
+ * @param files package file records
* @return 1 if partial hardlink sets can exist, 0 otherwise.
*/
static int checkHardLinks(FileRecords files)
@@ -946,22 +981,35 @@ static int seenHardLink(FileRecords files, FileListRec flp, rpm_ino_t *fileid)
* @todo Should directories have %doc/%config attributes? (#14531)
* @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
* @param fl package file tree walk data
- * @retval *fip file info for package
- * @param h
- * @param isSrc
+ * @param pkg (sub) package
+ * @param isSrc pass 1 for source packages 0 otherwise
*/
-static void genCpioListAndHeader(FileList fl,
- rpmfi * fip, Header h, int isSrc)
+static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
{
- int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
- size_t apathlen = 0;
- size_t dpathlen = 0;
- size_t skipLen = 0;
FileListRec flp;
char buf[BUFSIZ];
- int i;
+ int i, npaths = 0;
uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo;
rpm_loff_t totalFileSize = 0;
+ Header h = pkg->header; /* just a shortcut */
+ int override_date = 0;
+ time_t source_date_epoch;
+ char *srcdate = getenv("SOURCE_DATE_EPOCH");
+
+ /* Limit the maximum date to SOURCE_DATE_EPOCH if defined
+ * similar to the tar --clamp-mtime option
+ * https://reproducible-builds.org/specs/source-date-epoch/
+ */
+ if (srcdate && rpmExpandNumeric("%{?clamp_mtime_to_source_date_epoch}")) {
+ char *endptr;
+ errno = 0;
+ source_date_epoch = strtol(srcdate, &endptr, 10);
+ if (srcdate == endptr || *endptr || errno != 0) {
+ rpmlog(RPMLOG_ERR, _("unable to parse %s=%s\n"), "SOURCE_DATE_EPOCH", srcdate);
+ exit(28);
+ }
+ override_date = 1;
+ }
/*
* See if non-md5 file digest algorithm is requested. If not
@@ -979,16 +1027,40 @@ static void genCpioListAndHeader(FileList fl,
digestalgo);
digestalgo = defaultalgo;
}
-
+
+ /* Adjust paths if needed */
+ if (!isSrc && pkg->removePostfixes) {
+ pkg->fileRenameMap = fileRenameHashCreate(fl->files.used,
+ rstrhash, strcmp,
+ (fileRenameHashFreeKey)rfree, (fileRenameHashFreeData)rfree);
+ for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
+ char * cpiopath = flp->cpioPath;
+ char * cpiopath_orig = xstrdup(cpiopath);
+
+ for (ARGV_const_t postfix_p = pkg->removePostfixes; *postfix_p; postfix_p++) {
+ int len = strlen(*postfix_p);
+ int plen = strlen(cpiopath);
+ if (len <= plen && !strncmp(cpiopath+plen-len, *postfix_p, len)) {
+ cpiopath[plen-len] = '\0';
+ if (plen-len > 0 && cpiopath[plen-len-1] == '/') {
+ cpiopath[plen-len-1] = '\0';
+ }
+ }
+ }
+ if (strcmp(cpiopath_orig, cpiopath))
+ fileRenameHashAddEntry(pkg->fileRenameMap, xstrdup(cpiopath), cpiopath_orig);
+ else
+ _free(cpiopath_orig);
+ }
+ }
+
/* Sort the big list */
qsort(fl->files.recs, fl->files.used,
sizeof(*(fl->files.recs)), compareFileListRecs);
- /* Generate the header. */
- if (! isSrc) {
- skipLen = 1;
- }
+ pkg->dpaths = xmalloc((fl->files.used + 1) * sizeof(*pkg->dpaths));
+ /* Generate the header. */
for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
rpm_ino_t fileid = flp - fl->files.recs;
@@ -1044,29 +1116,26 @@ static void genCpioListAndHeader(FileList fl,
}
/* Skip files that were marked with %exclude. */
- if (flp->flags & RPMFILE_EXCLUDE) continue;
-
- /* Omit '/' and/or URL prefix, leave room for "./" prefix */
- apathlen += (strlen(flp->cpioPath) - skipLen + (_addDotSlash ? 3 : 1));
+ if (flp->flags & RPMFILE_EXCLUDE)
+ {
+ argvAdd(&pkg->fileExcludeList, flp->cpioPath);
+ continue;
+ }
- /* Leave room for both dirname and basename NUL's */
- dpathlen += (strlen(flp->diskPath) + 2);
+ /* Collect on-disk paths for archive creation */
+ pkg->dpaths[npaths++] = xstrdup(flp->diskPath);
- /*
- * Make the header. Store the on-disk path to OLDFILENAMES for
- * cpio list generation purposes for now, final path temporarily
- * to ORIGFILENAMES, to be swapped later into OLDFILENAMES.
- */
- headerPutString(h, RPMTAG_OLDFILENAMES, flp->diskPath);
- headerPutString(h, RPMTAG_ORIGFILENAMES, flp->cpioPath);
- headerPutString(h, RPMTAG_FILEUSERNAME, flp->uname);
- headerPutString(h, RPMTAG_FILEGROUPNAME, flp->gname);
+ headerPutString(h, RPMTAG_OLDFILENAMES, flp->cpioPath);
+ headerPutString(h, RPMTAG_FILEUSERNAME,
+ rpmstrPoolStr(fl->pool, flp->uname));
+ headerPutString(h, RPMTAG_FILEGROUPNAME,
+ rpmstrPoolStr(fl->pool, flp->gname));
/* Only use 64bit filesizes tag if required. */
if (fl->largeFiles) {
rpm_loff_t rsize64 = (rpm_loff_t)flp->fl_size;
headerPutUint64(h, RPMTAG_LONGFILESIZES, &rsize64, 1);
- /* XXX TODO: add rpmlib() dependency for large files */
+ (void) rpmlibNeedsFeature(pkg, "LargeFiles", "4.12.0-1");
} else {
rpm_off_t rsize32 = (rpm_off_t)flp->fl_size;
headerPutUint32(h, RPMTAG_FILESIZES, &rsize32, 1);
@@ -1078,6 +1147,9 @@ static void genCpioListAndHeader(FileList fl,
}
}
+ if (override_date && flp->fl_mtime > source_date_epoch) {
+ flp->fl_mtime = source_date_epoch;
+ }
/*
* For items whose size varies between systems, always explicitly
* cast to the header type before inserting.
@@ -1116,7 +1188,7 @@ static void genCpioListAndHeader(FileList fl,
}
buf[0] = '\0';
- if (S_ISREG(flp->fl_mode))
+ if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST))
(void) rpmDoDigest(digestalgo, flp->diskPath, 1,
(unsigned char *)buf, NULL);
headerPutString(h, RPMTAG_FILEDIGESTS, buf);
@@ -1131,7 +1203,7 @@ static void genCpioListAndHeader(FileList fl,
} else {
buf[llen] = '\0';
if (buf[0] == '/' && !rstreq(fl->buildRoot, "/") &&
- rstreqn(buf, fl->buildRoot, strlen(fl->buildRoot))) {
+ rstreqn(buf, fl->buildRoot, fl->buildRootLen)) {
rpmlog(RPMLOG_ERR,
_("Symlink points to BuildRoot: %s -> %s\n"),
flp->cpioPath, buf);
@@ -1157,6 +1229,7 @@ static void genCpioListAndHeader(FileList fl,
headerPutUint32(h, RPMTAG_FILEFLAGS, &(flp->flags) ,1);
}
+ pkg->dpaths[npaths] = NULL;
if (totalFileSize < UINT32_MAX) {
rpm_off_t totalsize = totalFileSize;
@@ -1168,69 +1241,31 @@ static void genCpioListAndHeader(FileList fl,
if (digestalgo != defaultalgo) {
headerPutUint32(h, RPMTAG_FILEDIGESTALGO, &digestalgo, 1);
- rpmlibNeedsFeature(h, "FileDigests", "4.6.0-1");
+ rpmlibNeedsFeature(pkg, "FileDigests", "4.6.0-1");
}
if (fl->haveCaps) {
- rpmlibNeedsFeature(h, "FileCaps", "4.6.1-1");
+ rpmlibNeedsFeature(pkg, "FileCaps", "4.6.1-1");
}
- if (_addDotSlash)
- (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
-
- {
- struct rpmtd_s filenames;
- rpmfiFlags flags = RPMFI_NOHEADER|RPMFI_NOFILEUSER|RPMFI_NOFILEGROUP;
- rpmfi fi;
- int fc;
- const char *fn;
- char *a, **apath;
+ if (!isSrc && !rpmExpandNumeric("%{_noPayloadPrefix}"))
+ (void) rpmlibNeedsFeature(pkg, "PayloadFilesHavePrefix", "4.0-1");
/* rpmfiNew() only groks compressed filelists */
headerConvert(h, HEADERCONV_COMPRESSFILELIST);
- fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, flags);
+ pkg->cpioList = rpmfilesNew(NULL, h, RPMTAG_BASENAMES,
+ (RPMFI_NOFILEUSER|RPMFI_NOFILEGROUP));
- if (fi == NULL) {
+ if (pkg->cpioList == NULL || rpmfilesFC(pkg->cpioList) != npaths) {
fl->processingFailed = 1;
- return;
}
- /*
- * Grab the real filenames from ORIGFILENAMES and put into OLDFILENAMES,
- * remove temporary cruft and side-effects from filelist compression
- * for rpmfiNew().
- */
- headerGet(h, RPMTAG_ORIGFILENAMES, &filenames, HEADERGET_ALLOC);
- headerDel(h, RPMTAG_ORIGFILENAMES);
- headerDel(h, RPMTAG_BASENAMES);
- headerDel(h, RPMTAG_DIRNAMES);
- headerDel(h, RPMTAG_DIRINDEXES);
- rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
- headerPut(h, &filenames, HEADERPUT_DEFAULT);
-
- /* Create hge-style archive path array, normally adding "./" */
- fc = rpmtdCount(&filenames);
- apath = xmalloc(fc * sizeof(*apath) + apathlen + 1);
- a = (char *)(apath + fc);
- *a = '\0';
- rpmtdInit(&filenames);
- for (int i = 0; (fn = rpmtdNextString(&filenames)); i++) {
- apath[i] = a;
- if (_addDotSlash)
- a = stpcpy(a, "./");
- a = stpcpy(a, (fn + skipLen));
- a++; /* skip apath NUL */
- }
- fi->apath = apath;
- *fip = fi;
- rpmtdFreeData(&filenames);
- }
-
- /* Compress filelist unless legacy format requested */
- if (!(fl->pkgFlags & RPMBUILD_PKG_NODIRTOKENS)) {
- headerConvert(h, HEADERCONV_COMPRESSFILELIST);
+ if (fl->pkgFlags & RPMBUILD_PKG_NODIRTOKENS) {
+ /* Uncompress filelist if legacy format requested */
+ headerConvert(h, HEADERCONV_EXPANDFILELIST);
+ } else {
/* Binary packages with dirNames cannot be installed by legacy rpm. */
- (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
+ (void) rpmlibNeedsFeature(pkg, "CompressedFileNames", "3.0.4-1");
}
}
@@ -1253,6 +1288,7 @@ static void FileListFree(FileList fl)
FileRecordsFree(&(fl->files));
free(fl->buildRoot);
argvFree(fl->docDirs);
+ rpmstrPoolFree(fl->pool);
}
/* forward ref */
@@ -1310,6 +1346,10 @@ static rpmRC addFile(FileList fl, const char * diskPath,
}
cpioPath = diskPath;
+ if (strncmp(diskPath, fl->buildRoot, fl->buildRootLen)) {
+ rpmlog(RPMLOG_ERR, _("Path is outside buildroot: %s\n"), diskPath);
+ goto exit;
+ }
/* Path may have prepended buildRoot, so locate the original filename. */
/*
@@ -1323,7 +1363,7 @@ static rpmRC addFile(FileList fl, const char * diskPath,
*
*/
if (fl->buildRoot && !rstreq(fl->buildRoot, "/"))
- cpioPath += strlen(fl->buildRoot);
+ cpioPath += fl->buildRootLen;
/* XXX make sure '/' can be packaged also */
if (*cpioPath == '\0')
@@ -1358,6 +1398,12 @@ static rpmRC addFile(FileList fl, const char * diskPath,
}
}
+ /* Error out when a non-directory is specified as one in spec */
+ if (fl->cur.isDir && (statp == &statbuf) && !S_ISDIR(statp->st_mode)) {
+ rpmlog(RPMLOG_ERR, _("Not a directory: %s\n"), diskPath);
+ goto exit;
+ }
+
/* Don't recurse into explicit %dir, don't double-recurse from fts */
if ((fl->cur.isDir != 1) && (statp == &statbuf) && S_ISDIR(statp->st_mode)) {
return recurseDir(fl, diskPath);
@@ -1368,9 +1414,15 @@ static rpmRC addFile(FileList fl, const char * diskPath,
fileGid = statp->st_gid;
/* Explicit %attr() always wins */
- if (fl->cur.ar.ar_fmodestr != NULL) {
- fileMode &= S_IFMT;
- fileMode |= fl->cur.ar.ar_fmode;
+ if (fl->cur.ar.ar_fmodestr) {
+ if (S_ISLNK(fileMode)) {
+ rpmlog(RPMLOG_WARNING,
+ "Explicit %%attr() mode not applicable to symlink: %s\n",
+ diskPath);
+ } else {
+ fileMode &= S_IFMT;
+ fileMode |= fl->cur.ar.ar_fmode;
+ }
} else {
/* ...but %defattr() for directories and files is different */
if (S_ISDIR(fileMode)) {
@@ -1378,22 +1430,22 @@ static rpmRC addFile(FileList fl, const char * diskPath,
fileMode &= S_IFMT;
fileMode |= fl->def.ar.ar_dmode;
}
- } else if (fl->def.ar.ar_fmodestr) {
+ } else if (!S_ISLNK(fileMode) && fl->def.ar.ar_fmodestr) {
fileMode &= S_IFMT;
fileMode |= fl->def.ar.ar_fmode;
}
}
if (fl->cur.ar.ar_user) {
- fileUname = fl->cur.ar.ar_user;
+ fileUname = rpmstrPoolStr(fl->pool, fl->cur.ar.ar_user);
} else if (fl->def.ar.ar_user) {
- fileUname = fl->def.ar.ar_user;
+ fileUname = rpmstrPoolStr(fl->pool, fl->def.ar.ar_user);
} else {
fileUname = rpmugUname(fileUid);
}
if (fl->cur.ar.ar_group) {
- fileGname = fl->cur.ar.ar_group;
+ fileGname = rpmstrPoolStr(fl->pool, fl->cur.ar.ar_group);
} else if (fl->def.ar.ar_group) {
- fileGname = fl->def.ar.ar_group;
+ fileGname = rpmstrPoolStr(fl->pool, fl->def.ar.ar_group);
} else {
fileGname = rpmugGname(fileGid);
}
@@ -1423,11 +1475,13 @@ static rpmRC addFile(FileList fl, const char * diskPath,
flp->fl_mode = fileMode;
flp->fl_uid = fileUid;
flp->fl_gid = fileGid;
+ if (S_ISDIR(fileMode))
+ flp->fl_size = 0;
flp->cpioPath = xstrdup(cpioPath);
flp->diskPath = xstrdup(diskPath);
- flp->uname = rpmugStashStr(fileUname);
- flp->gname = rpmugStashStr(fileGname);
+ flp->uname = rpmstrPoolId(fl->pool, fileUname, 1);
+ flp->gname = rpmstrPoolId(fl->pool, fileGname, 1);
if (fl->cur.langs) {
flp->langs = argvJoin(fl->cur.langs, "|");
@@ -1436,7 +1490,7 @@ static rpmRC addFile(FileList fl, const char * diskPath,
}
if (fl->cur.caps) {
- flp->caps = fl->cur.caps;
+ flp->caps = xstrdup(fl->cur.caps);
} else {
flp->caps = xstrdup("");
}
@@ -1555,15 +1609,15 @@ static rpmRC processMetadataFile(Package pkg, FileList fl,
apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
break;
}
- case RPMTAG_SECMANIFEST: {
+ case RPMTAG_SECMANIFEST: {
if ((xx = rpmioSlurp(fn, &pkt, &pktlen)) != 0 || pkt == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: Security manifest file read failed.\n"), fn);
- goto exit;
+ rpmlog(RPMLOG_ERR, _("%s: Security manifest file read failed.\n"), fn);
+ goto exit;
+ }
+ apkt = rpmBase64Encode(pkt, pktlen, -1);
+ rpmlog(RPMLOG_INFO, _("Aptk: %s\n"), apkt);
+ break;
}
- apkt = rpmBase64Encode(pkt, pktlen, -1);
- rpmlog(RPMLOG_INFO, _("Aptk: %s\n"), apkt);
- break;
- }
}
if (!apkt) {
@@ -1588,6 +1642,448 @@ exit:
return rc;
}
+/* add a file with possible virtual attributes to the file list */
+static void argvAddAttr(ARGV_t *filesp, rpmfileAttrs attrs, const char *path)
+{
+ char *line = NULL;
+
+ for (VFA_t *vfa = virtualAttrs; vfa->attribute != NULL; vfa++) {
+ if (vfa->flag & attrs)
+ line = rstrscat(&line, vfa->attribute, " ", NULL);
+ }
+ line = rstrscat(&line, path, NULL);
+ argvAdd(filesp, line);
+ free(line);
+}
+
+#if HAVE_LIBDW
+/* How build id links are generated. See macros.in for description. */
+#define BUILD_IDS_NONE 0
+#define BUILD_IDS_ALLDEBUG 1
+#define BUILD_IDS_SEPARATE 2
+#define BUILD_IDS_COMPAT 3
+
+static int addNewIDSymlink(ARGV_t *files,
+ char *targetpath, char *idlinkpath,
+ int isDbg, int *dups)
+{
+ const char *linkerr = _("failed symlink");
+ int rc = 0;
+ int nr = 0;
+ int exists = 0;
+ char *origpath, *linkpath;
+
+ if (isDbg)
+ rasprintf(&linkpath, "%s.debug", idlinkpath);
+ else
+ linkpath = idlinkpath;
+ 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++;
+ rasprintf(&linkpath, "%s.%d%s", idlinkpath, nr,
+ isDbg ? ".debug" : "");
+ }
+
+ if (!exists && symlink(targetpath, linkpath) < 0) {
+ rc = 1;
+ rpmlog(RPMLOG_ERR, "%s: %s -> %s: %m\n",
+ linkerr, linkpath, targetpath);
+ } else {
+ argvAddAttr(files, RPMFILE_ARTIFACT, linkpath);
+ }
+
+ 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
+ something like eu-elfcmp to see if they are really the same
+ ELF file or not. */
+ struct stat st1, st2;
+ if (stat (origpath, &st1) != 0) {
+ rpmlog(RPMLOG_WARNING, _("Duplicate build-id, stat %s: %m\n"),
+ origpath);
+ } else if (stat (linkpath, &st2) != 0) {
+ rpmlog(RPMLOG_WARNING, _("Duplicate build-id, stat %s: %m\n"),
+ linkpath);
+ } else if (!(S_ISREG(st1.st_mode) && S_ISREG(st2.st_mode)
+ && st1.st_nlink > 1 && st2.st_nlink == st1.st_nlink
+ && st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev)) {
+ char *rpath1 = realpath(origpath, NULL);
+ char *rpath2 = realpath(linkpath, NULL);
+ rpmlog(RPMLOG_WARNING, _("Duplicate build-ids %s and %s\n"),
+ rpath1, rpath2);
+ free(rpath1);
+ free(rpath2);
+ }
+ }
+
+ if (isDbg)
+ free(origpath);
+ if (nr > 0)
+ free(linkpath);
+ if (dups != NULL)
+ *dups = nr;
+
+ return rc;
+}
+
+static int generateBuildIDs(FileList fl, ARGV_t *files)
+{
+ int rc = 0;
+ int i;
+ FileListRec flp;
+ char **ids = NULL;
+ char **paths = NULL;
+ size_t nr_ids, allocated;
+ nr_ids = allocated = 0;
+
+ /* How are we supposed to create the build-id links? */
+ char *build_id_links_macro = rpmExpand("%{?_build_id_links}", NULL);
+ int build_id_links;
+ if (*build_id_links_macro == '\0') {
+ rpmlog(RPMLOG_WARNING,
+ _("_build_id_links macro not set, assuming 'compat'\n"));
+ build_id_links = BUILD_IDS_COMPAT;
+ } else if (strcmp(build_id_links_macro, "none") == 0) {
+ build_id_links = BUILD_IDS_NONE;
+ } else if (strcmp(build_id_links_macro, "alldebug") == 0) {
+ build_id_links = BUILD_IDS_ALLDEBUG;
+ } else if (strcmp(build_id_links_macro, "separate") == 0) {
+ build_id_links = BUILD_IDS_SEPARATE;
+ } else if (strcmp(build_id_links_macro, "compat") == 0) {
+ build_id_links = BUILD_IDS_COMPAT;
+ } else {
+ rc = 1;
+ rpmlog(RPMLOG_ERR,
+ _("_build_id_links macro set to unknown value '%s'\n"),
+ build_id_links_macro);
+ build_id_links = BUILD_IDS_NONE;
+ }
+ free(build_id_links_macro);
+
+ if (build_id_links == BUILD_IDS_NONE || rc != 0)
+ return rc;
+
+ /* Historically we have only checked build_ids when __debug_package
+ was defined. So don't terminate the build if __debug_package is
+ unset, even when _missing_build_ids_terminate_build is. */
+ int terminate = (rpmExpandNumeric("%{?_missing_build_ids_terminate_build}")
+ && rpmExpandNumeric("%{?__debug_package}"));
+
+ /* Collect and check all build-ids for ELF files in this package. */
+ int needMain = 0;
+ int needDbg = 0;
+ for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
+ struct stat sbuf;
+ if (lstat(flp->diskPath, &sbuf) == 0 && S_ISREG (sbuf.st_mode)) {
+ /* We determine whether this is a main or
+ debug ELF based on path. */
+ int isDbg = strncmp (flp->cpioPath,
+ DEBUG_LIB_PREFIX, strlen (DEBUG_LIB_PREFIX)) == 0;
+
+ /* For the main package files mimic what find-debuginfo.sh does.
+ Only check build-ids for executable files. Debug files are
+ always non-executable. */
+ if (!isDbg
+ && (sbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
+ continue;
+
+ int fd = open (flp->diskPath, O_RDONLY);
+ if (fd >= 0) {
+ /* Only real ELF files, that are ET_EXEC, ET_DYN or
+ kernel modules (ET_REL files with names ending in .ko)
+ should have build-ids. */
+ GElf_Ehdr ehdr;
+ Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+ if (elf != NULL && elf_kind(elf) == ELF_K_ELF
+ && gelf_getehdr(elf, &ehdr) != NULL
+ && (ehdr.e_type == ET_EXEC || ehdr.e_type == ET_DYN
+ || (ehdr.e_type == ET_REL
+ && rpmFileHasSuffix (flp->diskPath, ".ko")))) {
+ const void *build_id;
+ ssize_t len = dwelf_elf_gnu_build_id (elf, &build_id);
+ /* len == -1 means error. Zero means no
+ build-id. We want at least a length of 2 so we
+ have at least a xx/yy (hex) dir/file. But
+ reasonable build-ids are between 16 bytes (md5
+ is 128 bits) and 64 bytes (largest sha3 is 512
+ bits), common is 20 bytes (sha1 is 160 bits). */
+ if (len >= 16 && len <= 64) {
+ int addid = 0;
+ if (isDbg) {
+ needDbg = 1;
+ addid = 1;
+ }
+ else if (build_id_links != BUILD_IDS_ALLDEBUG) {
+ needMain = 1;
+ addid = 1;
+ }
+ if (addid) {
+ const unsigned char *p = build_id;
+ const unsigned char *end = p + len;
+ char *id_str;
+ if (allocated <= nr_ids) {
+ allocated += 16;
+ paths = xrealloc (paths,
+ allocated * sizeof(char *));
+ ids = xrealloc (ids,
+ allocated * sizeof(char *));
+ }
+
+ paths[nr_ids] = xstrdup(flp->cpioPath);
+ id_str = ids[nr_ids] = xmalloc(2 * len + 1);
+ while (p < end)
+ id_str += sprintf(id_str, "%02x",
+ (unsigned)*p++);
+ *id_str = '\0';
+ nr_ids++;
+ }
+ } else {
+ if (len < 0) {
+ rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
+ _("error reading build-id in %s: %s\n"),
+ flp->diskPath, elf_errmsg (-1));
+ } else if (len == 0) {
+ rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
+ _("Missing build-id in %s\n"),
+ flp->diskPath);
+ } else {
+ rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
+ (len < 16
+ ? _("build-id found in %s too small\n")
+ : _("build-id found in %s too large\n")),
+ flp->diskPath);
+ }
+ if (terminate)
+ rc = 1;
+ }
+ elf_end (elf);
+ }
+ close (fd);
+ }
+ }
+ }
+
+ /* Process and clean up all build-ids. */
+ if (nr_ids > 0) {
+ const char *errdir = _("failed to create directory");
+ char *mainiddir = NULL;
+ char *debugiddir = NULL;
+ if (rc == 0) {
+ char *attrstr;
+ /* Add .build-id directories to hold the subdirs/symlinks. */
+
+ mainiddir = rpmGetPath(fl->buildRoot, BUILD_ID_DIR, NULL);
+ debugiddir = rpmGetPath(fl->buildRoot, DEBUG_ID_DIR, NULL);
+
+ /* Make sure to reset all file flags to defaults. */
+ attrstr = mkattr();
+ argvAdd(files, attrstr);
+ free (attrstr);
+
+ /* Supported, but questionable. */
+ if (needMain && needDbg)
+ rpmlog(RPMLOG_WARNING,
+ _("Mixing main ELF and debug files in package"));
+
+ if (needMain) {
+ if ((rc = rpmioMkpath(mainiddir, 0755, -1, -1)) != 0) {
+ rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, mainiddir);
+ } else {
+ argvAddAttr(files, RPMFILE_DIR|RPMFILE_ARTIFACT, mainiddir);
+ }
+ }
+
+ if (rc == 0 && needDbg) {
+ if ((rc = rpmioMkpath(debugiddir, 0755, -1, -1)) != 0) {
+ rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, debugiddir);
+ } else {
+ argvAddAttr(files, RPMFILE_DIR|RPMFILE_ARTIFACT, debugiddir);
+ }
+ }
+ }
+
+ /* In case we need ALLDEBUG links we might need the vra as
+ tagged onto the .debug file name. */
+ char *vra = NULL;
+ if (rc == 0 && needDbg && build_id_links == BUILD_IDS_ALLDEBUG) {
+ int unique_debug_names =
+ rpmExpandNumeric("%{?_unique_debug_names}");
+ if (unique_debug_names == 1)
+ vra = rpmExpand("-%{VERSION}-%{RELEASE}.%{_arch}", NULL);
+ }
+
+ /* Now add a subdir and symlink for each buildid found. */
+ for (i = 0; i < nr_ids; i++) {
+ /* Don't add anything more when an error occurred. But do
+ cleanup. */
+ if (rc == 0) {
+ int isDbg = strncmp (paths[i], DEBUG_LIB_PREFIX,
+ strlen (DEBUG_LIB_PREFIX)) == 0;
+
+ char *buildidsubdir;
+ char subdir[4];
+ subdir[0] = '/';
+ subdir[1] = ids[i][0];
+ subdir[2] = ids[i][1];
+ subdir[3] = '\0';
+ if (isDbg)
+ buildidsubdir = rpmGetPath(debugiddir, subdir, NULL);
+ else
+ buildidsubdir = rpmGetPath(mainiddir, subdir, NULL);
+ /* We only need to create and add the subdir once. */
+ int addsubdir = access (buildidsubdir, F_OK) == -1;
+ if (addsubdir
+ && (rc = rpmioMkpath(buildidsubdir, 0755, -1, -1)) != 0) {
+ rpmlog(RPMLOG_ERR, "%s %s: %m\n", errdir, buildidsubdir);
+ } else {
+ if (addsubdir)
+ argvAddAttr(files, RPMFILE_DIR|RPMFILE_ARTIFACT, buildidsubdir);
+ if (rc == 0) {
+ char *linkpattern, *targetpattern;
+ char *linkpath, *targetpath;
+ int dups = 0;
+ if (isDbg) {
+ linkpattern = "%s/%s";
+ targetpattern = "../../../../..%s";
+ } else {
+ linkpattern = "%s/%s";
+ targetpattern = "../../../..%s";
+ }
+ rasprintf(&linkpath, linkpattern,
+ buildidsubdir, &ids[i][2]);
+ rasprintf(&targetpath, targetpattern, paths[i]);
+ rc = addNewIDSymlink(files, targetpath, linkpath,
+ isDbg, &dups);
+
+ /* We might want to have a link from the debug
+ build_ids dir to the main one. We create it
+ when we are creating compat links or doing
+ an old style alldebug build-ids package. In
+ the first case things are simple since we
+ just link to the main build-id symlink. The
+ second case is a bit tricky, since we
+ cannot be 100% sure the file names in the
+ main and debug package match. Currently
+ they do, but when creating parallel
+ installable debuginfo packages they might
+ not (in that case we might have to also
+ strip the nvr from the debug name).
+
+ In general either method is discouraged
+ since it might create dangling symlinks if
+ the package versions get out of sync. */
+ if (rc == 0 && isDbg
+ && build_id_links == BUILD_IDS_COMPAT) {
+ /* buildidsubdir already points to the
+ debug buildid. We just need to setup
+ 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);
+ 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(files, targetpath, linkpath,
+ 0, NULL);
+ }
+
+ if (rc == 0 && isDbg
+ && build_id_links == BUILD_IDS_ALLDEBUG) {
+ /* buildidsubdir already points to the
+ debug buildid. We do have to figure out
+ the main ELF file though (which is most
+ likely not in this package). Guess we
+ can find it by stripping the
+ /usr/lib/debug path and .debug
+ prefix. Which might not really be
+ correct if there was a more involved
+ transformation (for example for
+ parallel installable debuginfo
+ packages), but then we shouldn't be
+ using ALLDEBUG in the first place.
+ Also ignore things like .dwz multifiles
+ which don't end in ".debug". */
+ int pathlen = strlen(paths[i]);
+ int debuglen = strlen(".debug");
+ int prefixlen = strlen(DEBUG_LIB_DIR);
+ int vralen = vra == NULL ? 0 : strlen(vra);
+ if (pathlen > prefixlen + debuglen + vralen
+ && strcmp ((paths[i] + pathlen - debuglen),
+ ".debug") == 0) {
+ free(linkpath);
+ free(targetpath);
+ char *targetstr = xstrdup (paths[i]
+ + prefixlen);
+ int targetlen = pathlen - prefixlen;
+ int targetend = targetlen - debuglen - vralen;
+ targetstr[targetend] = '\0';
+ rasprintf(&linkpath, "%s/%s",
+ buildidsubdir, &ids[i][2]);
+ rasprintf(&targetpath, "../../../../..%s",
+ targetstr);
+ rc = addNewIDSymlink(files, targetpath,
+ linkpath, 0, &dups);
+ free(targetstr);
+ }
+ }
+ free(linkpath);
+ free(targetpath);
+ }
+ }
+ free(buildidsubdir);
+ }
+ free(paths[i]);
+ free(ids[i]);
+ }
+ free(mainiddir);
+ free(debugiddir);
+ free(vra);
+ free(paths);
+ free(ids);
+ }
+ return rc;
+}
+#endif
+
/**
* Add a file to a binary package.
* @param pkg
@@ -1647,16 +2143,13 @@ static rpmRC processBinaryFile(Package pkg, FileList fl, const char * fileName)
}
argvFree(argv);
} else {
- int lvl = RPMLOG_WARNING;
const char *msg = (fl->cur.isDir) ?
- _("Directory not found by glob: %s\n") :
- _("File not found by glob: %s\n");
- if (!(fl->cur.attrFlags & RPMFILE_EXCLUDE)) {
- lvl = RPMLOG_ERR;
- rc = RPMRC_FAIL;
- }
- rpmlog(lvl, msg, diskPath);
- goto exit;
+ _("Directory not found by glob: %s. "
+ "Trying without globbing.\n") :
+ _("File not found by glob: %s. "
+ "Trying without globbing.\n");
+ rpmlog(RPMLOG_DEBUG, msg, diskPath);
+ rc = addFile(fl, diskPath, NULL);
}
} else {
rc = addFile(fl, diskPath, NULL);
@@ -1676,6 +2169,8 @@ static rpmRC readFilesManifest(rpmSpec spec, Package pkg, const char *path)
char *fn, buf[BUFSIZ];
FILE *fd = NULL;
rpmRC rc = RPMRC_FAIL;
+ unsigned int nlines = 0;
+ char *expanded;
if (*path == '/') {
fn = rpmGetPath(path, NULL);
@@ -1690,13 +2185,28 @@ static rpmRC readFilesManifest(rpmSpec spec, Package pkg, const char *path)
goto exit;
}
+ /* XXX unmask %license while parsing files manifest*/
+ rpmPushMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC);
+
while (fgets(buf, sizeof(buf), fd)) {
- handleComments(buf);
- if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
+ if (handleComments(buf))
+ continue;
+ if (rpmExpandMacros(spec->macros, buf, &expanded, 0) < 0) {
rpmlog(RPMLOG_ERR, _("line: %s\n"), buf);
goto exit;
}
- argvAdd(&(pkg->fileList), buf);
+ argvAdd(&(pkg->fileList), expanded);
+ free(expanded);
+ nlines++;
+ }
+
+ if (nlines == 0) {
+ int terminate =
+ rpmExpandNumeric("%{?_empty_manifest_terminate_build}");
+ rpmlog(terminate ? RPMLOG_ERR : RPMLOG_WARNING,
+ _("Empty %%files file %s\n"), fn);
+ if (terminate)
+ goto exit;
}
if (ferror(fd))
@@ -1705,6 +2215,7 @@ static rpmRC readFilesManifest(rpmSpec spec, Package pkg, const char *path)
rc = RPMRC_OK;
exit:
+ rpmPopMacro(NULL, "license");
if (fd) fclose(fd);
free(fn);
return rc;
@@ -1737,24 +2248,47 @@ static char * getSpecialDocDir(Header h, rpmFlags sdtype)
return res;
}
-static specialDir specialDirNew(Header h, rpmFlags sdtype,
- AttrRec ar, AttrRec def_ar)
+static specialDir specialDirNew(Header h, rpmFlags sdtype)
{
specialDir sd = xcalloc(1, sizeof(*sd));
- dupAttrRec(ar, &(sd->ar));
- dupAttrRec(def_ar, &(sd->def_ar));
+
+ sd->entriesCount = 0;
+ sd->entriesAlloced = 10;
+ sd->entries = xcalloc(sd->entriesAlloced, sizeof(sd->entries[0]));
+
sd->dirname = getSpecialDocDir(h, sdtype);
sd->sdtype = sdtype;
return sd;
}
+static void addSpecialFile(specialDir sd, const char *path, FileEntry cur,
+ FileEntry def)
+{
+ argvAdd(&sd->files, path);
+
+ if (sd->entriesCount >= sd->entriesAlloced) {
+ sd->entriesAlloced <<= 1;
+ sd->entries = xrealloc(sd->entries, sd->entriesAlloced *
+ sizeof(sd->entries[0]));
+ }
+
+ copyFileEntry(cur, &sd->entries[sd->entriesCount].curEntry);
+ copyFileEntry(def, &sd->entries[sd->entriesCount].defEntry);
+ sd->entriesCount++;
+}
+
static specialDir specialDirFree(specialDir sd)
{
+ int i = 0;
+
if (sd) {
argvFree(sd->files);
- freeAttrRec(&(sd->ar));
- freeAttrRec(&(sd->def_ar));
free(sd->dirname);
+ for (i = 0; i < sd->entriesCount; i++) {
+ FileEntryFree(&sd->entries[i].curEntry);
+ FileEntryFree(&sd->entries[i].defEntry);
+ }
+ free(sd->entries);
free(sd);
}
return NULL;
@@ -1767,10 +2301,13 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
const char *sdname = (sd->sdtype == RPMFILE_DOC) ? "%doc" : "%license";
char *mkdocdir = rpmExpand("%{__mkdir_p} $", sdenv, NULL);
StringBuf docScript = newStringBuf();
+ char *basepath, **files;
+ int fi;
appendStringBuf(docScript, sdenv);
appendStringBuf(docScript, "=$RPM_BUILD_ROOT");
appendLineStringBuf(docScript, sd->dirname);
+ appendLineStringBuf(docScript, "export LC_ALL=C");
appendStringBuf(docScript, "export ");
appendLineStringBuf(docScript, sdenv);
appendLineStringBuf(docScript, mkdocdir);
@@ -1781,7 +2318,8 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
appendStringBuf(docScript, "cp -pr ");
appendStringBuf(docScript, efn);
appendStringBuf(docScript, " $");
- appendLineStringBuf(docScript, sdenv);
+ appendStringBuf(docScript, sdenv);
+ appendLineStringBuf(docScript, " ||:");
free(efn);
}
@@ -1793,52 +2331,77 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
fl->processingFailed = 1;
}
- /* Reset for %doc */
- FileEntryFree(&fl->cur);
-
- fl->cur.attrFlags |= sd->sdtype;
- fl->cur.verifyFlags = fl->def.verifyFlags;
- dupAttrRec(&(sd->ar), &(fl->cur.ar));
- dupAttrRec(&(sd->def_ar), &(fl->def.ar));
+ basepath = rpmGenPath(spec->rootDir, "%{_builddir}", spec->buildSubdir);
+ files = sd->files;
+ fi = 0;
+ while (*files != NULL) {
+ char *origfile = rpmGenPath(basepath, *files, NULL);
+ char *eorigfile = rpmEscapeSpaces(origfile);
+ ARGV_t globFiles;
+ int globFilesCount, i;
+ char *newfile;
+
+ FileEntryFree(&fl->cur);
+ FileEntryFree(&fl->def);
+ copyFileEntry(&sd->entries[fi].curEntry, &fl->cur);
+ copyFileEntry(&sd->entries[fi].defEntry, &fl->def);
+ fi++;
+
+ if (rpmGlob(eorigfile, &globFilesCount, &globFiles) == 0) {
+ for (i = 0; i < globFilesCount; i++) {
+ rasprintf(&newfile, "%s/%s", sd->dirname, basename(globFiles[i]));
+ processBinaryFile(pkg, fl, newfile);
+ free(newfile);
+ }
+ argvFree(globFiles);
+ } else {
+ rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), eorigfile);
+ fl->processingFailed = 1;
+ }
+ free(eorigfile);
+ free(origfile);
+ files++;
+ }
+ free(basepath);
+ FileEntryFree(&fl->cur);
+ FileEntryFree(&fl->def);
+ copyFileEntry(&sd->entries[0].defEntry, &fl->def);
+ fl->cur.isDir = 1;
(void) processBinaryFile(pkg, fl, sd->dirname);
freeStringBuf(docScript);
free(mkdocdir);
}
-
-static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
- Package pkg, int installSpecialDoc, int test)
+
+/* Resets the default settings for files in the package list.
+ Used in processPackageFiles whenever a new set of files is added. */
+static void resetPackageFilesDefaults (struct FileList_s *fl,
+ rpmBuildPkgFlags pkgFlags)
{
- struct FileList_s fl;
- ARGV_t fileNames = NULL;
- specialDir specialDoc = NULL;
- specialDir specialLic = NULL;
+ struct AttrRec_s root_ar = { 0, 0, 0, 0, 0, 0 };
- pkg->cpioList = NULL;
+ root_ar.ar_user = rpmstrPoolId(fl->pool, UID_0_USER, 1);
+ root_ar.ar_group = rpmstrPoolId(fl->pool, GID_0_GROUP, 1);
+ dupAttrRec(&root_ar, &fl->def.ar); /* XXX assume %defattr(-,root,root) */
- for (ARGV_const_t fp = pkg->fileFile; fp && *fp != NULL; fp++) {
- if (readFilesManifest(spec, pkg, *fp))
- return RPMRC_FAIL;
- }
- /* Init the file list structure */
- memset(&fl, 0, sizeof(fl));
+ fl->def.verifyFlags = RPMVERIFY_ALL;
- /* XXX spec->buildRoot == NULL, then xstrdup("") is returned */
- fl.buildRoot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
-
- dupAttrRec(&root_ar, &fl.def.ar); /* XXX assume %defattr(-,root,root) */
- fl.def.verifyFlags = RPMVERIFY_ALL;
-
- fl.pkgFlags = pkgFlags;
+ fl->pkgFlags = pkgFlags;
+}
- { char *docs = rpmGetPath("%{?__docdir_path}", NULL);
- argvSplit(&fl.docDirs, docs, ":");
- free(docs);
- }
-
- for (ARGV_const_t fp = pkg->fileList; *fp != NULL; fp++) {
+/* Adds the given fileList to the package. If fromSpecFileList is not zero
+ then the specialDirs are also filled in and the files are sanitized
+ through processBinaryFile(). Otherwise no special files are processed
+ and the files are added directly through addFile(). */
+static void addPackageFileList (struct FileList_s *fl, Package pkg,
+ ARGV_t *fileList,
+ specialDir *specialDoc, specialDir *specialLic,
+ int fromSpecFileList)
+{
+ ARGV_t fileNames = NULL;
+ for (ARGV_const_t fp = *fileList; *fp != NULL; fp++) {
char buf[strlen(*fp) + 1];
const char *s = *fp;
SKIPSPACE(s);
@@ -1848,92 +2411,169 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
rstrlcpy(buf, s, sizeof(buf));
/* Reset for a new line in %files */
- FileEntryFree(&fl.cur);
+ FileEntryFree(&fl->cur);
/* turn explicit flags into %def'd ones (gosh this is hacky...) */
- fl.cur.specdFlags = ((unsigned)fl.def.specdFlags) >> 8;
- fl.cur.verifyFlags = fl.def.verifyFlags;
-
- if (parseForVerify(buf, 0, &fl.cur) ||
- parseForVerify(buf, 1, &fl.def) ||
- parseForAttr(buf, 0, &fl.cur) ||
- parseForAttr(buf, 1, &fl.def) ||
- parseForDev(buf, &fl.cur) ||
- parseForConfig(buf, &fl.cur) ||
- parseForLang(buf, &fl.cur) ||
- parseForCaps(buf, &fl.cur) ||
- parseForSimple(buf, &fl.cur, &fileNames))
+ fl->cur.specdFlags = ((unsigned)fl->def.specdFlags) >> 8;
+ fl->cur.verifyFlags = fl->def.verifyFlags;
+
+ if (parseForVerify(buf, 0, &fl->cur) ||
+ parseForVerify(buf, 1, &fl->def) ||
+ parseForAttr(fl->pool, buf, 0, &fl->cur) ||
+ parseForAttr(fl->pool, buf, 1, &fl->def) ||
+ parseForDev(buf, &fl->cur) ||
+ parseForConfig(buf, &fl->cur) ||
+ parseForLang(buf, &fl->cur) ||
+ parseForCaps(buf, &fl->cur) ||
+ parseForSimple(buf, &fl->cur, &fileNames))
{
- fl.processingFailed = 1;
+ fl->processingFailed = 1;
continue;
}
for (ARGV_const_t fn = fileNames; fn && *fn; fn++) {
- if (fl.cur.attrFlags & RPMFILE_SPECIALDIR) {
- rpmFlags oattrs = (fl.cur.attrFlags & ~RPMFILE_SPECIALDIR);
+
+ /* For file lists that don't come from a spec file list
+ processing is easy. There are no special files and the
+ file names don't need to be adjusted. */
+ if (!fromSpecFileList) {
+ if (fl->cur.attrFlags & RPMFILE_SPECIALDIR
+ || fl->cur.attrFlags & RPMFILE_DOCDIR
+ || fl->cur.attrFlags & RPMFILE_PUBKEY) {
+ rpmlog(RPMLOG_ERR,
+ _("Special file in generated file list: %s\n"),
+ *fn);
+ fl->processingFailed = 1;
+ continue;
+ }
+ if (fl->cur.attrFlags & RPMFILE_DIR)
+ fl->cur.isDir = 1;
+ addFile(fl, *fn, NULL);
+ continue;
+ }
+
+ /* File list does come from the spec, try to detect special
+ files and adjust the actual file names. */
+ if (fl->cur.attrFlags & RPMFILE_SPECIALDIR) {
+ rpmFlags oattrs = (fl->cur.attrFlags & ~RPMFILE_SPECIALDIR);
specialDir *sdp = NULL;
if (oattrs == RPMFILE_DOC) {
- sdp = &specialDoc;
+ sdp = specialDoc;
} else if (oattrs == RPMFILE_LICENSE) {
- sdp = &specialLic;
+ sdp = specialLic;
}
if (sdp == NULL || **fn == '/') {
rpmlog(RPMLOG_ERR,
_("Can't mix special %s with other forms: %s\n"),
(oattrs & RPMFILE_DOC) ? "%doc" : "%license", *fn);
- fl.processingFailed = 1;
+ fl->processingFailed = 1;
continue;
}
/* save attributes on first special doc/license for later use */
if (*sdp == NULL) {
- *sdp = specialDirNew(pkg->header, oattrs,
- &fl.cur.ar, &fl.def.ar);
+ *sdp = specialDirNew(pkg->header, oattrs);
}
- argvAdd(&(*sdp)->files, *fn);
+ addSpecialFile(*sdp, *fn, &fl->cur, &fl->def);
continue;
}
/* this is now an artificial limitation */
if (fn != fileNames) {
rpmlog(RPMLOG_ERR, _("More than one file on a line: %s\n"),*fn);
- fl.processingFailed = 1;
+ fl->processingFailed = 1;
continue;
}
- if (fl.cur.attrFlags & RPMFILE_DOCDIR) {
- argvAdd(&(fl.docDirs), *fn);
- } else if (fl.cur.attrFlags & RPMFILE_PUBKEY) {
- (void) processMetadataFile(pkg, &fl, *fn, RPMTAG_PUBKEYS);
- } else if (fl.cur.attrFlags & RPMFILE_SECMANIFEST) {
- (void) processMetadataFile(pkg, &fl, *fn, RPMTAG_SECMANIFEST);
- } else {
- if (fl.cur.attrFlags & RPMFILE_DIR)
- fl.cur.isDir = 1;
- (void) processBinaryFile(pkg, &fl, *fn);
+ if (fl->cur.attrFlags & RPMFILE_DOCDIR) {
+ argvAdd(&(fl->docDirs), *fn);
+ } else if (fl->cur.attrFlags & RPMFILE_PUBKEY) {
+ (void) processMetadataFile(pkg, fl, *fn, RPMTAG_PUBKEYS);
+ } else if (fl->cur.attrFlags & RPMFILE_SECMANIFEST) {
+ (void) processMetadataFile(pkg, fl, *fn, RPMTAG_SECMANIFEST);
+ }else {
+ if (fl->cur.attrFlags & RPMFILE_DIR)
+ fl->cur.isDir = 1;
+ (void) processBinaryFile(pkg, fl, *fn);
}
}
- if (fl.cur.caps)
- fl.haveCaps = 1;
+ if (fl->cur.caps)
+ fl->haveCaps = 1;
}
+ argvFree(fileNames);
+}
+
+static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ Package pkg, int didInstall, int test)
+{
+ struct FileList_s fl;
+ specialDir specialDoc = NULL;
+ specialDir specialLic = NULL;
+
+ pkg->cpioList = NULL;
+
+ for (ARGV_const_t fp = pkg->fileFile; fp && *fp != NULL; fp++) {
+ if (readFilesManifest(spec, pkg, *fp))
+ return RPMRC_FAIL;
+ }
+ /* Init the file list structure */
+ memset(&fl, 0, sizeof(fl));
+
+ fl.pool = rpmstrPoolLink(spec->pool);
+ /* XXX spec->buildRoot == NULL, then xstrdup("") is returned */
+ fl.buildRoot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
+ fl.buildRootLen = strlen(fl.buildRoot);
+
+ resetPackageFilesDefaults (&fl, pkgFlags);
+
+ { char *docs = rpmGetPath("%{?__docdir_path}", NULL);
+ argvSplit(&fl.docDirs, docs, ":");
+ free(docs);
+ }
+
+ addPackageFileList (&fl, pkg, &pkg->fileList,
+ &specialDoc, &specialLic, 1);
/* Now process special docs and licenses if present */
if (specialDoc)
- processSpecialDir(spec, pkg, &fl, specialDoc, installSpecialDoc, test);
+ processSpecialDir(spec, pkg, &fl, specialDoc, didInstall, test);
if (specialLic)
- processSpecialDir(spec, pkg, &fl, specialLic, installSpecialDoc, test);
+ processSpecialDir(spec, pkg, &fl, specialLic, didInstall, test);
if (fl.processingFailed)
goto exit;
+#if HAVE_LIBDW
+ /* Check build-ids and add build-ids links for files to package list. */
+ const char *arch = headerGetString(pkg->header, RPMTAG_ARCH);
+ if (!rstreq(arch, "noarch")) {
+ /* Go through the current package list and generate a files list. */
+ ARGV_t idFiles = NULL;
+ if (generateBuildIDs (&fl, &idFiles) != 0) {
+ rpmlog(RPMLOG_ERR, _("Generating build-id links failed\n"));
+ fl.processingFailed = 1;
+ argvFree(idFiles);
+ goto exit;
+ }
+
+ if (idFiles != NULL) {
+ resetPackageFilesDefaults (&fl, pkgFlags);
+ addPackageFileList (&fl, pkg, &idFiles, NULL, NULL, 0);
+ }
+ argvFree(idFiles);
+
+ if (fl.processingFailed)
+ goto exit;
+ }
+#endif
+
/* Verify that file attributes scope over hardlinks correctly. */
if (checkHardLinks(&fl.files))
- (void) rpmlibNeedsFeature(pkg->header,
- "PartialHardlinkSets", "4.0.4-1");
+ (void) rpmlibNeedsFeature(pkg, "PartialHardlinkSets", "4.0.4-1");
- genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
+ genCpioListAndHeader(&fl, pkg, 0);
exit:
FileListFree(&fl);
@@ -1958,6 +2598,7 @@ rpmRC processSourceFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags)
struct FileList_s fl;
ARGV_t files = NULL;
Package pkg;
+ Package sourcePkg = spec->sourcePackage;
static char *_srcdefattr;
static int oneshot;
@@ -1988,13 +2629,14 @@ rpmRC processSourceFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags)
}
}
- spec->sourceCpioList = NULL;
+ sourcePkg->cpioList = NULL;
/* Init the file list structure */
memset(&fl, 0, sizeof(fl));
+ fl.pool = rpmstrPoolLink(spec->pool);
if (_srcdefattr) {
char *a = rstrscat(NULL, "%defattr ", _srcdefattr, NULL);
- parseForAttr(a, 1, &fl.def);
+ parseForAttr(fl.pool, a, 1, &fl.def);
free(a);
}
fl.files.alloced = spec->numSources + 1;
@@ -2039,31 +2681,39 @@ rpmRC processSourceFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags)
flp->fl_mode &= S_IFMT;
flp->fl_mode |= fl.def.ar.ar_fmode;
}
+
if (fl.def.ar.ar_user) {
- flp->uname = rpmugStashStr(fl.def.ar.ar_user);
+ flp->uname = fl.def.ar.ar_user;
} else {
- flp->uname = rpmugStashStr(rpmugUname(flp->fl_uid));
+ flp->uname = rpmstrPoolId(fl.pool, rpmugUname(flp->fl_uid), 1);
}
+ if (! flp->uname) {
+ flp->uname = rpmstrPoolId(fl.pool, rpmugUname(getuid()), 1);
+ }
+ if (! flp->uname) {
+ flp->uname = rpmstrPoolId(fl.pool, UID_0_USER, 1);
+ }
+
if (fl.def.ar.ar_group) {
- flp->gname = rpmugStashStr(fl.def.ar.ar_group);
+ flp->gname = fl.def.ar.ar_group;
} else {
- flp->gname = rpmugStashStr(rpmugGname(flp->fl_gid));
+ flp->gname = rpmstrPoolId(fl.pool, rpmugGname(flp->fl_gid), 1);
}
- flp->langs = xstrdup("");
-
- if (! (flp->uname && flp->gname)) {
- rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), diskPath);
- fl.processingFailed = 1;
+ if (! flp->gname) {
+ flp->gname = rpmstrPoolId(fl.pool, rpmugGname(getgid()), 1);
+ }
+ if (! flp->gname) {
+ flp->gname = rpmstrPoolId(fl.pool, GID_0_GROUP, 1);
}
+ flp->langs = xstrdup("");
fl.files.used++;
}
argvFree(files);
if (! fl.processingFailed) {
- if (spec->sourceHeader != NULL) {
- genCpioListAndHeader(&fl, &spec->sourceCpioList,
- spec->sourceHeader, 1);
+ if (sourcePkg->header != NULL) {
+ genCpioListAndHeader(&fl, sourcePkg, 1);
}
}
@@ -2073,6 +2723,7 @@ rpmRC processSourceFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags)
/**
* Check packaged file list against what's in the build root.
+ * @param buildRoot path of build root
* @param fileList packaged file list
* @return -1 if skipped, 0 on OK, 1 on error
*/
@@ -2109,245 +2760,370 @@ exit:
return rc;
}
-#if HAVE_GELF_H && HAVE_LIBELF
-/* Query the build-id from the ELF file NAME and store it in the newly
- allocated *build_id array of size *build_id_size. Returns -1 on
- error. */
+static rpmTag copyTagsFromMainDebug[] = {
+ RPMTAG_ARCH,
+ RPMTAG_SUMMARY,
+ RPMTAG_DESCRIPTION,
+ RPMTAG_GROUP,
+ /* see addTargets */
+ RPMTAG_OS,
+ RPMTAG_PLATFORM,
+ RPMTAG_OPTFLAGS,
+};
-int
-getELFBuildId (const char *name,
- unsigned char **id, size_t *id_size)
+/* this is a hack: patch the summary and the description to include
+ * the correct package name */
+static void patchDebugPackageString(Package dbg, rpmTag tag, Package pkg, Package mainpkg)
{
- int fd, i;
- Elf *elf;
- GElf_Ehdr ehdr;
- Elf_Data *build_id = NULL;
- size_t build_id_offset = 0, build_id_size = 0;
-
- /* Now query the build-id of the file and add the
- corresponding links in the .build-id tree.
- The following code is based on tools/debugedit.c. */
- fd = open (name, O_RDONLY);
- if (fd < 0)
- return -1;
- elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
- if (elf == NULL)
- {
- fprintf (stderr, "cannot open ELF file: %s",
- elf_errmsg (-1));
- close (fd);
- return -1;
- }
- if (elf_kind (elf) != ELF_K_ELF
- || gelf_getehdr (elf, &ehdr) == NULL
- || (ehdr.e_type != ET_DYN
- && ehdr.e_type != ET_EXEC
- && ehdr.e_type != ET_REL))
- {
- elf_end (elf);
- close (fd);
- return -1;
- }
- for (i = 0; i < ehdr.e_shnum; ++i)
- {
- Elf_Scn *s = elf_getscn (elf, i);
- GElf_Shdr shdr;
- Elf_Data *data;
- Elf32_Nhdr nh;
- Elf_Data dst =
- {
- .d_version = EV_CURRENT, .d_type = ELF_T_NHDR,
- .d_buf = &nh, .d_size = sizeof nh
- };
- Elf_Data src = dst;
-
- gelf_getshdr (s, &shdr);
- if (shdr.sh_type != SHT_NOTE
- || !(shdr.sh_flags & SHF_ALLOC))
- continue;
-
- /* Look for a build-ID note here. */
- data = elf_rawdata (s, NULL);
- src.d_buf = data->d_buf;
- assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
- while (data->d_buf + data->d_size - src.d_buf > (int) sizeof nh
- && elf32_xlatetom (&dst, &src, ehdr.e_ident[EI_DATA]))
- {
- Elf32_Word len = sizeof nh + nh.n_namesz;
- len = (len + 3) & ~3;
+ const char *oldname, *newname, *old;
+ char *oldsubst = NULL, *newsubst = NULL, *p;
+ oldname = headerGetString(mainpkg->header, RPMTAG_NAME);
+ newname = headerGetString(pkg->header, RPMTAG_NAME);
+ rasprintf(&oldsubst, "package %s", oldname);
+ rasprintf(&newsubst, "package %s", newname);
+ old = headerGetString(dbg->header, tag);
+ p = old ? strstr(old, oldsubst) : NULL;
+ if (p) {
+ char *new = NULL;
+ rasprintf(&new, "%.*s%s%s", (int)(p - old), old, newsubst, p + strlen(oldsubst));
+ headerDel(dbg->header, tag);
+ headerPutString(dbg->header, tag, new);
+ _free(new);
+ }
+ _free(oldsubst);
+ _free(newsubst);
+}
- if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3
- && !memcmp (src.d_buf + sizeof nh, "GNU", sizeof "GNU"))
- {
- build_id = data;
- build_id_offset = src.d_buf + len - data->d_buf;
- build_id_size = nh.n_descsz;
- break;
- }
+/* Early prototype for use in filterDebuginfoPackage. */
+static void addPackageDeps(Package from, Package to, enum rpmTag_e tag);
- len += nh.n_descsz;
- len = (len + 3) & ~3;
- src.d_buf += len;
- }
+/* create a new debuginfo subpackage for package pkg from the
+ * main debuginfo package */
+static Package cloneDebuginfoPackage(rpmSpec spec, Package pkg, Package maindbg)
+{
+ const char *name = headerGetString(pkg->header, RPMTAG_NAME);
+ char *dbgname = NULL;
+ Package dbg;
+
+ rasprintf(&dbgname, "%s-%s", name, "debuginfo");
+ dbg = newPackage(dbgname, spec->pool, &spec->packages);
+ headerPutString(dbg->header, RPMTAG_NAME, dbgname);
+ copyInheritedTags(dbg->header, pkg->header);
+ headerDel(dbg->header, RPMTAG_GROUP);
+ headerCopyTags(maindbg->header, dbg->header, copyTagsFromMainDebug);
+ dbg->autoReq = maindbg->autoReq;
+ dbg->autoProv = maindbg->autoProv;
+
+ /* patch summary and description strings */
+ patchDebugPackageString(dbg, RPMTAG_SUMMARY, pkg, spec->packages);
+ patchDebugPackageString(dbg, RPMTAG_DESCRIPTION, pkg, spec->packages);
+
+ /* Add self-provides (normally done by addTargets) */
+ addPackageProvides(dbg);
+ dbg->ds = rpmdsThis(dbg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
+
+ _free(dbgname);
+ return dbg;
+}
- if (build_id != NULL)
- break;
- }
+/* collect the debug files for package pkg and put them into
+ * a (possibly new) debuginfo subpackage */
+static void filterDebuginfoPackage(rpmSpec spec, Package pkg,
+ Package maindbg, Package dbgsrc,
+ char *buildroot, char *uniquearch)
+{
+ rpmfi fi;
+ ARGV_t files = NULL;
+ ARGV_t dirs = NULL;
+ int lastdiridx = -1, dirsadded;
+ char *path = NULL, *p, *pmin;
+ size_t buildrootlen = strlen(buildroot);
- if (build_id == NULL)
- return -1;
+ /* ignore noarch subpackages */
+ if (rstreq(headerGetString(pkg->header, RPMTAG_ARCH), "noarch"))
+ return;
- *id = malloc (build_id_size);
- *id_size = build_id_size;
- memcpy (*id, build_id->d_buf + build_id_offset, build_id_size);
+ if (!uniquearch)
+ uniquearch = "";
+
+ fi = rpmfilesIter(pkg->cpioList, RPMFI_ITER_FWD);
+ /* Check if the current package has files with debug info
+ and add them to the file list */
+ fi = rpmfiInit(fi, 0);
+ while (rpmfiNext(fi) >= 0) {
+ const char *name = rpmfiFN(fi);
+ int namel = strlen(name);
+
+ /* strip trailing .debug like in find-debuginfo.sh */
+ if (namel > 6 && !strcmp(name + namel - 6, ".debug"))
+ namel -= 6;
+
+ /* fileRenameMap doesn't necessarily have to be initialized */
+ if (pkg->fileRenameMap) {
+ const char **names = NULL;
+ int namec = 0;
+ fileRenameHashGetEntry(pkg->fileRenameMap, name, &names, &namec, NULL);
+ if (namec) {
+ if (namec > 1)
+ rpmlog(RPMLOG_WARNING, _("%s was mapped to multiple filenames"), name);
+ name = *names;
+ namel = strlen(name);
+ }
+ }
+
+ /* generate path */
+ rasprintf(&path, "%s%s%.*s%s.debug", buildroot, DEBUG_LIB_DIR, namel, name, uniquearch);
+
+ /* If that file exists we have debug information for it */
+ if (access(path, F_OK) == 0) {
+ /* Append the file list preamble */
+ if (!files) {
+ char *attr = mkattr();
+ argvAdd(&files, attr);
+ argvAddAttr(&files, RPMFILE_DIR, DEBUG_LIB_DIR);
+ free(attr);
+ }
- elf_end (elf);
- close (fd);
+ /* Add the files main debug-info file */
+ argvAdd(&files, path + buildrootlen);
+
+ /* Add the dir(s) */
+ dirsadded = 0;
+ pmin = path + buildrootlen + strlen(DEBUG_LIB_DIR);
+ while ((p = strrchr(path + buildrootlen, '/')) != NULL && p > pmin) {
+ *p = 0;
+ if (lastdiridx >= 0 && !strcmp(dirs[lastdiridx], path + buildrootlen))
+ break; /* already added this one */
+ argvAdd(&dirs, path + buildrootlen);
+ dirsadded++;
+ }
+ if (dirsadded)
+ lastdiridx = argvCount(dirs) - dirsadded; /* remember longest dir */
+ }
+ path = _free(path);
+ }
+ rpmfiFree(fi);
+ /* Exclude debug files for files which were excluded in respective non-debug package */
+ for (ARGV_const_t excl = pkg->fileExcludeList; excl && *excl; excl++) {
+ const char *name = *excl;
+
+ /* generate path */
+ rasprintf(&path, "%s%s%s%s.debug", buildroot, DEBUG_LIB_DIR, name, uniquearch);
+ /* Exclude only debuginfo files which actually exist */
+ if (access(path, F_OK) == 0) {
+ char *line = NULL;
+ rasprintf(&line, "%%exclude %s", path + buildrootlen);
+ argvAdd(&files, line);
+ _free(line);
+ }
+ path = _free(path);
+ }
- return 0;
-}
+ /* add collected directories to file list */
+ if (dirs) {
+ int i;
+ argvSort(dirs, NULL);
+ for (i = 0; dirs[i]; i++) {
+ if (!i || strcmp(dirs[i], dirs[i - 1]) != 0)
+ argvAddAttr(&files, RPMFILE_DIR, dirs[i]);
+ }
+ dirs = argvFree(dirs);
+ }
+ if (files) {
+ /* Add security manifest to set right SMACK labels */
+ argvAdd(&files, "%manifest %{name}-debuginfo.manifest");
-static rpmTag copyTagsForDebug[] = {
- RPMTAG_EPOCH,
- RPMTAG_VERSION,
- RPMTAG_RELEASE,
- RPMTAG_LICENSE,
- RPMTAG_PACKAGER,
- RPMTAG_DISTRIBUTION,
- RPMTAG_DISTURL,
- RPMTAG_VENDOR,
- RPMTAG_ICON,
- RPMTAG_URL,
- RPMTAG_CHANGELOGTIME,
- RPMTAG_CHANGELOGNAME,
- RPMTAG_CHANGELOGTEXT,
- RPMTAG_PREFIXES,
- RPMTAG_RHNPLATFORM,
- RPMTAG_OS,
- RPMTAG_DISTTAG,
- RPMTAG_CVSID,
- RPMTAG_ARCH,
- 0
-};
+ /* we have collected some files. Now put them in a debuginfo
+ * package. If this is not the main package, clone the main
+ * debuginfo package */
+ if (pkg == spec->packages) {
+ maindbg->fileList = files;
+ /*free maindb_fileList_bakup and set to NULL*/
+ maindb_fileList_bakup = argvFree(maindb_fileList_bakup);
+ }
+ else {
+ Package dbg = cloneDebuginfoPackage(spec, pkg, maindbg);
+ dbg->fileList = files;
+ /* Recommend the debugsource package (or the main debuginfo). */
+ addPackageDeps(dbg, dbgsrc ? dbgsrc : maindbg,
+ RPMTAG_RECOMMENDNAME);
+ }
+ } else {
+ /*To allow generate debuginfo package which is written in spec file, even there is no .debug files*/
+ if (pkg == spec->packages && headerGetString(maindbg->header,RPMTAG_MULTIFILELIST)) {
+ rpmlog(RPMLOG_WARNING, "user rewrite %%file debuginfo to pack something\n");
+ maindbg->fileList = maindb_fileList_bakup;
+ maindb_fileList_bakup = NULL;
+ headerDel(maindbg->header,RPMTAG_MULTIFILELIST);
+ }
+ }
+}
-static void addDebuginfoPackage(rpmSpec spec, Package pkg, char *buildroot)
+/* add the debug dwz files to package pkg.
+ * return 1 if something was added, 0 otherwise. */
+static int addDebugDwz(Package pkg, char *buildroot)
{
- const char *a;
-
- elf_version(EV_CURRENT);
- a = headerGetString(pkg->header, RPMTAG_ARCH);
- if (strcmp(a, "noarch") != 0 && strcmp(a, "src") != 0 && strcmp(a, "nosrc") != 0)
- {
- Package dbg;
- rpmfi fi = pkg->cpioList;
- char tmp[1024];
- const char *name;
- ARGV_t files = NULL;
- int seen_build_id = 0;
-
- /* Check if the current package has files with debug info
- and record them. */
- fi = rpmfiInit (fi, 0);
- while (rpmfiNext (fi) >= 0)
- {
- const char *base;
- int i;
- unsigned char *build_id;
- size_t build_id_size = 0;
- struct stat sbuf;
-
- name = rpmfiFN (fi);
- /* Skip leading buildroot. */
- base = name + strlen (buildroot);
- /* Pre-pend %buildroot/usr/lib/debug and append .debug. */
- snprintf (tmp, 1024, "%s/usr/lib/debug%s.debug",
- buildroot, base);
- /* If that file exists we have debug information for it. */
- if (access (tmp, F_OK) != 0)
- continue;
+ int ret = 0;
+ char *path = NULL;
+ struct stat sbuf;
+
+ rasprintf(&path, "%s%s", buildroot, DEBUG_DWZ_DIR);
+ if (lstat(path, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)) {
+ if (!pkg->fileList) {
+ char *attr = mkattr();
+ argvAdd(&pkg->fileList, attr);
+ argvAddAttr(&pkg->fileList, RPMFILE_DIR|RPMFILE_ARTIFACT, DEBUG_LIB_DIR);
+ free(attr);
+ }
+ argvAddAttr(&pkg->fileList, RPMFILE_ARTIFACT, DEBUG_DWZ_DIR);
+ ret = 1;
+ }
+ path = _free(path);
+ return ret;
+}
- /* Append the file list preamble. */
- if (!files)
- {
- argvAdd(&files, "%defattr(-,root,root)");
- argvAdd(&files, "%dir /usr/lib/debug");
- }
- /* Add the files main debug-info file. */
- snprintf (tmp, 1024, "/usr/lib/debug/%s.debug", base);
- argvAdd(&files, tmp);
-
- /* Do not bother to check build-ids for symbolic links.
- We'll handle them for the link target. */
- if (lstat (name, &sbuf) == -1
- || S_ISLNK (sbuf.st_mode))
- continue;
+/* add the debug source files to package pkg.
+ * return 1 if something was added, 0 otherwise. */
+static int addDebugSrc(Package pkg, char *buildroot)
+{
+ int ret = 0;
+ char *path = NULL;
+ DIR *d;
+ struct dirent *de;
+
+ /* not needed if we have an extra debugsource subpackage */
+ if (rpmExpandNumeric("%{?_debugsource_packages}"))
+ return 0;
+
+ rasprintf(&path, "%s%s", buildroot, DEBUG_SRC_DIR);
+ d = opendir(path);
+ path = _free(path);
+ if (d) {
+ while ((de = readdir(d)) != NULL) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+ rasprintf(&path, "%s/%s", DEBUG_SRC_DIR, de->d_name);
+ if (!pkg->fileList) {
+ char *attr = mkattr();
+ argvAdd(&pkg->fileList, attr);
+ free(attr);
+ }
+ argvAdd(&pkg->fileList, path);
+ path = _free(path);
+ ret = 1;
+ }
+ closedir(d);
+ }
+ return ret;
+}
- /* Try to gather the build-id from the binary. */
- if (getELFBuildId (name, &build_id, &build_id_size) == -1)
- continue;
+/* find the debugsource package, if it has been created.
+ * We do this simply by searching for a package with the right name. */
+static Package findDebugsourcePackage(rpmSpec spec)
+{
+ Package pkg = NULL;
+ if (lookupPackage(spec, "debugsource", PART_SUBNAME|PART_QUIET, &pkg))
+ return NULL;
+ return pkg && pkg->fileList ? pkg : NULL;
+}
- /* If we see build-id links for the first time add the
- directory. */
- if (!seen_build_id)
- argvAdd(&files, "%dir /usr/lib/debug/.build-id");
-
- /* From the build-id construct the two links pointing back
- to the debug information file and the binary. */
- snprintf (tmp, 1024, "/usr/lib/debug/.build-id/%02x/",
- build_id[0]);
- for (i = 1; i < build_id_size; ++i)
- sprintf (tmp + strlen (tmp), "%02x", build_id[i]);
- argvAdd(&files, tmp);
- sprintf (tmp + strlen (tmp), ".debug");
- argvAdd(&files, tmp);
-
- free (build_id);
- }
+/* find the main debuginfo package. We do this simply by
+ * searching for a package with the right name. */
+static Package findDebuginfoPackage(rpmSpec spec)
+{
+ Package pkg = NULL;
+ if (lookupPackage(spec, "debuginfo", PART_SUBNAME|PART_QUIET, &pkg))
+ return NULL;
+ return pkg && pkg->fileList ? pkg : NULL;
+}
- /* If there are debuginfo files for this package add a
- new debuginfo package. */
- if (files)
- {
- dbg = newPackage (spec);
- headerNVR (pkg->header, &name, NULL, NULL);
- /* Set name, summary and group. */
- snprintf (tmp, 1024, "%s-debuginfo", name);
- headerPutString(dbg->header, RPMTAG_NAME, tmp);
- snprintf (tmp, 1024, "Debug information for package %s", name);
- headerPutString(dbg->header, RPMTAG_SUMMARY, tmp);
- snprintf (tmp, 1024, "This package provides debug information for package %s.\n"
- "Debug information is useful when developing applications that use this\n"
- "package or when debugging this package.", name);
- headerPutString(dbg->header, RPMTAG_DESCRIPTION, tmp);
- headerPutString(dbg->header, RPMTAG_GROUP, "Development/Debug");
- /* Inherit other tags from parent. */
- headerCopyTags (pkg->header, dbg->header, copyTagsForDebug);
-
- /* Build up the files list. */
- dbg->fileList = files;
- }
- }
+/* add a dependency (e.g. RPMTAG_REQUIRENAME or RPMTAG_RECOMMENDNAME)
+ for package "to" into package "from". */
+static void addPackageDeps(Package from, Package to, enum rpmTag_e tag)
+{
+ const char *name;
+ char *evr, *isaprov;
+ name = headerGetString(to->header, RPMTAG_NAME);
+ evr = headerGetAsString(to->header, RPMTAG_EVR);
+ isaprov = rpmExpand(name, "%{?_isa}", NULL);
+ addReqProv(from, tag, isaprov, evr, RPMSENSE_EQUAL, 0);
+ free(isaprov);
+ free(evr);
}
-#endif
rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
- int installSpecialDoc, int test)
+ int didInstall, int test)
{
Package pkg;
rpmRC rc = RPMRC_OK;
char *buildroot;
+ char *uniquearch = NULL;
+ Package maindbg = NULL; /* the (existing) main debuginfo package */
+ Package deplink = NULL; /* create requires to this package */
+ /* The debugsource package, if it exists, that the debuginfo package(s)
+ should Recommend. */
+ Package dbgsrcpkg = findDebugsourcePackage(spec);
+#if HAVE_LIBDW
+ elf_version (EV_CURRENT);
+#endif
check_fileList = newStringBuf();
- buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
genSourceRpmName(spec);
+ buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
+ if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) {
+ maindbg = findDebuginfoPackage(spec);
+ if (maindbg) {
+ /* move debuginfo package to back */
+ if (maindbg->next) {
+ Package *pp;
+ /* dequeue */
+ for (pp = &spec->packages; *pp != maindbg; pp = &(*pp)->next)
+ ;
+ *pp = maindbg->next;
+ maindbg->next = 0;
+ /* enqueue at tail */
+ for (; *pp; pp = &(*pp)->next)
+ ;
+ *pp = maindbg;
+ }
+ /* delete unsplit file list, we will re-add files back later */
+ /*backup maindb fileList before free*/
+ maindb_fileList_bakup = maindbg->fileList;
+ maindbg->fileFile = argvFree(maindbg->fileFile);
+ maindbg->fileList = NULL;
+ if (rpmExpandNumeric("%{?_unique_debug_names}"))
+ uniquearch = rpmExpand("-%{VERSION}-%{RELEASE}.%{_arch}", NULL);
+ }
+ } else if (dbgsrcpkg != NULL) {
+ /* We have a debugsource package, but no debuginfo subpackages.
+ The main debuginfo package should recommend the debugsource one. */
+ Package dbgpkg = findDebuginfoPackage(spec);
+ if (dbgpkg)
+ addPackageDeps(dbgpkg, dbgsrcpkg, RPMTAG_RECOMMENDNAME);
+ }
+
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
char *nvr;
const char *a;
int header_color;
int arch_color;
+ if (pkg == maindbg) {
+ /* if there is just one debuginfo package, we put our extra stuff
+ * in it. Otherwise we put it in the main debug package */
+ Package extradbg = !maindbg->fileList && maindbg->next && !maindbg->next->next ?
+ maindbg->next : maindbg;
+ if (addDebugDwz(extradbg, buildroot))
+ deplink = extradbg;
+ if (addDebugSrc(extradbg, buildroot))
+ deplink = extradbg;
+ if (dbgsrcpkg != NULL)
+ addPackageDeps(extradbg, dbgsrcpkg, RPMTAG_RECOMMENDNAME);
+ maindbg = NULL; /* all normal packages processed */
+ }
+
if (pkg->fileList == NULL)
continue;
@@ -2356,13 +3132,17 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n"), nvr);
free(nvr);
-
- if ((rc = processPackageFiles(spec, pkgFlags, pkg, installSpecialDoc, test)) != RPMRC_OK)
+
+ if ((rc = processPackageFiles(spec, pkgFlags, pkg, didInstall, test)) != RPMRC_OK)
goto exit;
-#if HAVE_GELF_H && HAVE_LIBELF
- addDebuginfoPackage(spec, pkg, buildroot);
-#endif
- if ((rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
+
+ if (maindbg)
+ filterDebuginfoPackage(spec, pkg, maindbg, dbgsrcpkg,
+ buildroot, uniquearch);
+ else if (deplink && pkg != deplink)
+ addPackageDeps(pkg, deplink, RPMTAG_REQUIRENAME);
+
+ if ((rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
goto exit;
a = headerGetString(pkg->header, RPMTAG_ARCH);
@@ -2397,6 +3177,8 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
}
exit:
check_fileList = freeStringBuf(check_fileList);
+ _free(buildroot);
+ _free(uniquearch);
return rc;
}