summaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
authorbiao716.wang <biao716.wang@samsung.com>2021-01-05 14:51:28 +0900
committerbiao716.wang <biao716.wang@samsung.com>2021-01-05 14:51:28 +0900
commit9de33a8a7cd9eae05c3c1df4b2c0e1e4cd2bd40a (patch)
tree03067d36d530c3eeb623e601b0c12a98f744376d /build
parent287097d4d8079b4485870c08cf5675b0bdd37ed9 (diff)
downloadrpm-submit/tizen_base/20210113.025730.tar.gz
rpm-submit/tizen_base/20210113.025730.tar.bz2
rpm-submit/tizen_base/20210113.025730.zip
Change-Id: Iab5438d6e4d45c937b191c03e9ef5dd3fad165c8 Signed-off-by: biao716.wang <biao716.wang@samsung.com>
Diffstat (limited to 'build')
-rw-r--r--build/Makefile.am11
-rw-r--r--build/build.c26
-rw-r--r--build/expression.c4
-rw-r--r--build/files.c1832
-rw-r--r--build/pack.c779
-rw-r--r--build/parseBuildInstallClean.c2
-rw-r--r--build/parseChangelog.c113
-rw-r--r--build/parseDescription.c23
-rw-r--r--build/parseFiles.c18
-rw-r--r--build/parsePolicies.c5
-rw-r--r--build/parsePreamble.c258
-rw-r--r--build/parsePrep.c89
-rw-r--r--build/parseReqs.c374
-rw-r--r--build/parseScript.c139
-rw-r--r--build/parseSpec.c308
-rw-r--r--build/reqprov.c115
-rw-r--r--build/rpmbuild.h6
-rw-r--r--build/rpmbuild_internal.h132
-rw-r--r--build/rpmbuild_misc.h28
-rw-r--r--build/rpmfc.c775
-rw-r--r--build/rpmfc.h46
-rw-r--r--build/rpmspec.h8
-rw-r--r--build/spec.c137
23 files changed, 3404 insertions, 1824 deletions
diff --git a/build/Makefile.am b/build/Makefile.am
index 1a540bce3..2fa3c3d6c 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -1,6 +1,10 @@
# Makefile for rpmbuild library.
+include $(top_srcdir)/rpm.am
+AM_CFLAGS = @RPMCFLAGS@
+
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
+AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
AM_CPPFLAGS += @WITH_MAGIC_INCLUDE@
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
@@ -16,10 +20,15 @@ librpmbuild_la_SOURCES = \
parsePolicies.c policies.c \
rpmbuild_internal.h rpmbuild_misc.h
-librpmbuild_la_LDFLAGS = -version-info 4:0:1
+librpmbuild_la_LDFLAGS = -version-info $(rpm_version_info)
librpmbuild_la_LIBADD = \
$(top_builddir)/lib/librpm.la \
$(top_builddir)/rpmio/librpmio.la \
$(top_builddir)/misc/libmisc.la \
+ @LTLIBICONV@ \
@WITH_POPT_LIB@ \
@WITH_MAGIC_LIB@
+
+if LIBDW
+librpmbuild_la_LIBADD += @WITH_LIBELF_LIB@ @WITH_LIBDW_LIB@
+endif
diff --git a/build/build.c b/build/build.c
index 04b039c5e..81152e53e 100644
--- a/build/build.c
+++ b/build/build.c
@@ -69,7 +69,7 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
pid_t pid;
pid_t child;
int status;
- rpmRC rc;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
switch (what) {
case RPMBUILD_PREP:
@@ -118,13 +118,11 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
fd = rpmMkTempFile(spec->rootDir, &scriptName);
if (Ferror(fd)) {
rpmlog(RPMLOG_ERR, _("Unable to open temp file: %s\n"), Fstrerror(fd));
- rc = RPMRC_FAIL;
goto exit;
}
if ((fp = fdopen(Fileno(fd), "w")) == NULL) {
rpmlog(RPMLOG_ERR, _("Unable to open stream: %s\n"), strerror(errno));
- rc = RPMRC_FAIL;
goto exit;
}
@@ -151,7 +149,6 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
}
if (buildDir && buildDir[0] != '/') {
- rc = RPMRC_FAIL;
goto exit;
}
@@ -160,8 +157,6 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
if (!(child = fork())) {
- /* NSPR messes with SIGPIPE, reset to default for the kids */
- signal(SIGPIPE, SIG_DFL);
errno = 0;
(void) execvp(argv[0], (char *const *)argv);
@@ -176,21 +171,19 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
if (pid == -1) {
rpmlog(RPMLOG_ERR, _("Error executing scriptlet %s (%s)\n"),
scriptName, name);
- rc = RPMRC_FAIL;
goto exit;
}
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
scriptName, name);
- rc = RPMRC_FAIL;
} else
rc = RPMRC_OK;
exit:
Fclose(fd);
if (scriptName) {
- if (rc == RPMRC_OK)
+ if (rc == RPMRC_OK && !rpmIsDebug())
(void) unlink(scriptName);
free(scriptName);
}
@@ -209,6 +202,21 @@ static rpmRC buildSpec(BTA_t buildArgs, rpmSpec spec, int what)
int test = (what & RPMBUILD_NOBUILD);
char *cookie = buildArgs->cookie ? xstrdup(buildArgs->cookie) : NULL;
+ if (rpmExpandNumeric("%{?source_date_epoch_from_changelog}") &&
+ getenv("SOURCE_DATE_EPOCH") == NULL) {
+ /* Use date of first (== latest) changelog entry */
+ Header h = spec->packages->header;
+ struct rpmtd_s td;
+ if (headerGet(h, RPMTAG_CHANGELOGTIME, &td, (HEADERGET_MINMEM|HEADERGET_RAW))) {
+ char sdestr[22];
+ snprintf(sdestr, sizeof(sdestr), "%lli",
+ (long long) rpmtdGetNumber(&td));
+ rpmlog(RPMLOG_NOTICE, _("setting %s=%s\n"), "SOURCE_DATE_EPOCH", sdestr);
+ setenv("SOURCE_DATE_EPOCH", sdestr, 0);
+ rpmtdFreeData(&td);
+ }
+ }
+
/* XXX TODO: rootDir is only relevant during build, eliminate from spec */
spec->rootDir = buildArgs->rootdir;
if (!spec->recursing && spec->BACount) {
diff --git a/build/expression.c b/build/expression.c
index a71ad095c..581a79e19 100644
--- a/build/expression.c
+++ b/build/expression.c
@@ -105,7 +105,6 @@ typedef struct _parseState {
char *p; /*!< current position in expression string */
int nextToken; /*!< current lookahead token */
Value tokenValue; /*!< valid when TOK_INTEGER or TOK_STRING */
- rpmSpec spec; /*!< spec file that we are parsing inside of */
} *ParseState;
@@ -644,7 +643,7 @@ static Value doLogical(ParseState state)
return v1;
}
-int parseExpressionBoolean(rpmSpec spec, const char *expr)
+int parseExpressionBoolean(const char *expr)
{
struct _parseState state;
int result = -1;
@@ -654,7 +653,6 @@ int parseExpressionBoolean(rpmSpec spec, const char *expr)
/* Initialize the expression parser state. */
state.p = state.str = xstrdup(expr);
- state.spec = spec;
state.nextToken = 0;
state.tokenValue = NULL;
(void) rdToken(&state);
diff --git a/build/files.c b/build/files.c
index 6f2cc7d98..67268d41d 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/fts.h"
-#include "lib/cpio.h"
+#include "misc/rpmfts.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,27 +119,17 @@ 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;
-
typedef struct FileEntry_s {
rpmfileAttrs attrFlags;
specfFlags specdFlags;
@@ -134,6 +146,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 +175,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 +193,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));
}
@@ -290,42 +303,6 @@ static VFA_t const verifyAttrs[] = {
{ NULL, 0 }
};
-/**
- * Add 'provides' information to debuginfo package
- * @param h Header information from debuginfo package
- * @return nothing
- */
-static void addPackageProvides_for_debuginfo_pkg(Header h)
-{
- const char *arch, *name;
- char *evr, *isaprov;
- rpmsenseFlags pflags = RPMSENSE_EQUAL;
-
- /* <name> = <evr> provide */
- name = headerGetString(h, RPMTAG_NAME);
- arch = headerGetString(h, RPMTAG_ARCH);
- evr = headerGetAsString(h, RPMTAG_EVR);
- headerPutString(h, RPMTAG_PROVIDENAME, name);
- headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
-
- /*
- * <name>(<isa>) = <evr> provide
- * FIXME: noarch needs special casing for now as BuildArch: noarch doesn't
- * cause reading in the noarch macros :-/
- */
-
- isaprov = rpmExpand(name, "%{?_isa}", NULL);
- if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) {
- headerPutString(h, RPMTAG_PROVIDENAME, isaprov);
- headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
- }
-
- free(isaprov);
- free(evr);
-}
-
static rpmFlags vfaMatch(VFA_t *attrs, const char *token, rpmFlags *flags)
{
VFA_t *vfa;
@@ -413,7 +390,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.
@@ -427,6 +408,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;
@@ -452,6 +434,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++ = ' ';
@@ -501,23 +487,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;
@@ -555,6 +544,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++ = ' ';
@@ -563,61 +556,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));
@@ -628,6 +621,7 @@ static rpmRC parseForAttr(char * buf, int def, FileEntry entry)
exit:
free(q);
+ free(attr_parameters);
return rc;
}
@@ -862,7 +856,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 }
};
@@ -943,7 +939,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)
@@ -982,22 +978,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
@@ -1015,16 +1024,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;
@@ -1080,29 +1113,26 @@ static void genCpioListAndHeader(FileList fl,
}
/* Skip files that were marked with %exclude. */
- if (flp->flags & RPMFILE_EXCLUDE) continue;
+ if (flp->flags & RPMFILE_EXCLUDE)
+ {
+ argvAdd(&pkg->fileExcludeList, flp->cpioPath);
+ continue;
+ }
- /* Omit '/' and/or URL prefix, leave room for "./" prefix */
- apathlen += (strlen(flp->cpioPath) - skipLen + (_addDotSlash ? 3 : 1));
+ /* Collect on-disk paths for archive creation */
+ pkg->dpaths[npaths++] = xstrdup(flp->diskPath);
- /* Leave room for both dirname and basename NUL's */
- dpathlen += (strlen(flp->diskPath) + 2);
-
- /*
- * 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);
@@ -1114,6 +1144,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.
@@ -1152,7 +1185,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);
@@ -1167,7 +1200,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);
@@ -1193,6 +1226,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;
@@ -1204,69 +1238,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");
}
}
@@ -1289,6 +1285,7 @@ static void FileListFree(FileList fl)
FileRecordsFree(&(fl->files));
free(fl->buildRoot);
argvFree(fl->docDirs);
+ rpmstrPoolFree(fl->pool);
}
/* forward ref */
@@ -1346,6 +1343,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. */
/*
@@ -1359,7 +1360,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')
@@ -1394,6 +1395,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);
@@ -1404,9 +1411,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)) {
@@ -1414,22 +1427,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);
}
@@ -1459,11 +1472,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, "|");
@@ -1472,7 +1487,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("");
}
@@ -1591,15 +1606,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) {
@@ -1624,6 +1639,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
@@ -1683,16 +2140,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);
@@ -1712,6 +2166,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);
@@ -1726,13 +2182,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))
@@ -1741,6 +2212,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;
@@ -1773,24 +2245,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;
@@ -1803,10 +2298,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);
@@ -1817,7 +2315,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);
}
@@ -1829,52 +2328,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)
-{
- struct FileList_s fl;
- ARGV_t fileNames = NULL;
- 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));
+/* 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 AttrRec_s root_ar = { 0, 0, 0, 0, 0, 0 };
- /* XXX spec->buildRoot == NULL, then xstrdup("") is returned */
- fl.buildRoot = rpmGenPath(spec->rootDir, spec->buildRoot, 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) */
- dupAttrRec(&root_ar, &fl.def.ar); /* XXX assume %defattr(-,root,root) */
- fl.def.verifyFlags = RPMVERIFY_ALL;
+ 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);
@@ -1884,92 +2408,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);
@@ -1994,6 +2595,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;
@@ -2024,13 +2626,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;
@@ -2075,31 +2678,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);
}
}
@@ -2109,6 +2720,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
*/
@@ -2145,259 +2757,357 @@ 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;
+ 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);
+ }
+ }
+}
-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;
- const char *ver, *rel;
-
- elf_version(EV_CURRENT);
- a = headerGetString(pkg->header, RPMTAG_ARCH);
- ver = headerGetAsString(pkg->header, RPMTAG_VERSION);
- rel = headerGetAsString(pkg->header, RPMTAG_RELEASE);
-
- 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)
- {
- /* Add security manifest to set right SMACK labels */
- argvAdd(&files, "%manifest %{name}-debuginfo.manifest");
-
- 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);
- headerPutString(dbg->header, RPMTAG_VERSION, ver);
- headerPutString(dbg->header, RPMTAG_RELEASE, rel);
- headerPutString(dbg->header, RPMTAG_ARCH, a);
- 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");
-
- /* Add 'provides' information to debuginfo package. */
- addPackageProvides_for_debuginfo_pkg(dbg->header);
-
- /* 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 */
+ maindbg->fileFile = argvFree(maindbg->fileFile);
+ maindbg->fileList = argvFree(maindbg->fileList);
+ 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;
@@ -2406,13 +3116,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);
@@ -2447,6 +3161,8 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
}
exit:
check_fileList = freeStringBuf(check_fileList);
+ _free(buildroot);
+ _free(uniquearch);
return rc;
}
diff --git a/build/pack.c b/build/pack.c
index 6b710380e..34e0568a7 100644
--- a/build/pack.c
+++ b/build/pack.c
@@ -6,8 +6,7 @@
#include "system.h"
#include <errno.h>
-#include <netdb.h>
-#include <time.h>
+#include <sys/wait.h>
#include <rpm/rpmlib.h> /* RPMSIGTAG*, rpmReadPackageFile */
#include <rpm/rpmfileutil.h>
@@ -15,7 +14,6 @@
#include "rpmio/rpmio_internal.h" /* fdInitDigest, fdFiniDigest */
#include "lib/fsm.h"
-#include "lib/cpio.h"
#include "lib/signature.h"
#include "lib/rpmlead.h"
#include "build/rpmbuild_internal.h"
@@ -23,15 +21,54 @@
#include "debug.h"
-typedef struct cpioSourceArchive_s {
- rpm_loff_t cpioArchiveSize;
- rpmfi cpioList;
-} * CSA_t;
+static int rpmPackageFilesArchive(rpmfiles fi, int isSrc,
+ FD_t cfd, ARGV_t dpaths,
+ rpm_loff_t * archiveSize, char ** failedFile)
+{
+ int rc = 0;
+ rpmfi archive = rpmfiNewArchiveWriter(cfd, fi);
+
+ while (!rc && (rc = rpmfiNext(archive)) >= 0) {
+ /* Copy file into archive. */
+ FD_t rfd = NULL;
+ const char *path = dpaths[rpmfiFX(archive)];
+ rfd = Fopen(path, "r.ufdio");
+ if (Ferror(rfd)) {
+ rc = RPMERR_OPEN_FAILED;
+ } else {
+ rc = rpmfiArchiveWriteFile(archive, rfd);
+ }
+
+ if (rc && failedFile)
+ *failedFile = xstrdup(path);
+ if (rfd) {
+ /* preserve any prior errno across close */
+ int myerrno = errno;
+ Fclose(rfd);
+ errno = myerrno;
+ }
+ }
+
+ if (rc == RPMERR_ITER_END)
+ rc = 0;
+
+ /* Finish the payload stream */
+ if (!rc)
+ rc = rpmfiArchiveClose(archive);
+
+ if (archiveSize)
+ *archiveSize = (rc == 0) ? rpmfiArchiveTell(archive) : 0;
+
+ rpmfiFree(archive);
+
+ return rc;
+}
/**
* @todo Create transaction set *much* earlier.
*/
-static rpmRC cpio_doio(FD_t fdo, Header h, CSA_t csa, const char * fmodeMacro)
+static rpmRC cpio_doio(FD_t fdo, Package pkg, const char * fmodeMacro,
+ rpm_loff_t *archiveSize)
{
char *failedFile = NULL;
FD_t cfd;
@@ -42,16 +79,18 @@ static rpmRC cpio_doio(FD_t fdo, Header h, CSA_t csa, const char * fmodeMacro)
if (cfd == NULL)
return RPMRC_FAIL;
- fsmrc = rpmPackageFilesArchive(csa->cpioList, headerIsSource(h), cfd,
- &csa->cpioArchiveSize, &failedFile);
+ fsmrc = rpmPackageFilesArchive(pkg->cpioList, headerIsSource(pkg->header),
+ cfd, pkg->dpaths,
+ archiveSize, &failedFile);
if (fsmrc) {
+ char *emsg = rpmfileStrerror(fsmrc);
if (failedFile)
rpmlog(RPMLOG_ERR, _("create archive failed on file %s: %s\n"),
- failedFile, rpmcpioStrerror(fsmrc));
+ failedFile, emsg);
else
- rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"),
- rpmcpioStrerror(fsmrc));
+ rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"), emsg);
+ free(emsg);
}
free(failedFile);
@@ -92,11 +131,13 @@ static rpmRC addFileToTag(rpmSpec spec, const char * file,
}
while (fgets(buf, sizeof(buf), f)) {
- if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
+ char *expanded;
+ if (rpmExpandMacros(spec->macros, buf, &expanded, 0) < 0) {
rpmlog(RPMLOG_ERR, _("%s: line: %s\n"), fn, buf);
goto exit;
}
- appendStringBuf(sb, buf);
+ appendStringBuf(sb, expanded);
+ free(expanded);
}
headerPutString(h, tag, getStringBuf(sb));
rc = RPMRC_OK;
@@ -109,40 +150,31 @@ exit:
return rc;
}
-static rpm_time_t * getBuildTime(void)
-{
- static rpm_time_t buildTime[1];
-
- if (buildTime[0] == 0)
- buildTime[0] = (int32_t) time(NULL);
- return buildTime;
-}
-
-static const char * buildHost(void)
-{
- static char hostname[1024];
- static int oneshot = 0;
- struct hostent *hbn;
-
- if (! oneshot) {
- (void) gethostname(hostname, sizeof(hostname));
- hbn = gethostbyname(hostname);
- if (hbn)
- strcpy(hostname, hbn->h_name);
- else
- rpmlog(RPMLOG_WARNING,
- _("Could not canonicalize hostname: %s\n"), hostname);
- oneshot = 1;
- }
- return(hostname);
-}
-
static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
{
struct TriggerFileEntry *p;
int addflags = 0;
rpmRC rc = RPMRC_FAIL;
Header h = pkg->header;
+ struct TriggerFileEntry *tfa[] = {pkg->triggerFiles,
+ pkg->fileTriggerFiles,
+ pkg->transFileTriggerFiles};
+
+ rpmTagVal progTags[] = {RPMTAG_TRIGGERSCRIPTPROG,
+ RPMTAG_FILETRIGGERSCRIPTPROG,
+ RPMTAG_TRANSFILETRIGGERSCRIPTPROG};
+
+ rpmTagVal flagTags[] = {RPMTAG_TRIGGERSCRIPTFLAGS,
+ RPMTAG_FILETRIGGERSCRIPTFLAGS,
+ RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS};
+
+ rpmTagVal scriptTags[] = {RPMTAG_TRIGGERSCRIPTS,
+ RPMTAG_FILETRIGGERSCRIPTS,
+ RPMTAG_TRANSFILETRIGGERSCRIPTS};
+ rpmTagVal priorityTags[] = {0,
+ RPMTAG_FILETRIGGERPRIORITIES,
+ RPMTAG_TRANSFILETRIGGERPRIORITIES};
+ int i;
if (addFileToTag(spec, pkg->preInFile, h, RPMTAG_PREIN, 1) ||
addFileToTag(spec, pkg->preUnFile, h, RPMTAG_PREUN, 1) ||
@@ -155,30 +187,39 @@ static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
goto exit;
}
- /* if any trigger has flags, we need to add flags entry for all of them */
- for (p = pkg->triggerFiles; p != NULL; p = p->next) {
- if (p->flags) {
- addflags = 1;
- break;
- }
- }
- for (p = pkg->triggerFiles; p != NULL; p = p->next) {
- headerPutString(h, RPMTAG_TRIGGERSCRIPTPROG, p->prog);
- if (addflags) {
- headerPutUint32(h, RPMTAG_TRIGGERSCRIPTFLAGS, &p->flags, 1);
+ for (i = 0; i < sizeof(tfa)/sizeof(tfa[0]); i++) {
+ addflags = 0;
+ /* if any trigger has flags, we need to add flags entry for all of them */
+ for (p = tfa[i]; p != NULL; p = p->next) {
+ if (p->flags) {
+ addflags = 1;
+ break;
+ }
}
- if (p->script) {
- headerPutString(h, RPMTAG_TRIGGERSCRIPTS, p->script);
- } else if (p->fileName) {
- if (addFileToTag(spec, p->fileName, h, RPMTAG_TRIGGERSCRIPTS, 0)) {
- goto exit;
+ for (p = tfa[i]; p != NULL; p = p->next) {
+ headerPutString(h, progTags[i], p->prog);
+
+ if (priorityTags[i]) {
+ headerPutUint32(h, priorityTags[i], &p->priority, 1);
+ }
+
+ if (addflags) {
+ headerPutUint32(h, flagTags[i], &p->flags, 1);
+ }
+
+ if (p->script) {
+ headerPutString(h, scriptTags[i], p->script);
+ } else if (p->fileName) {
+ if (addFileToTag(spec, p->fileName, h, scriptTags[i], 0)) {
+ goto exit;
+ }
+ } else {
+ /* This is dumb. When the header supports NULL string */
+ /* this will go away. */
+ headerPutString(h, scriptTags[i], "");
}
- } else {
- /* This is dumb. When the header supports NULL string */
- /* this will go away. */
- headerPutString(h, RPMTAG_TRIGGERSCRIPTS, "");
}
}
rc = RPMRC_OK;
@@ -187,92 +228,40 @@ exit:
return rc;
}
-static rpmRC copyPayload(FD_t ifd, const char *ifn, FD_t ofd, const char *ofn)
+static int haveTildeDep(Package pkg)
{
- char buf[BUFSIZ];
- size_t nb;
- rpmRC rc = RPMRC_OK;
-
- while ((nb = Fread(buf, 1, sizeof(buf), ifd)) > 0) {
- if (Fwrite(buf, sizeof(buf[0]), nb, ofd) != nb) {
- rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"),
- ofn, Fstrerror(ofd));
- rc = RPMRC_FAIL;
- break;
+ for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
+ rpmds ds = rpmdsInit(pkg->dependencies[i]);
+ while (rpmdsNext(ds) >= 0) {
+ if (strchr(rpmdsEVR(ds), '~'))
+ return 1;
}
}
-
- if (nb < 0) {
- rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"),
- ifn, Fstrerror(ifd));
- rc = RPMRC_FAIL;
- }
-
- return rc;
+ return 0;
}
-static int depContainsTilde(Header h, rpmTagVal tagEVR)
+static int haveRichDep(Package pkg)
{
- struct rpmtd_s evrs;
- const char *evr = NULL;
-
- if (headerGet(h, tagEVR, &evrs, HEADERGET_MINMEM)) {
- while ((evr = rpmtdNextString(&evrs)) != NULL)
- if (strchr(evr, '~'))
- break;
- rpmtdFreeData(&evrs);
+ for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
+ rpmds ds = rpmdsInit(pkg->dependencies[i]);
+ rpmTagVal tagN = rpmdsTagN(ds);
+ if (tagN != RPMTAG_REQUIRENAME && tagN != RPMTAG_CONFLICTNAME)
+ continue;
+ while (rpmdsNext(ds) >= 0) {
+ if (rpmdsIsRich(ds))
+ return 1;
+ }
}
- return evr != NULL;
-}
-
-static rpmTagVal depevrtags[] = {
- RPMTAG_PROVIDEVERSION,
- RPMTAG_REQUIREVERSION,
- RPMTAG_OBSOLETEVERSION,
- RPMTAG_CONFLICTVERSION,
- RPMTAG_ORDERVERSION,
- RPMTAG_TRIGGERVERSION,
- RPMTAG_SUGGESTSVERSION,
- RPMTAG_ENHANCESVERSION,
- 0
-};
-
-static int haveTildeDep(Header h)
-{
- int i;
-
- for (i = 0; depevrtags[i] != 0; i++)
- if (depContainsTilde(h, depevrtags[i]))
- return 1;
return 0;
}
-static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
- CSA_t csa, char **cookie)
+static char *getIOFlags(Package pkg)
{
- FD_t fd = NULL;
- FD_t ifd = NULL;
- char * sigtarget = NULL;;
- char * rpmio_flags = NULL;
- char * SHA1 = NULL;
+ char *rpmio_flags;
const char *s;
- Header h;
- Header sig = NULL;
- int xx;
- rpmRC rc = RPMRC_OK;
- struct rpmtd_s td;
- rpmTagVal sizetag;
- rpmTagVal payloadtag;
-
- /* Transfer header reference form *hdrp to h. */
- h = headerLink(*hdrp);
- *hdrp = headerFree(*hdrp);
-
- if (pkgidp)
- *pkgidp = NULL;
/* Save payload information */
- if (headerIsSource(h))
+ if (headerIsSource(pkg->header))
rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
else
rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);
@@ -286,7 +275,7 @@ static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileNam
if (s) {
char *buf = NULL;
const char *compr = NULL;
- headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio");
+ headerPutString(pkg->header, RPMTAG_PAYLOADFORMAT, "cpio");
if (rstreq(s+1, "ufdio")) {
compr = NULL;
@@ -296,252 +285,300 @@ static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileNam
} else if (rstreq(s+1, "bzdio")) {
compr = "bzip2";
/* Add prereq on rpm version that understands bzip2 payloads */
- (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
+ (void) rpmlibNeedsFeature(pkg, "PayloadIsBzip2", "3.0.5-1");
#endif
#if HAVE_LZMA_H
} else if (rstreq(s+1, "xzdio")) {
compr = "xz";
- (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1");
+ (void) rpmlibNeedsFeature(pkg, "PayloadIsXz", "5.2-1");
} else if (rstreq(s+1, "lzdio")) {
compr = "lzma";
- (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1");
+ (void) rpmlibNeedsFeature(pkg, "PayloadIsLzma", "4.4.6-1");
+#endif
+#ifdef HAVE_ZSTD
+ } else if (rstreq(s+1, "zstdio")) {
+ compr = "zstd";
+ /* Add prereq on rpm version that understands zstd payloads */
+ (void) rpmlibNeedsFeature(pkg, "PayloadIsZstd", "5.4.18-1");
#endif
} else {
rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
rpmio_flags);
- rc = RPMRC_FAIL;
+ rpmio_flags = _free(rpmio_flags);
goto exit;
}
if (compr)
- headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr);
+ headerPutString(pkg->header, RPMTAG_PAYLOADCOMPRESSOR, compr);
buf = xstrdup(rpmio_flags);
buf[s - rpmio_flags] = '\0';
- headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1);
+ headerPutString(pkg->header, RPMTAG_PAYLOADFLAGS, buf+1);
free(buf);
}
+exit:
+ return rpmio_flags;
+}
+static void finalizeDeps(Package pkg)
+{
/* check if the package has a dependency with a '~' */
- if (haveTildeDep(h))
- (void) rpmlibNeedsFeature(h, "TildeInVersions", "4.10.0-1");
+ if (haveTildeDep(pkg))
+ (void) rpmlibNeedsFeature(pkg, "TildeInVersions", "4.10.0-1");
+
+ /* check if the package has a rich dependency */
+ if (haveRichDep(pkg))
+ (void) rpmlibNeedsFeature(pkg, "RichDependencies", "4.12.0-1");
+
+ /* All dependencies added finally, write them into the header */
+ for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
+ /* Nuke any previously added dependencies from the header */
+ headerDel(pkg->header, rpmdsTagN(pkg->dependencies[i]));
+ headerDel(pkg->header, rpmdsTagEVR(pkg->dependencies[i]));
+ headerDel(pkg->header, rpmdsTagF(pkg->dependencies[i]));
+ headerDel(pkg->header, rpmdsTagTi(pkg->dependencies[i]));
+ /* ...and add again, now with automatic dependencies included */
+ rpmdsPutToHeader(pkg->dependencies[i], pkg->header);
+ }
+}
- /* Create and add the cookie */
- if (cookie) {
- rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
- headerPutString(h, RPMTAG_COOKIE, *cookie);
+static void *nullDigest(int algo, int ascii)
+{
+ void *d = NULL;
+ DIGEST_CTX ctx = rpmDigestInit(algo, 0);
+ rpmDigestFinal(ctx, &d, NULL, ascii);
+ return d;
+}
+
+static rpmRC fdJump(FD_t fd, off_t offset)
+{
+ if (Fseek(fd, offset, SEEK_SET) < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+ Fdescr(fd), Fstrerror(fd));
+ return RPMRC_FAIL;
}
+ return RPMRC_OK;
+}
- /*
- * Add system-wide Tizen build information
- */
- char *buildinfo = rpmExpand("%{?_buildinfo}", NULL);
- if (buildinfo && *buildinfo) {
- int err;
- int count = 0;
- char **strings = NULL;
-
- if ((err = poptParseArgvString(buildinfo, &count, &strings))) {
- rc = RPMRC_FAIL;
- free(buildinfo);
- rpmlog(RPMLOG_ERR, _("Can't parse BUILDINFO tag: %s\n"), poptStrerror(err));
- goto exit;
- }
+static rpmRC fdConsume(FD_t fd, off_t start, off_t nbytes)
+{
+ size_t bufsiz = 32*BUFSIZ;
+ unsigned char buf[bufsiz];
+ off_t left = nbytes;
+ ssize_t nb;
- if (count)
- headerPutStringArray(h, RPMTAG_BUILDINFO, strings, count);
+ if (start && fdJump(fd, start))
+ return RPMRC_FAIL;
- strings = _free(strings);
- }
- free(buildinfo);
+ while (left > 0) {
+ nb = Fread(buf, 1, (left < bufsiz) ? left : bufsiz, fd);
+ if (nb > 0)
+ left -= nb;
+ else
+ break;
+ };
- /* Reallocate the header into one contiguous region. */
- h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
- if (h == NULL) { /* XXX can't happen */
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
- goto exit;
+ if (left) {
+ rpmlog(RPMLOG_ERR, _("Failed to read %jd bytes in file %s: %s\n"),
+ (intmax_t) nbytes, Fdescr(fd), Fstrerror(fd));
}
- /* Re-reference reallocated header. */
- *hdrp = headerLink(h);
- /*
- * Write the header+archive into a temp file so that the size of
- * archive (after compression) can be added to the header.
- */
- fd = rpmMkTempFile(NULL, &sigtarget);
- if (fd == NULL || Ferror(fd)) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
+ return (left == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
+
+static rpmRC writeHdr(FD_t fd, Header pkgh)
+{
+ /* Reallocate the header into one contiguous region for writing. */
+ Header h = headerReload(headerCopy(pkgh), RPMTAG_HEADERIMMUTABLE);
+ rpmRC rc = RPMRC_FAIL;
+
+ if (h == NULL) {
+ rpmlog(RPMLOG_ERR,_("Unable to create immutable header region\n"));
goto exit;
}
- fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
- } else { /* Write the archive and get the size */
- (void) Fflush(fd);
- fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
- if (csa->cpioList != NULL) {
- rc = cpio_doio(fd, h, csa, rpmio_flags);
- } else {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
- }
+ rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
+ Fdescr(fd), Fstrerror(fd));
+ goto exit;
}
+ (void) Fflush(fd);
+ rc = RPMRC_OK;
+
+exit:
+ headerFree(h);
+ return rc;
+}
+
+/*
+ * This is more than just a little insane:
+ * In order to write the signature, we need to know the size and
+ * the size and digests of the header and payload, which are located
+ * after the signature on disk. We also need a digest of the compressed
+ * payload for the main header, and of course the payload is after the
+ * header on disk. So we need to create placeholders for both the
+ * signature and main header that exactly match the final sizes, calculate
+ * the payload digest, then generate and write the real main header to
+ * be able to FINALLY calculate the digests we need for the signature
+ * header. In other words, we need to write things in the exact opposite
+ * order to how the RPM format is laid on disk.
+ */
+static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp,
+ const char *fileName, char **cookie,
+ rpm_time_t buildTime, const char* buildHost)
+{
+ FD_t fd = NULL;
+ char * rpmio_flags = NULL;
+ char * SHA1 = NULL;
+ char * SHA256 = NULL;
+ uint8_t * MD5 = NULL;
+ char * pld = NULL;
+ uint32_t pld_algo = PGPHASHALGO_SHA256; /* TODO: macro configuration */
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ rpm_loff_t archiveSize = 0;
+ off_t sigStart, hdrStart, payloadStart, payloadEnd;
- if (rc != RPMRC_OK)
+ if (pkgidp)
+ *pkgidp = NULL;
+
+ rpmio_flags = getIOFlags(pkg);
+ if (!rpmio_flags)
goto exit;
- (void) Fclose(fd);
- fd = NULL;
- (void) unlink(fileName);
+ finalizeDeps(pkg);
- /* Generate the signature */
- (void) fflush(stdout);
- sig = rpmNewSignature();
+ /* Create and add the cookie */
+ if (cookie) {
+ rasprintf(cookie, "%s %d", buildHost, buildTime);
+ headerPutString(pkg->header, RPMTAG_COOKIE, *cookie);
+ }
/*
- * There should be rpmlib() dependency on this, but that doesn't
- * really do much good as these are signature tags that get read
- * way before dependency checking has a chance to figure out anything.
- * On the positive side, not inserting the 32bit tag at all means
- * older rpm will just bail out with error message on attempt to read
- * such a package.
+ * Add system-wide Tizen build information
*/
- if (csa->cpioArchiveSize < UINT32_MAX) {
- sizetag = RPMSIGTAG_SIZE;
- payloadtag = RPMSIGTAG_PAYLOADSIZE;
- } else {
- sizetag = RPMSIGTAG_LONGSIZE;
- payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
- }
- (void) rpmGenDigest(sig, sigtarget, sizetag);
- (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);
-
- if (SHA1) {
- /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
- rpmtdReset(&td);
- td.tag = RPMSIGTAG_SHA1;
- td.type = RPM_STRING_TYPE;
- td.data = SHA1;
- td.count = 1;
- headerPut(sig, &td, HEADERPUT_DEFAULT);
- SHA1 = _free(SHA1);
- }
+ char *buildinfo = rpmExpand("%{?_buildinfo}", NULL);
+ if (buildinfo && *buildinfo) {
+ int xx;
+ int count = 0;
+ char **strings = NULL;
- {
- /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
- rpmtdReset(&td);
- td.tag = payloadtag;
- td.count = 1;
- if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
- rpm_off_t asize = csa->cpioArchiveSize;
- td.type = RPM_INT32_TYPE;
- td.data = &asize;
- headerPut(sig, &td, HEADERPUT_DEFAULT);
- } else {
- rpm_loff_t asize = csa->cpioArchiveSize;
- td.type = RPM_INT64_TYPE;
- td.data = &asize;
- headerPut(sig, &td, HEADERPUT_DEFAULT);
- }
+
+ if ((xx = poptParseArgvString(buildinfo, &count, &strings))) {
+ rc = RPMRC_FAIL;
+ free(buildinfo);
+ rpmlog(RPMLOG_ERR, _("Can't parse BUILDINFO tag: %s\n"), poptStrerror(xx));
+ goto exit;
+ }
+
+ if (count)
+ headerPutStringArray(pkg->header, RPMTAG_BUILDINFO, strings, count);
+
+ strings = _free(strings);
}
+ free(buildinfo);
- /* Reallocate the signature into one contiguous region. */
- sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
- if (sig == NULL) { /* XXX can't happen */
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
+ /* Create a dummy payload digest to get the header size right */
+ pld = nullDigest(pld_algo, 1);
+ headerPutUint32(pkg->header, RPMTAG_PAYLOADDIGESTALGO, &pld_algo, 1);
+ headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
+ pld = _free(pld);
+
+ /* Check for UTF-8 encoding of string tags, add encoding tag if all good */
+ if (checkForEncoding(pkg->header, 1))
goto exit;
- }
/* Open the output file */
- fd = Fopen(fileName, "w.ufdio");
+ fd = Fopen(fileName, "w+.ufdio");
if (fd == NULL || Ferror(fd)) {
- rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
fileName, Fstrerror(fd));
goto exit;
}
/* Write the lead section into the package. */
- {
- rpmlead lead = rpmLeadFromHeader(h);
- rc = rpmLeadWrite(fd, lead);
- rpmLeadFree(lead);
- if (rc != RPMRC_OK) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
- Fstrerror(fd));
- goto exit;
- }
+ if (rpmLeadWrite(fd, pkg->header)) {
+ rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd));
+ goto exit;
}
- /* Write the signature section into the package. */
- if (rpmWriteSignature(fd, sig)) {
- rc = RPMRC_FAIL;
+ /* Save the position of signature section */
+ sigStart = Ftell(fd);
+
+ /* Generate and write a placeholder signature header */
+ SHA1 = nullDigest(PGPHASHALGO_SHA1, 1);
+ SHA256 = nullDigest(PGPHASHALGO_SHA256, 1);
+ MD5 = nullDigest(PGPHASHALGO_MD5, 0);
+ if (rpmGenerateSignature(SHA256, SHA1, MD5, 0, 0, fd))
goto exit;
- }
+ SHA1 = _free(SHA1);
+ SHA256 = _free(SHA256);
+ MD5 = _free(MD5);
- /* Append the header and archive */
- ifd = Fopen(sigtarget, "r.ufdio");
- if (ifd == NULL || Ferror(ifd)) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
- sigtarget, Fstrerror(ifd));
+ /* Write a placeholder header. */
+ hdrStart = Ftell(fd);
+ if (writeHdr(fd, pkg->header))
goto exit;
- }
- /* Add signatures to header, and write header into the package. */
- /* XXX header+payload digests/signatures might be checked again here. */
- { Header nh = headerRead(ifd, HEADER_MAGIC_YES);
+ /* Write payload section (cpio archive) */
+ payloadStart = Ftell(fd);
+ if (cpio_doio(fd, pkg, rpmio_flags, &archiveSize))
+ goto exit;
+ payloadEnd = Ftell(fd);
- if (nh == NULL) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
- sigtarget, Fstrerror(ifd));
- goto exit;
- }
+ /* Re-read payload to calculate compressed digest */
+ fdInitDigestID(fd, pld_algo, RPMTAG_PAYLOADDIGEST, 0);
+ if (fdConsume(fd, payloadStart, payloadEnd - payloadStart))
+ goto exit;
+ fdFiniDigest(fd, RPMTAG_PAYLOADDIGEST, (void **)&pld, NULL, 1);
- xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
- headerFree(nh);
+ /* Insert the payload digest in main header */
+ headerDel(pkg->header, RPMTAG_PAYLOADDIGEST);
+ headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
+ pld = _free(pld);
- if (xx) {
- rc = RPMRC_FAIL;
- rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
- fileName, Fstrerror(fd));
- goto exit;
- }
- }
-
- /* Write the payload into the package. */
- rc = copyPayload(ifd, fileName, fd, sigtarget);
+ /* Write the final header */
+ if (fdJump(fd, hdrStart))
+ goto exit;
+ if (writeHdr(fd, pkg->header))
+ goto exit;
+
+ /* Calculate digests: SHA on header, legacy MD5 on header + payload */
+ fdInitDigestID(fd, PGPHASHALGO_MD5, RPMTAG_SIGMD5, 0);
+ fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMTAG_SHA1HEADER, 0);
+ fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMTAG_SHA256HEADER, 0);
+ if (fdConsume(fd, hdrStart, payloadStart - hdrStart))
+ goto exit;
+ fdFiniDigest(fd, RPMTAG_SHA1HEADER, (void **)&SHA1, NULL, 1);
+ fdFiniDigest(fd, RPMTAG_SHA256HEADER, (void **)&SHA256, NULL, 1);
+
+ if (fdConsume(fd, 0, payloadEnd - payloadStart))
+ goto exit;
+ fdFiniDigest(fd, RPMTAG_SIGMD5, (void **)&MD5, NULL, 0);
+
+ if (fdJump(fd, sigStart))
+ goto exit;
+
+ /* Generate the signature. Now with right values */
+ if (rpmGenerateSignature(SHA256, SHA1, MD5, payloadEnd - hdrStart, archiveSize, fd))
+ goto exit;
+
+ rc = RPMRC_OK;
exit:
free(rpmio_flags);
free(SHA1);
- headerFree(h);
+ free(SHA256);
/* XXX Fish the pkgid out of the signature header. */
- if (sig != NULL && pkgidp != NULL) {
- struct rpmtd_s md5tag;
- headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT);
- if (rpmtdType(&md5tag) == RPM_BIN_TYPE &&
- md5tag.count == 16 && md5tag.data != NULL) {
- *pkgidp = md5tag.data;
+ if (pkgidp != NULL) {
+ if (MD5 != NULL) {
+ *pkgidp = MD5;
}
+ } else {
+ free(MD5);
}
- rpmFreeSignature(sig);
- Fclose(ifd);
Fclose(fd);
- if (sigtarget) {
- (void) unlink(sigtarget);
- free(sigtarget);
- }
-
if (rc == RPMRC_OK)
rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
else
@@ -576,78 +613,13 @@ static rpmRC checkPackages(char *pkgcheck)
return RPMRC_OK;
}
-static void trimChangelog(Header h)
+static rpmRC packageBinary(rpmSpec spec, Package pkg, const char *cookie, int cheating, char** filename)
{
- static int oneshot;
- static int cuttime, minnum, maxnum;
- int * times;
- char ** names = 0, ** texts = 0;
- int i, keep, count = 0;
-
- if (!oneshot) {
- char *binarychangelogtrim = rpmExpand("%{?_binarychangelogtrim}", NULL);
- oneshot = 1;
- if (binarychangelogtrim && *binarychangelogtrim) {
- maxnum = atoi(binarychangelogtrim);
- binarychangelogtrim = strchr(binarychangelogtrim, ',');
- if (binarychangelogtrim)
- binarychangelogtrim++;
- }
- if (binarychangelogtrim && *binarychangelogtrim) {
- cuttime = atoi(binarychangelogtrim);
- binarychangelogtrim = strchr(binarychangelogtrim, ',');
- if (binarychangelogtrim)
- binarychangelogtrim++;
- }
- if (binarychangelogtrim && *binarychangelogtrim) {
- minnum = atoi(binarychangelogtrim);
- binarychangelogtrim = strchr(binarychangelogtrim, ',');
- }
- }
- if (!cuttime && !minnum && !maxnum) {
- return;
- }
- if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) &times, &count))
- return;
- if ((!cuttime || count <= minnum) && (!maxnum || count <= maxnum)) {
- return;
- }
- keep = count;
- if (maxnum && keep > maxnum)
- keep = maxnum;
- if (cuttime) {
- for (i = 0; i < keep; i++) {
- if (i >= minnum && times[i] < cuttime)
- break;
- }
- keep = i;
- }
- if (keep >= count)
- return;
- headerGetEntry(h, RPMTAG_CHANGELOGNAME, NULL, (void **) &names, &count);
- headerGetEntry(h, RPMTAG_CHANGELOGTEXT, NULL, (void **) &texts, &count);
- headerModifyEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, times, keep);
- headerModifyEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, names, keep);
- headerModifyEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, texts, keep);
- free(names);
- free(texts);
-}
-
-rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
-{
- struct cpioSourceArchive_s csabuf;
- CSA_t csa = &csabuf;
- rpmRC rc;
- const char *errorString;
- Package pkg;
- char *pkglist = NULL;
-
- trimChangelog(spec->packages->header);
- for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
- char *fn;
+ const char *errorString;
+ rpmRC rc = RPMRC_OK;
if (pkg->fileList == NULL)
- continue;
+ return rc;
if ((rc = processScriptFiles(spec, pkg)))
return rc;
@@ -660,15 +632,15 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
headerCopyTags(spec->packages->header, pkg->header, copyTags);
headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
- headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
- headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
+ headerPutString(pkg->header, RPMTAG_BUILDHOST, spec->buildHost);
+ headerPutUint32(pkg->header, RPMTAG_BUILDTIME, &(spec->buildTime), 1);
if (spec->sourcePkgId != NULL) {
headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
}
if (cheating) {
- (void) rpmlibNeedsFeature(pkg->header, "ShortCircuited", "4.9.0-1");
+ (void) rpmlibNeedsFeature(pkg, "ShortCircuited", "4.9.0-1");
}
{ char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
@@ -681,14 +653,14 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
headerGetString(pkg->header, RPMTAG_NAME), errorString);
return RPMRC_FAIL;
}
- fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
+ *filename = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
if ((binDir = strchr(binRpm, '/')) != NULL) {
struct stat st;
char *dn;
*binDir = '\0';
dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
if (stat(dn, &st) < 0) {
- switch(errno) {
+ switch (errno) {
case ENOENT:
if (mkdir(dn, 0755) == 0)
break;
@@ -703,19 +675,28 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
free(binRpm);
}
- memset(csa, 0, sizeof(*csa));
- csa->cpioArchiveSize = 0;
- csa->cpioList = rpmfiLink(pkg->cpioList);
-
- rc = writeRPM(&pkg->header, NULL, fn, csa, NULL);
- csa->cpioList = rpmfiFree(csa->cpioList);
+ rc = writeRPM(pkg, NULL, *filename, NULL, spec->buildTime, spec->buildHost);
if (rc == RPMRC_OK) {
/* Do check each written package if enabled */
- char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", fn, NULL);
+ char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", *filename, NULL);
if (pkgcheck[0] != ' ') {
rc = checkPackages(pkgcheck);
}
free(pkgcheck);
+ }
+ return rc;
+}
+
+rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
+{
+ rpmRC rc;
+ Package pkg;
+ char *pkglist = NULL;
+
+ for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
+ char *fn = NULL;
+ rc = packageBinary(spec, pkg, cookie, cheating, &fn);
+ if (rc == RPMRC_OK) {
rstrcat(&pkglist, fn);
rstrcat(&pkglist, " ");
}
@@ -741,32 +722,28 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
rpmRC packageSources(rpmSpec spec, char **cookie)
{
- struct cpioSourceArchive_s csabuf;
- CSA_t csa = &csabuf;
+ Package sourcePkg = spec->sourcePackage;
rpmRC rc;
+ uint32_t one = 1;
/* Add some cruft */
- headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
- headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
- headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
+ headerPutString(sourcePkg->header, RPMTAG_RPMVERSION, VERSION);
+ headerPutString(sourcePkg->header, RPMTAG_BUILDHOST, spec->buildHost);
+ headerPutUint32(sourcePkg->header, RPMTAG_BUILDTIME, &(spec->buildTime), 1);
+ headerPutUint32(sourcePkg->header, RPMTAG_SOURCEPACKAGE, &one, 1);
/* XXX this should be %_srpmdir */
{ char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
- memset(csa, 0, sizeof(*csa));
- csa->cpioArchiveSize = 0;
- csa->cpioList = rpmfiLink(spec->sourceCpioList);
-
spec->sourcePkgId = NULL;
- rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, csa, cookie);
+ rc = writeRPM(sourcePkg, &spec->sourcePkgId, fn, cookie, spec->buildTime, spec->buildHost);
/* Do check SRPM package if enabled */
if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
rc = checkPackages(pkgcheck);
}
- rpmfiFree(csa->cpioList);
free(pkgcheck);
free(fn);
}
diff --git a/build/parseBuildInstallClean.c b/build/parseBuildInstallClean.c
index 7cfd70755..f7b4bb715 100644
--- a/build/parseBuildInstallClean.c
+++ b/build/parseBuildInstallClean.c
@@ -49,7 +49,7 @@ int parseBuildInstallClean(rpmSpec spec, int parsePart)
if (parsePart == PART_BUILD) {
char* buf = strdup(
- "if [[ $RPM_ARCH == \"aarch64\" ]]; then\n"
+ "if [[ `uname -m` == \"aarch64\" ]]; then\n"
"ref=/usr/lib/rpm\n"
"for s in guess sub; do\n"
" for c in $(find -maxdepth 8 -name \"config.$s\"); do\n"
diff --git a/build/parseChangelog.c b/build/parseChangelog.c
index b06c9236b..105bb20c3 100644
--- a/build/parseChangelog.c
+++ b/build/parseChangelog.c
@@ -32,17 +32,20 @@ static int sameDate(const struct tm *ot, const struct tm *nt)
/**
* Parse date string to seconds.
+ * accepted date formats are "Mon Jun 6 2016" (original one)
+ * and "Thu Oct 6 06:48:39 CEST 2016" (extended one)
* @param datestr date string (e.g. 'Wed Jan 1 1997')
* @retval secs secs since the unix epoch
* @return 0 on success, -1 on error
*/
-static int dateToTimet(const char * datestr, time_t * secs)
+static int dateToTimet(const char * datestr, time_t * secs, int * date_words)
{
int rc = -1; /* assume failure */
struct tm time, ntime;
const char * const * idx;
char *p, *pe, *q, *date, *tz;
-
+ char tz_name[10]; /* name of timezone (if extended format is used) */
+
static const char * const days[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
static const char * const months[] =
@@ -80,26 +83,93 @@ static int dateToTimet(const char * datestr, time_t * secs)
if (*p == '\0') goto exit;
pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
- /* make this noon so the day is always right (as we make this UTC) */
- time.tm_hour = 12;
-
time.tm_mday = strtol(p, &q, 10);
if (!(q && *q == '\0')) goto exit;
if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) goto exit;
- /* year */
- p = pe; SKIPSPACE(p);
- if (*p == '\0') goto exit;
- pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe = '\0';
+ /* first part of year entry (original format) / time entry (extended format)*/
+ p = pe;
+ SKIPSPACE(p);
+ if (*p == '\0')
+ goto exit;
+
+ /* in the original format here is year record (e.g. 1999),
+ * in the extended one here is time stamp (e.g. 10:22:30).
+ * Choose the format
+ */
+ if ((p[1]==':') || ((p[1]!='\0') && ((p[2]==':')))) {
+ /* it can be extended format */
+ *date_words = 6;
+
+ /* second part of time entry */
+ /* hours */
+ time.tm_hour = strtol(p, &q, 10);
+ if ( (time.tm_hour < 0) || (time.tm_hour > 23) )
+ goto exit;
+ if (*q!=':')
+ goto exit;
+ p = ++q;
+ /* minutes */
+ time.tm_min = strtol(p, &q, 10);
+ if ( (time.tm_min < 0) || (time.tm_min > 59) )
+ goto exit;
+ if (*q != ':')
+ goto exit;
+ p = ++q;
+ /* time - seconds */
+ time.tm_sec = strtol(p, &q, 10);
+ if ( (time.tm_sec < 0) || (time.tm_sec > 59) )
+ goto exit;
+ p = q;
+
+ /* time zone name */
+ SKIPSPACE(p);
+ if (*p == '\0')
+ goto exit;
+ pe = p;
+ SKIPNONSPACE(pe);
+ if (*pe != '\0')
+ *pe++ = '\0';
+ if (((int)(pe-p) + 1) > 9 )
+ goto exit;
+ strncpy(tz_name, p, (int)(pe-p));
+ tz_name[(int)(pe-p)] = '\0';
+
+ /* first part of year entry */
+ p = pe;
+ SKIPSPACE(p);
+ if (*p == '\0')
+ goto exit;
+ } else {
+ *date_words = 4;
+ /* the original format */
+ /* make this noon so the day is always right (as we make this UTC) */
+ time.tm_hour = 12;
+ }
+
+ /* year - second part */
+ pe = p;
+ SKIPNONSPACE(pe);
+ if (*pe != '\0')
+ *pe = '\0';
time.tm_year = strtol(p, &q, 10);
if (!(q && *q == '\0')) goto exit;
if (time.tm_year < 1990 || time.tm_year >= 3000) goto exit;
time.tm_year -= 1900;
- /* chnagelog date is always in UTC */
+ /* change time zone and compute calendar time representation */
tz = getenv("TZ");
- if (tz) tz = xstrdup(tz);
- setenv("TZ", "UTC", 1);
+ if (tz)
+ tz = xstrdup(tz);
+ if (*date_words == 6) {
+ /* changelog date is in read time zone */
+ tz = getenv("TZ");
+ if (tz) tz = xstrdup(tz);
+ setenv("TZ", tz_name, 1);
+ } else {
+ /* changelog date is always in UTC */
+ setenv("TZ", "UTC", 1);
+ }
ntime = time; /* struct assignment */
*secs = mktime(&ntime);
unsetenv("TZ");
@@ -107,6 +177,7 @@ static int dateToTimet(const char * datestr, time_t * secs)
setenv("TZ", tz, 1);
free(tz);
}
+
if (*secs == -1) goto exit;
/* XXX Turn this into a hard error in a release or two */
@@ -135,6 +206,7 @@ static rpmRC addChangelog(Header h, ARGV_const_t sb)
time_t lastTime = 0;
time_t trimtime = rpmExpandNumeric("%{?_changelog_trimtime}");
char *date, *name, *text, *next;
+ int date_words; /* number of words in date string */
s = sp = argvJoin(sb, "");
@@ -149,7 +221,7 @@ static rpmRC addChangelog(Header h, ARGV_const_t sb)
/* find end of line */
date = s;
- while(*s && *s != '\n') s++;
+ while (*s && *s != '\n') s++;
if (! *s) {
rpmlog(RPMLOG_ERR, _("incomplete %%changelog entry\n"));
goto exit;
@@ -160,12 +232,8 @@ static rpmRC addChangelog(Header h, ARGV_const_t sb)
/* 4 fields of date */
date++;
s = date;
- for (i = 0; i < 4; i++) {
- SKIPSPACE(s);
- SKIPNONSPACE(s);
- }
SKIPSPACE(date);
- if (dateToTimet(date, &time)) {
+ if (dateToTimet(date, &time, &date_words)) {
rpmlog(RPMLOG_ERR, _("bad date in %%changelog: %s\n"), date);
goto exit;
}
@@ -174,6 +242,10 @@ static rpmRC addChangelog(Header h, ARGV_const_t sb)
_("%%changelog not in descending chronological order\n"));
goto exit;
}
+ for (i = 0; i < date_words; i++) {
+ SKIPSPACE(s);
+ SKIPNONSPACE(s);
+ }
lastTime = time;
/* skip space to the name */
@@ -237,6 +309,11 @@ int parseChangelog(rpmSpec spec)
{
int nextPart, rc, res = PART_ERROR;
ARGV_t sb = NULL;
+
+ if (headerIsEntry(spec->packages->header, RPMTAG_CHANGELOGTIME)) {
+ rpmlog(RPMLOG_ERR, _("line %d: second %%changelog\n"), spec->lineNum);
+ goto exit;
+ }
/* There are no options to %changelog */
if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
diff --git a/build/parseDescription.c b/build/parseDescription.c
index f233d8d24..428821e56 100644
--- a/build/parseDescription.c
+++ b/build/parseDescription.c
@@ -60,22 +60,8 @@ int parseDescription(rpmSpec spec)
}
}
- if (lookupPackage(spec, name, flag, &pkg)) {
- rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
- spec->lineNum, spec->line);
+ if (lookupPackage(spec, name, flag, &pkg))
goto exit;
- }
-
-
- /******************/
-
-#if 0
- if (headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
- rpmlog(RPMLOG_ERR, _("line %d: Second description\n"),
- spec->lineNum);
- goto exit;
- }
-#endif
sb = newStringBuf();
@@ -99,11 +85,10 @@ int parseDescription(rpmSpec spec)
}
stripTrailingBlanksStringBuf(sb);
- if (!((spec->flags & RPMSPEC_NOLANG) && !rstreq(lang, RPMBUILD_DEFAULT_LANG))) {
- (void) headerAddI18NString(pkg->header, RPMTAG_DESCRIPTION,
- getStringBuf(sb), lang);
+ if (addLangTag(spec, pkg->header,
+ RPMTAG_DESCRIPTION, getStringBuf(sb), lang)) {
+ nextPart = PART_ERROR;
}
-
exit:
freeStringBuf(sb);
diff --git a/build/parseFiles.c b/build/parseFiles.c
index ea0d6385f..5ccc94509 100644
--- a/build/parseFiles.c
+++ b/build/parseFiles.c
@@ -27,7 +27,7 @@ int parseFiles(rpmSpec spec)
};
/* XXX unmask %license while parsing %files */
- addMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC);
+ rpmPushMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC);
if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%files: %s\n"),
@@ -61,10 +61,18 @@ int parseFiles(rpmSpec spec)
}
}
- if (lookupPackage(spec, name, flag, &pkg)) {
- rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
- spec->lineNum, spec->line);
+ if (lookupPackage(spec, name, flag, &pkg))
goto exit;
+
+ /*
+ * This should be an error, but its surprisingly commonly abused for the
+ * effect of multiple -f arguments in versions that dont support it.
+ * Warn but preserve behavior, except for leaking memory.
+ */
+ if (pkg->fileList != NULL) {
+ rpmlog(RPMLOG_WARNING, _("line %d: multiple %%files for package '%s'\n"),
+ spec->lineNum, rpmstrPoolStr(pkg->pool, pkg->name));
+ pkg->fileList = argvFree(pkg->fileList);
}
for (arg=1; arg<argc; arg++) {
@@ -95,7 +103,7 @@ int parseFiles(rpmSpec spec)
res = nextPart;
exit:
- delMacro(NULL, "license");
+ rpmPopMacro(NULL, "license");
free(argv);
poptFreeContext(optCon);
diff --git a/build/parsePolicies.c b/build/parsePolicies.c
index 129541635..54c8593ec 100644
--- a/build/parsePolicies.c
+++ b/build/parsePolicies.c
@@ -58,11 +58,8 @@ int parsePolicies(rpmSpec spec)
}
}
- if (lookupPackage(spec, name, flag, &pkg)) {
- rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
- spec->lineNum, spec->line);
+ if (lookupPackage(spec, name, flag, &pkg))
goto exit;
- }
if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
nextPart = PART_NONE;
diff --git a/build/parsePreamble.c b/build/parsePreamble.c
index f02e14e92..96bf9c035 100644
--- a/build/parsePreamble.c
+++ b/build/parsePreamble.c
@@ -19,8 +19,8 @@
#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
#define SKIPNONSPACE(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)++;}
/**
*/
@@ -92,7 +92,7 @@ static int parseSimplePart(const char *line, char **name, int *flag)
*name = NULL;
if (!(tok = strtok(NULL, " \t\n"))) {
- rc = 0;
+ rc = 1;
goto exit;
}
@@ -299,14 +299,14 @@ static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag
rasprintf(&buf, "%s%d",
(flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
- addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
+ rpmPushMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
free(buf);
rasprintf(&buf, "%sURL%d",
(flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
- addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
+ rpmPushMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
free(buf);
#ifdef WITH_LUA
- if (!spec->recursing) {
+ {
rpmlua lua = NULL; /* global state */
const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
rpmluaPushTable(lua, what);
@@ -428,6 +428,11 @@ static rpmRC checkForValidArchitectures(rpmSpec spec)
char *arch = rpmExpand("%{_target_cpu}", NULL);
char *os = rpmExpand("%{_target_os}", NULL);
rpmRC rc = RPMRC_FAIL; /* assume failure */
+
+ if (!strcmp(arch, "noarch")) {
+ free(arch);
+ arch = rpmExpand("%{_build_cpu}", NULL);
+ }
if (isMemberInEntry(spec->buildRestrictions,
arch, RPMTAG_EXCLUDEARCH) == 1) {
@@ -539,6 +544,13 @@ static void fillOutMainPackage(Header h)
/**
*/
+void copyInheritedTags(Header h, Header fromh)
+{
+ headerCopyTags(fromh, h, (rpmTagVal *)copyTagsDuringParse);
+}
+
+/**
+ */
static rpmRC readIcon(Header h, const char * file)
{
char *fn = NULL;
@@ -598,36 +610,113 @@ if (multiToken) { \
return RPMRC_FAIL; \
}
+static void specLog(rpmSpec spec, int lvl, const char *line, const char *msg)
+{
+ if (spec) {
+ rpmlog(lvl, _("line %d: %s in: %s\n"), spec->lineNum, msg, spec->line);
+ } else {
+ rpmlog(lvl, _("%s in: %s\n"), msg, line);
+ }
+}
+
/**
* Check for inappropriate characters. All alphanums are considered sane.
- * @param spec spec
+ * @param spec spec (or NULL)
* @param field string to check
- * @param fsize size of string to check
* @param whitelist string of permitted characters
* @return RPMRC_OK if OK
*/
-rpmRC rpmCharCheck(rpmSpec spec, const char *field, size_t fsize, const char *whitelist)
+rpmRC rpmCharCheck(rpmSpec spec, const char *field, const char *whitelist)
{
- const char *ch, *stop = &field[fsize];
+ const char *ch;
+ char *err = NULL;
+ rpmRC rc = RPMRC_OK;
- for (ch=field; *ch && ch < stop; ch++) {
+ for (ch=field; *ch; ch++) {
if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
- if (isprint(*ch)) {
- rpmlog(RPMLOG_ERR, _("line %d: Illegal char '%c' in: %s\n"),
- spec->lineNum, *ch, spec->line);
- } else {
- rpmlog(RPMLOG_ERR, _("line %d: Illegal char in: %s\n"),
- spec->lineNum, spec->line);
+ rasprintf(&err, _("Illegal char '%c' (0x%x)"),
+ isprint(*ch) ? *ch : '?', *ch);
+ }
+ for (ch=field; *ch; ch++) {
+ if (strchr("%{}", *ch)) {
+ specLog(spec, RPMLOG_WARNING, field,
+ _("Possible unexpanded macro"));
+ break;
}
- return RPMRC_FAIL;
}
- if (strstr(field, "..") != NULL) {
- rpmlog(RPMLOG_ERR, _("line %d: Illegal sequence \"..\" in: %s\n"),
- spec->lineNum, spec->line);
- return RPMRC_FAIL;
+
+ if (err == NULL && strstr(field, "..") != NULL) {
+ rasprintf(&err, _("Illegal sequence \"..\""));
}
-
- return RPMRC_OK;
+
+ if (err) {
+ specLog(spec, RPMLOG_ERR, field, err);
+ free(err);
+ rc = RPMRC_FAIL;
+ }
+ return rc;
+}
+
+static int haveLangTag(Header h, rpmTagVal tag, const char *lang)
+{
+ int rc = 0; /* assume tag not present */
+ int langNum = -1;
+
+ if (lang && *lang) {
+ /* See if the language is in header i18n table */
+ struct rpmtd_s langtd;
+ const char *s = NULL;
+ headerGet(h, RPMTAG_HEADERI18NTABLE, &langtd, HEADERGET_MINMEM);
+ while ((s = rpmtdNextString(&langtd)) != NULL) {
+ if (rstreq(s, lang)) {
+ langNum = rpmtdGetIndex(&langtd);
+ break;
+ }
+ }
+ rpmtdFreeData(&langtd);
+ } else {
+ /* C locale */
+ langNum = 0;
+ }
+
+ /* If locale is present, check the actual tag content */
+ if (langNum >= 0) {
+ struct rpmtd_s td;
+ headerGet(h, tag, &td, HEADERGET_MINMEM|HEADERGET_RAW);
+ if (rpmtdSetIndex(&td, langNum) == langNum) {
+ const char *s = rpmtdGetString(&td);
+ /* non-empty string means a dupe */
+ if (s && *s)
+ rc = 1;
+ }
+ rpmtdFreeData(&td);
+ };
+
+ return rc;
+}
+
+int addLangTag(rpmSpec spec, Header h, rpmTagVal tag,
+ const char *field, const char *lang)
+{
+ int skip = 0;
+
+ if (haveLangTag(h, tag, lang)) {
+ /* Turn this into an error eventually */
+ rpmlog(RPMLOG_WARNING, _("line %d: second %s\n"),
+ spec->lineNum, rpmTagGetName(tag));
+ }
+
+ if (!*lang) {
+ headerPutString(h, tag, field);
+ } else {
+ skip = ((spec->flags & RPMSPEC_NOLANG) &&
+ !rstreq(lang, RPMBUILD_DEFAULT_LANG));
+ if (skip)
+ return 0;
+ headerAddI18NString(h, tag, field, lang);
+ }
+
+ return 0;
}
static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
@@ -669,14 +758,17 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
switch (tag) {
case RPMTAG_NAME:
SINGLE_TOKEN_ONLY;
- if (rpmCharCheck(spec, field, strlen(field), ".-_+%{}"))
+ if (rpmCharCheck(spec, field, WHITELIST_NAME))
goto exit;
headerPutString(pkg->header, tag, field);
+ /* Main pkg name is unknown at the start, populate as soon as we can */
+ if (pkg == spec->packages)
+ pkg->name = rpmstrPoolId(spec->pool, field, 1);
break;
case RPMTAG_VERSION:
case RPMTAG_RELEASE:
SINGLE_TOKEN_ONLY;
- if (rpmCharCheck(spec, field, strlen(field), "._+%{}~"))
+ if (rpmCharCheck(spec, field, "._+%{}~"))
goto exit;
headerPutString(pkg->header, tag, field);
break;
@@ -694,11 +786,8 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
case RPMTAG_VENDOR:
case RPMTAG_LICENSE:
case RPMTAG_PACKAGER:
- if (!*lang) {
- headerPutString(pkg->header, tag, field);
- } else if (!((spec->flags & RPMSPEC_NOLANG) &&
- !rstreq(lang, RPMBUILD_DEFAULT_LANG)))
- headerAddI18NString(pkg->header, tag, field, lang);
+ if (addLangTag(spec, pkg->header, tag, field, lang))
+ goto exit;
break;
case RPMTAG_BUILDROOT:
/* just silently ignore BuildRoot */
@@ -731,8 +820,8 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
goto exit;
}
macro = NULL;
- delMacro(NULL, "_docdir");
- addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
+ rpmPopMacro(NULL, "_docdir");
+ rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
break;
case RPMTAG_EPOCH: {
SINGLE_TOKEN_ONLY;
@@ -773,8 +862,8 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
if (parseNoSource(spec, field, tag))
goto exit;
break;
- case RPMTAG_ORDERFLAGS:
- case RPMTAG_REQUIREFLAGS:
+ case RPMTAG_ORDERNAME:
+ case RPMTAG_REQUIRENAME:
if (parseBits(lang, installScriptBits, &tagflags)) {
rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
spec->lineNum, rpmTagGetName(tag), spec->line);
@@ -782,17 +871,24 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
}
/* fallthrough */
case RPMTAG_PREREQ:
+ case RPMTAG_RECOMMENDNAME:
+ case RPMTAG_SUGGESTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_ENHANCENAME:
+ case RPMTAG_CONFLICTNAME:
+ case RPMTAG_OBSOLETENAME:
+ case RPMTAG_PROVIDENAME:
+ if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
+ goto exit;
+ break;
case RPMTAG_BUILDPREREQ:
case RPMTAG_BUILDREQUIRES:
case RPMTAG_BUILDCONFLICTS:
- case RPMTAG_CONFLICTFLAGS:
- case RPMTAG_OBSOLETEFLAGS:
- case RPMTAG_PROVIDEFLAGS:
- if (parseRCPOT(spec, pkg, field, tag, 0, tagflags))
+ if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags, addReqProvPkg, NULL))
goto exit;
break;
- case RPMTAG_SUGGESTSFLAGS:
- case RPMTAG_ENHANCESFLAGS:
+ case RPMTAG_OLDSUGGESTSFLAGS:
+ case RPMTAG_OLDENHANCESFLAGS:
case RPMTAG_BUILDSUGGESTS:
case RPMTAG_BUILDENHANCES:
tagflags = RPMSENSE_MISSINGOK;
@@ -800,7 +896,7 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
tagflags |= RPMSENSE_STRONG;
if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
tagflags |= RPMSENSE_STRONG;
- if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
+ if (parseRCPOT(spec, pkg, field, tag, 0, tagflags, addReqProvPkg, NULL))
return rc;
break;
case RPMTAG_EXCLUDEARCH:
@@ -820,6 +916,13 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
goto exit;
}
if (spec->packages == pkg) {
+ if (spec->BANames) {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: Duplicate BuildArch entry: %s\n"),
+ spec->lineNum, spec->line);
+ BANames = _free(BANames);
+ goto exit;
+ }
spec->BACount = BACount;
spec->BANames = BANames;
} else {
@@ -836,8 +939,10 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
spec->BANames = _free(spec->BANames);
break;
}
- case RPMTAG_COLLECTIONS:
- case RPMTAG_BUILDINFO:
+ case RPMTAG_REMOVEPATHPOSTFIXES:
+ argvSplit(&pkg->removePostfixes, field, ":");
+ break;
+ case RPMTAG_BUILDINFO:
if (addOrAppendListEntry(pkg->header, tag, field))
goto exit;
break;
@@ -846,8 +951,17 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
goto exit;
}
- if (macro)
- addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
+ if (macro) {
+ rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
+ /* Add a separate uppercase macro for tags from the main package */
+ if (pkg == spec->packages) {
+ char *m = xstrdup(macro);
+ for (char *p = m; *p; ++p)
+ *p = rtoupper(*p);
+ rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC);
+ free(m);
+ }
+ }
rc = RPMRC_OK;
exit:
return rc;
@@ -881,7 +995,7 @@ static struct PreambleRec_s const preambleList[] = {
{RPMTAG_GROUP, 1, 0, LEN_AND_STR("group")},
{RPMTAG_PACKAGER, 0, 0, LEN_AND_STR("packager")},
{RPMTAG_URL, 0, 0, LEN_AND_STR("url")},
- {RPMTAG_VCS, 0, 0, LEN_AND_STR("vcs")},
+ {RPMTAG_VCS, 0, 0, LEN_AND_STR("vcs")},
{RPMTAG_SOURCE, 0, 0, LEN_AND_STR("source")},
{RPMTAG_PATCH, 0, 0, LEN_AND_STR("patch")},
{RPMTAG_NOSOURCE, 0, 0, LEN_AND_STR("nosource")},
@@ -891,11 +1005,15 @@ static struct PreambleRec_s const preambleList[] = {
{RPMTAG_EXCLUDEOS, 0, 0, LEN_AND_STR("excludeos")},
{RPMTAG_EXCLUSIVEOS, 0, 0, LEN_AND_STR("exclusiveos")},
{RPMTAG_ICON, 0, 0, LEN_AND_STR("icon")},
- {RPMTAG_PROVIDEFLAGS, 0, 0, LEN_AND_STR("provides")},
- {RPMTAG_REQUIREFLAGS, 2, 0, LEN_AND_STR("requires")},
+ {RPMTAG_PROVIDENAME, 0, 0, LEN_AND_STR("provides")},
+ {RPMTAG_REQUIRENAME, 2, 0, LEN_AND_STR("requires")},
+ {RPMTAG_RECOMMENDNAME, 0, 0, LEN_AND_STR("recommends")},
+ {RPMTAG_SUGGESTNAME, 0, 0, LEN_AND_STR("suggests")},
+ {RPMTAG_SUPPLEMENTNAME, 0, 0, LEN_AND_STR("supplements")},
+ {RPMTAG_ENHANCENAME, 0, 0, LEN_AND_STR("enhances")},
{RPMTAG_PREREQ, 2, 1, LEN_AND_STR("prereq")},
- {RPMTAG_CONFLICTFLAGS, 0, 0, LEN_AND_STR("conflicts")},
- {RPMTAG_OBSOLETEFLAGS, 0, 0, LEN_AND_STR("obsoletes")},
+ {RPMTAG_CONFLICTNAME, 0, 0, LEN_AND_STR("conflicts")},
+ {RPMTAG_OBSOLETENAME, 0, 0, LEN_AND_STR("obsoletes")},
{RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefixes")},
{RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefix")},
{RPMTAG_BUILDROOT, 0, 0, LEN_AND_STR("buildroot")},
@@ -910,18 +1028,19 @@ static struct PreambleRec_s const preambleList[] = {
{RPMTAG_DOCDIR, 0, 0, LEN_AND_STR("docdir")},
{RPMTAG_DISTTAG, 0, 0, LEN_AND_STR("disttag")},
{RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")},
- {RPMTAG_COLLECTIONS, 0, 0, LEN_AND_STR("collections")},
{RPMTAG_ORDERFLAGS, 2, 0, LEN_AND_STR("orderwithrequires")},
- {RPMTAG_SUGGESTSFLAGS, 0, 0, LEN_AND_STR("recommends")},
- {RPMTAG_SUGGESTSFLAGS, 0, 0, LEN_AND_STR("suggests")},
- {RPMTAG_ENHANCESFLAGS, 0, 0, LEN_AND_STR("supplements")},
- {RPMTAG_ENHANCESFLAGS, 0, 0, LEN_AND_STR("enhances")},
+ {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("recommends")},
+ {RPMTAG_OLDSUGGESTSFLAGS, 0, 0, LEN_AND_STR("suggests")},
+ {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("supplements")},
+ {RPMTAG_OLDENHANCESFLAGS, 0, 0, LEN_AND_STR("enhances")},
{RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildrecommends")},
{RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildsuggests")},
{RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildsupplements")},
{RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildenhances")},
{RPMTAG_SECMANIFEST, 0, 0, LEN_AND_STR("manifest")},
- {RPMTAG_BUILDINFO, 0, 0, LEN_AND_STR("buildinfo")},
+ {RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")},
+ {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")},
+ {RPMTAG_BUILDINFO, 0, 0, LEN_AND_STR("buildinfo")},
{0, 0, 0, 0}
};
@@ -995,8 +1114,6 @@ int parsePreamble(rpmSpec spec, int initialPackage)
char *NVR = NULL;
char lang[BUFSIZ];
- pkg = newPackage(spec);
-
if (! initialPackage) {
/* There is one option to %package: <pkg> or -n <pkg> */
if (parseSimplePart(spec->line, &name, &flag)) {
@@ -1004,9 +1121,11 @@ int parsePreamble(rpmSpec spec, int initialPackage)
spec->line);
goto exit;
}
+
+ //if (rpmCharCheck(spec, name, WHITELIST_NAME))
+ // goto exit;
if (!lookupPackage(spec, name, flag, NULL)) {
- rpmlog(RPMLOG_ERR, _("Package already exists: %s\n"), spec->line);
free(name);
goto exit;
}
@@ -1018,9 +1137,13 @@ int parsePreamble(rpmSpec spec, int initialPackage)
} else
NVR = xstrdup(name);
free(name);
+ pkg = newPackage(NVR, spec->pool, &spec->packages);
headerPutString(pkg->header, RPMTAG_NAME, NVR);
} else {
NVR = xstrdup("(main package)");
+ pkg = newPackage(NULL, spec->pool, &spec->packages);
+ spec->sourcePackage = newPackage(NULL, spec->pool, NULL);
+
}
if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
@@ -1037,6 +1160,14 @@ int parsePreamble(rpmSpec spec, int initialPackage)
SKIPSPACE(linep);
if (*linep != '\0') {
if (findPreambleTag(spec, &tag, &macro, lang)) {
+ if (spec->lineNum == 1 &&
+ (unsigned char)(spec->line[0]) == 0xed &&
+ (unsigned char)(spec->line[1]) == 0xab &&
+ (unsigned char)(spec->line[2]) == 0xee &&
+ (unsigned char)(spec->line[3]) == 0xdb) {
+ rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n"));
+ goto exit;
+ }
rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
spec->lineNum, spec->line);
goto exit;
@@ -1060,7 +1191,7 @@ int parsePreamble(rpmSpec spec, int initialPackage)
}
}
- /*
+ /*
* Expand buildroot one more time to get %{version} and the like
* from the main package, validate sanity. The spec->buildRoot could
* still contain unexpanded macros but it cannot be empty or '/', and it
@@ -1078,7 +1209,7 @@ int parsePreamble(rpmSpec spec, int initialPackage)
}
free(spec->buildRoot);
spec->buildRoot = buildRoot;
- addMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
+ rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
}
/* XXX Skip valid arch check if not building binary package */
@@ -1100,8 +1231,7 @@ int parsePreamble(rpmSpec spec, int initialPackage)
}
if (pkg != spec->packages) {
- headerCopyTags(spec->packages->header, pkg->header,
- (rpmTagVal *)copyTagsDuringParse);
+ copyInheritedTags(pkg->header, spec->packages->header);
}
if (checkForRequired(pkg->header, NVR)) {
diff --git a/build/parsePrep.c b/build/parsePrep.c
index fd4d30cdf..a62123e25 100644
--- a/build/parsePrep.c
+++ b/build/parsePrep.c
@@ -6,6 +6,7 @@
#include "system.h"
#include <errno.h>
+#include <libgen.h>
#include <rpm/header.h>
#include <rpm/rpmlog.h>
@@ -29,10 +30,6 @@ static rpmRC checkOwners(const char * urlfn)
urlfn, strerror(errno));
return RPMRC_FAIL;
}
- if (!rpmugUname(sb.st_uid) || !rpmugGname(sb.st_gid)) {
- rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), urlfn);
- return RPMRC_FAIL;
- }
return RPMRC_OK;
}
@@ -47,21 +44,25 @@ static rpmRC checkOwners(const char * urlfn)
* @param removeEmpties include -E?
* @param fuzz fuzz factor, fuzz<0 means no fuzz set
* @param dir dir to change to (i.e. patch -d argument)
+ * @param outfile send output to this file (i.e. patch -o argument)
* @return expanded %patch macro (NULL on error)
*/
static char *doPatch(rpmSpec spec, uint32_t c, int strip, const char *db,
- int reverse, int removeEmpties, int fuzz, const char *dir)
+ int reverse, int removeEmpties, int fuzz, const char *dir,
+ const char *outfile)
{
char *fn = NULL;
char *buf = NULL;
char *arg_backup = NULL;
char *arg_fuzz = NULL;
char *arg_dir = NULL;
+ char *arg_outfile = NULL;
char *args = NULL;
char *arg_patch_flags = rpmExpand("%{?_default_patch_flags}", NULL);
struct Source *sp;
char *patchcmd;
+ rpmCompressedMagic compressed = COMPRESSED_NOT;
for (sp = spec->sources; sp != NULL; sp = sp->next) {
if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) {
@@ -80,7 +81,7 @@ static char *doPatch(rpmSpec spec, uint32_t c, int strip, const char *db,
fn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
/* On non-build parse's, file cannot be stat'd or read. */
- if ((spec->flags & RPMSPEC_FORCE) || checkOwners(fn)) goto exit;
+ if ((spec->flags & RPMSPEC_FORCE) || rpmFileIsCompressed(fn, &compressed) || checkOwners(fn)) goto exit;
if (db) {
rasprintf(&arg_backup,
@@ -94,17 +95,28 @@ static char *doPatch(rpmSpec spec, uint32_t c, int strip, const char *db,
rasprintf(&arg_dir, " -d %s", dir);
} else arg_dir = xstrdup("");
+ if (outfile) {
+ rasprintf(&arg_outfile, " -o %s", outfile);
+ } else arg_outfile = xstrdup("");
+
if (fuzz >= 0) {
rasprintf(&arg_fuzz, " --fuzz=%d", fuzz);
} else arg_fuzz = xstrdup("");
- rasprintf(&args, "%s -p%d %s%s%s%s%s", arg_patch_flags, strip, arg_backup, arg_fuzz, arg_dir,
+ rasprintf(&args, "%s -p%d %s%s%s%s%s%s", arg_patch_flags, strip, arg_backup, arg_fuzz, arg_dir, arg_outfile,
reverse ? " -R" : "",
removeEmpties ? " -E" : "");
- patchcmd = rpmExpand("%{uncompress: ", fn, "} | %{__patch} ", args, NULL);
+ /* Avoid the extra cost of fork and pipe for uncompressed patches */
+ if (compressed != COMPRESSED_NOT) {
+ patchcmd = rpmExpand("{ %{uncompress: ", fn, "} || echo patch_fail ; } | "
+ "%{__patch} ", args, NULL);
+ } else {
+ patchcmd = rpmExpand("%{__patch} ", args, " < ", fn, NULL);
+ }
free(arg_fuzz);
+ free(arg_outfile);
free(arg_dir);
free(arg_backup);
free(args);
@@ -138,7 +150,7 @@ static char *doUntar(rpmSpec spec, uint32_t c, int quietly)
char *fn = NULL;
char *buf = NULL;
char *tar = NULL;
- const char *taropts = ((rpmIsVerbose() && !quietly) ? "-xvvf" : "-xf");
+ const char *taropts = ((rpmIsVerbose() && !quietly) ? "-xvvof" : "-xof");
struct Source *sp;
rpmCompressedMagic compressed = COMPRESSED_NOT;
@@ -167,6 +179,7 @@ static char *doUntar(rpmSpec spec, uint32_t c, int quietly)
if (compressed != COMPRESSED_NOT) {
char *zipper, *t = NULL;
int needtar = 1;
+ int needgemspec = 0;
switch (compressed) {
case COMPRESSED_NOT: /* XXX can't happen */
@@ -197,6 +210,14 @@ static char *doUntar(rpmSpec spec, uint32_t c, int quietly)
t = "%{__7zip} x";
needtar = 0;
break;
+ case COMPRESSED_ZSTD:
+ t = "%{__zstd} -dc";
+ break;
+ case COMPRESSED_GEM:
+ t = "%{__gem} unpack";
+ needtar = 0;
+ needgemspec = 1;
+ break;
}
zipper = rpmGetPath(t, NULL);
if (needtar) {
@@ -205,6 +226,22 @@ static char *doUntar(rpmSpec spec, uint32_t c, int quietly)
"if [ $STATUS -ne 0 ]; then\n"
" exit $STATUS\n"
"fi", zipper, fn, tar, taropts);
+ } else if (needgemspec) {
+ char *gem = rpmGetPath("%{__gem}", NULL);
+ char *gemspec = NULL;
+ char gemnameversion[strlen(sp->source) - 3];
+
+ rstrlcpy(gemnameversion, sp->source, strlen(sp->source) - 3);
+ gemspec = rpmGetPath("%{_builddir}/", gemnameversion, ".gemspec", NULL);
+
+ rasprintf(&buf, "%s '%s' && %s spec '%s' --ruby > '%s'\n"
+ "STATUS=$?\n"
+ "if [ $STATUS -ne 0 ]; then\n"
+ " exit $STATUS\n"
+ "fi", zipper, fn, gem, fn, gemspec);
+
+ free(gemspec);
+ free(gem);
} else {
rasprintf(&buf, "%s '%s'\n"
"STATUS=$?\n"
@@ -225,7 +262,6 @@ exit:
/**
* Parse %setup macro.
- * @todo FIXME: Option -q broken when not immediately after %setup.
* @param spec build info
* @param line current line from spec file
* @return RPMRC_OK on success
@@ -245,6 +281,7 @@ static int doSetupMacro(rpmSpec spec, const char *line)
uint32_t num;
int leaveDirs = 0, skipDefaultAction = 0;
int createDir = 0, quietly = 0;
+ int buildInPlace = 0;
const char * dirName = NULL;
struct poptOption optionsTable[] = {
{ NULL, 'a', POPT_ARG_STRING, NULL, 'a', NULL, NULL},
@@ -257,6 +294,8 @@ static int doSetupMacro(rpmSpec spec, const char *line)
{ 0, 0, 0, 0, 0, NULL, NULL}
};
+ if (strstr(line+6, " -q")) quietly = 1;
+
if ((xx = poptParseArgvString(line, &argc, &argv))) {
rpmlog(RPMLOG_ERR, _("Error parsing %%setup: %s\n"), poptStrerror(xx));
goto exit;
@@ -298,7 +337,16 @@ static int doSetupMacro(rpmSpec spec, const char *line)
headerGetString(spec->packages->header, RPMTAG_NAME),
headerGetString(spec->packages->header, RPMTAG_VERSION));
}
- addMacro(spec->macros, "buildsubdir", NULL, spec->buildSubdir, RMIL_SPEC);
+ /* Mer addition - support --build-in-place */
+ if (rpmExpandNumeric("%{_build_in_place}")) {
+ buildInPlace = 1;
+ spec->buildSubdir = NULL;
+ }
+ rpmPushMacro(spec->macros, "buildsubdir", NULL, spec->buildSubdir, RMIL_SPEC);
+ if (buildInPlace) {
+ rc = RPMRC_OK;
+ goto exit;
+ }
/* cd to the build dir */
{ char * buildDir = rpmGenPath(spec->rootDir, "%{_builddir}", "");
@@ -316,6 +364,8 @@ static int doSetupMacro(rpmSpec spec, const char *line)
free(buf);
}
+ appendStringBuf(spec->prep, getStringBuf(before));
+
/* if necessary, create and cd into the proper dir */
if (createDir) {
buf = rpmExpand("%{__mkdir_p} ", spec->buildSubdir, "\n",
@@ -333,8 +383,6 @@ static int doSetupMacro(rpmSpec spec, const char *line)
free(chptr);
}
- appendStringBuf(spec->prep, getStringBuf(before));
-
if (!createDir) {
rasprintf(&buf, "cd '%s'", spec->buildSubdir);
appendLineStringBuf(spec->prep, buf);
@@ -372,12 +420,12 @@ exit:
/**
* Parse %patch line.
* This supports too many crazy syntaxes:
- * - %patchN is equal to %patch -P<N>
- * - -P<N> -P<N+1>... can be used to apply several patch on a single line
+ * - %patchN is equal to %patch -P\<N\>
+ * - -P\<N\> -P\<N+1\>... can be used to apply several patch on a single line
* - Any trailing arguments are treated as patch numbers
* - Any combination of the above, except unless at least one -P is specified,
- * %patch is treated as %patch -P0 so that "%patch 1" is actually
- * equal to "%patch -P0 -P1".
+ * %patch is treated as "numberless patch" so that "%patch 1" actually tries
+ * to pull in numberless "Patch:" and numbered "Patch1:".
*
* @param spec build info
* @param line current line from spec file
@@ -385,7 +433,7 @@ exit:
*/
static rpmRC doPatchMacro(rpmSpec spec, const char *line)
{
- char *opt_b, *opt_P, *opt_d;
+ char *opt_b, *opt_P, *opt_d, *opt_o;
char *buf = NULL;
int opt_p, opt_R, opt_E, opt_F;
int argc, c;
@@ -402,13 +450,14 @@ static rpmRC doPatchMacro(rpmSpec spec, const char *line)
{ NULL, 'z', POPT_ARG_STRING, &opt_b, 'z', NULL, NULL },
{ NULL, 'F', POPT_ARG_INT, &opt_F, 'F', NULL, NULL },
{ NULL, 'd', POPT_ARG_STRING, &opt_d, 'd', NULL, NULL },
+ { NULL, 'o', POPT_ARG_STRING, &opt_o, 'o', NULL, NULL },
{ NULL, 0, 0, NULL, 0, NULL, NULL }
};
poptContext optCon = NULL;
opt_p = opt_R = opt_E = 0;
opt_F = rpmExpandNumeric("%{_default_patch_fuzz}"); /* get default fuzz factor for %patch */
- opt_b = opt_d = NULL;
+ opt_b = opt_d = opt_o = NULL;
/* Convert %patchN to %patch -PN to simplify further processing */
if (! strchr(" \t\n", line[6])) {
@@ -460,7 +509,7 @@ static rpmRC doPatchMacro(rpmSpec spec, const char *line)
*patch, line);
goto exit;
}
- s = doPatch(spec, pnum, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d);
+ s = doPatch(spec, pnum, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d, opt_o);
if (s == NULL) {
goto exit;
}
diff --git a/build/parseReqs.c b/build/parseReqs.c
index 1507090d3..4d7e8e8bf 100644
--- a/build/parseReqs.c
+++ b/build/parseReqs.c
@@ -12,119 +12,230 @@
#include "build/rpmbuild_misc.h"
#include "debug.h"
-/**
- */
-static struct ReqComp {
-const char * token;
- rpmsenseFlags sense;
-} const ReqComparisons[] = {
- { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
- { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
- { "<", RPMSENSE_LESS},
-
- { "==", RPMSENSE_EQUAL},
- { "=", RPMSENSE_EQUAL},
-
- { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
- { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
- { ">", RPMSENSE_GREATER},
-
- { NULL, 0 },
+
+#define SKIPWHITE(_x) {while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
+#define SKIPNONWHITE(_x){while (*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+
+static rpmRC checkSep(const char *s, char c, char **emsg)
+{
+ const char *sep = strchr(s, c);
+ if (sep && strchr(sep + 1, c)) {
+ rasprintf(emsg, "Invalid version (double separator '%c'): %s", c, s);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
+static rpmRC checkEpoch(const char *s, char **emsg)
+{
+ const char *si, *sep = strchr(s, ':');
+
+ if (!sep)
+ return RPMRC_OK;
+
+ for (si = s; si != sep; si++) {
+ if (!risdigit(*si)) {
+ rasprintf(emsg, "Invalid version (epoch must be unsigned integer): %s", s);
+ return RPMRC_FAIL;
+ }
+ }
+ return RPMRC_OK;
+}
+
+static rpmRC checkDep(rpmSpec spec, char *N, char *EVR, char **emsg)
+{
+ /*
+ * Tokens must begin with alphanumeric, _, or /, but we don't know
+ * the spec's encoding so we only check what we can: plain ascii.
+ */
+ if (isascii(N[0]) && !(risalnum(N[0]) || N[0] == '_' || N[0] == '/')) {
+ rasprintf(emsg, _("Dependency tokens must begin with alpha-numeric, '_' or '/'"));
+ return RPMRC_FAIL;
+ }
+ if (EVR) {
+ if (N[0] == '/') {
+ rasprintf(emsg, _("Versioned file name not permitted"));
+ return RPMRC_FAIL;
+ }
+ // if (rpmCharCheck(spec, EVR, ".-_+:%{}~"))
+ // return RPMRC_FAIL;
+ if (checkSep(EVR, '-', emsg) != RPMRC_OK ||
+ checkSep(EVR, ':', emsg) != RPMRC_OK ||
+ checkEpoch(EVR, emsg) != RPMRC_OK) {
+
+ if (rpmExpandNumeric("%{?_wrong_version_format_terminate_build}"))
+ return RPMRC_FAIL;
+ }
+ }
+ return RPMRC_OK;
+}
+
+struct parseRCPOTRichData {
+ rpmSpec spec;
+ StringBuf sb;
};
-#define SKIPWHITE(_x) {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
-#define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+/* Callback for the rich dependency parser. We use this to do check for invalid
+ * characters and to build a normailzed version of the dependency */
+static rpmRC parseRCPOTRichCB(void *cbdata, rpmrichParseType type,
+ const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
+ rpmrichOp op, char **emsg) {
+ struct parseRCPOTRichData *data = cbdata;
+ StringBuf sb = data->sb;
+ rpmRC rc = RPMRC_OK;
+
+ if (type == RPMRICH_PARSE_ENTER) {
+ appendStringBuf(sb, "(");
+ } else if (type == RPMRICH_PARSE_LEAVE) {
+ appendStringBuf(sb, ")");
+ } else if (type == RPMRICH_PARSE_SIMPLE) {
+ char *N = xmalloc(nl + 1);
+ char *EVR = NULL;
+ rstrlcpy(N, n, nl + 1);
+ appendStringBuf(sb, N);
+ if (el) {
+ char rel[6], *rp = rel;
+ EVR = xmalloc(el + 1);
+ rstrlcpy(EVR, e, el + 1);
+ *rp++ = ' ';
+ if (sense & RPMSENSE_LESS)
+ *rp++ = '<';
+ if (sense & RPMSENSE_GREATER)
+ *rp++ = '>';
+ if (sense & RPMSENSE_EQUAL)
+ *rp++ = '=';
+ *rp++ = ' ';
+ *rp = 0;
+ appendStringBuf(sb, rel);
+ appendStringBuf(sb, EVR);
+ }
+ rc = checkDep(data->spec, N, EVR, emsg);
+ _free(N);
+ _free(EVR);
+ } else if (type == RPMRICH_PARSE_OP) {
+ appendStringBuf(sb, " ");
+ appendStringBuf(sb, rpmrichOpStr(op));
+ appendStringBuf(sb, " ");
+ }
+ return rc;
+}
rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
- int index, rpmsenseFlags tagflags)
+ int index, rpmsenseFlags tagflags, addReqProvFunction cb, void *cbdata)
{
- const char *r, *re, *v, *ve;
- const char *emsg = NULL;
- char * N = NULL, * EVR = NULL;
- rpmTagVal nametag = RPMTAG_NOT_FOUND;
- rpmsenseFlags Flags;
- Header h = pkg->header; /* everything except buildrequires go here */
- rpmRC rc = RPMRC_FAIL; /* assume failure */
-
- switch (tagN) {
- default:
- case RPMTAG_REQUIREFLAGS:
- nametag = RPMTAG_REQUIRENAME;
+ const char *r, *re, *v, *ve;
+ char *emsg = NULL;
+ char * N = NULL, * EVR = NULL;
+ rpmTagVal nametag = RPMTAG_NOT_FOUND;
+ rpmsenseFlags Flags;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ int allow_richdeps = 0;
+
+ if (!cbdata)
+ cbdata = pkg;
+
+ switch (tagN) {
+ default:
+ case RPMTAG_REQUIRENAME:
tagflags |= RPMSENSE_ANY;
+ /* fall through */
+ case RPMTAG_RECOMMENDNAME:
+ case RPMTAG_SUGGESTNAME:
+ case RPMTAG_SUPPLEMENTNAME:
+ case RPMTAG_ENHANCENAME:
+ case RPMTAG_CONFLICTNAME:
+ allow_richdeps = 1;
+ /* fall through */
+ case RPMTAG_PROVIDENAME:
+ case RPMTAG_OBSOLETENAME:
+ case RPMTAG_ORDERNAME:
+ nametag = tagN;
break;
- case RPMTAG_PROVIDEFLAGS:
- nametag = RPMTAG_PROVIDENAME;
- break;
- case RPMTAG_OBSOLETEFLAGS:
- nametag = RPMTAG_OBSOLETENAME;
- break;
- case RPMTAG_CONFLICTFLAGS:
- nametag = RPMTAG_CONFLICTNAME;
- break;
- case RPMTAG_ORDERFLAGS:
- nametag = RPMTAG_ORDERNAME;
- break;
- case RPMTAG_PREREQ:
+ case RPMTAG_PREREQ:
/* XXX map legacy PreReq into Requires(pre,preun) */
nametag = RPMTAG_REQUIRENAME;
tagflags |= (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_PREUN);
+ allow_richdeps = 1;
break;
- case RPMTAG_TRIGGERPREIN:
+ case RPMTAG_TRIGGERPREIN:
nametag = RPMTAG_TRIGGERNAME;
tagflags |= RPMSENSE_TRIGGERPREIN;
break;
- case RPMTAG_TRIGGERIN:
+ case RPMTAG_TRIGGERIN:
nametag = RPMTAG_TRIGGERNAME;
tagflags |= RPMSENSE_TRIGGERIN;
break;
- case RPMTAG_TRIGGERPOSTUN:
+ case RPMTAG_TRIGGERPOSTUN:
nametag = RPMTAG_TRIGGERNAME;
tagflags |= RPMSENSE_TRIGGERPOSTUN;
break;
- case RPMTAG_TRIGGERUN:
+ case RPMTAG_TRIGGERUN:
nametag = RPMTAG_TRIGGERNAME;
tagflags |= RPMSENSE_TRIGGERUN;
break;
- case RPMTAG_BUILDPREREQ:
- case RPMTAG_BUILDREQUIRES:
+ case RPMTAG_BUILDPREREQ:
+ case RPMTAG_BUILDREQUIRES:
nametag = RPMTAG_REQUIRENAME;
tagflags |= RPMSENSE_ANY;
- h = spec->buildRestrictions;
+ allow_richdeps = 1;
break;
- case RPMTAG_BUILDCONFLICTS:
+ case RPMTAG_BUILDCONFLICTS:
nametag = RPMTAG_CONFLICTNAME;
- h = spec->buildRestrictions;
+ allow_richdeps = 1;
break;
- case RPMTAG_SUGGESTSFLAGS:
- nametag = RPMTAG_SUGGESTSNAME;
+ case RPMTAG_FILETRIGGERIN:
+ nametag = RPMTAG_FILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERIN;
break;
- case RPMTAG_ENHANCESFLAGS:
- nametag = RPMTAG_ENHANCESNAME;
+ case RPMTAG_FILETRIGGERUN:
+ nametag = RPMTAG_FILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERUN;
break;
- case RPMTAG_BUILDSUGGESTS:
- nametag = RPMTAG_SUGGESTSNAME;
- h = spec->buildRestrictions;
+ case RPMTAG_FILETRIGGERPOSTUN:
+ nametag = RPMTAG_FILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERPOSTUN;
break;
- case RPMTAG_BUILDENHANCES:
- nametag = RPMTAG_ENHANCESNAME;
- h = spec->buildRestrictions;
+ case RPMTAG_TRANSFILETRIGGERIN:
+ nametag = RPMTAG_TRANSFILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERIN;
break;
- }
+ case RPMTAG_TRANSFILETRIGGERUN:
+ nametag = RPMTAG_TRANSFILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERUN;
+ break;
+ case RPMTAG_TRANSFILETRIGGERPOSTUN:
+ nametag = RPMTAG_TRANSFILETRIGGERNAME;
+ tagflags |= RPMSENSE_TRIGGERPOSTUN;
+ break;
+ }
- for (r = field; *r != '\0'; r = re) {
+ for (r = field; *r != '\0'; r = re) {
SKIPWHITE(r);
if (*r == '\0')
- break;
+ break;
Flags = (tagflags & ~RPMSENSE_SENSEMASK);
- /*
- * Tokens must begin with alphanumeric, _, or /, but we don't know
- * the spec's encoding so we only check what we can: plain ascii.
- */
- if (isascii(r[0]) && !(risalnum(r[0]) || r[0] == '_' || r[0] == '/')) {
- emsg = _("Dependency tokens must begin with alpha-numeric, '_' or '/'");
- goto exit;
+ if (r[0] == '(') {
+ struct parseRCPOTRichData data;
+ if (!allow_richdeps) {
+ rasprintf(&emsg, _("No rich dependencies allowed for this type"));
+ goto exit;
+ }
+ data.spec = spec;
+ data.sb = newStringBuf();
+ if (rpmrichParseForTag(&r, &emsg, parseRCPOTRichCB, &data, nametag) != RPMRC_OK) {
+ freeStringBuf(data.sb);
+ goto exit;
+ }
+ if (cb && cb(cbdata, nametag, getStringBuf(data.sb), NULL, Flags, index) != RPMRC_OK) {
+ rasprintf(&emsg, _("invalid dependency"));
+ freeStringBuf(data.sb);
+ goto exit;
+ }
+ freeStringBuf(data.sb);
+ re = r;
+ continue;
}
re = r;
@@ -133,71 +244,106 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
rstrlcpy(N, r, (re-r) + 1);
/* Parse EVR */
+ EVR = NULL;
v = re;
SKIPWHITE(v);
ve = v;
SKIPNONWHITE(ve);
- re = v; /* ==> next token (if no EVR found) starts here */
+ re = v; /* ==> next token (if no EVR found) starts here */
/* Check for possible logical operator */
if (ve > v) {
- const struct ReqComp *rc;
- for (rc = ReqComparisons; rc->token != NULL; rc++) {
- if ((ve-v) != strlen(rc->token) || !rstreqn(v, rc->token, (ve-v)))
- continue;
+ rpmsenseFlags sense = rpmParseDSFlags(v, ve - v);
+ if (sense) {
+ Flags |= sense;
+
+ /* now parse EVR */
+ v = ve;
+ SKIPWHITE(v);
+ ve = v;
+ SKIPNONWHITE(ve);
+ if (*v == '\0' || ve == v) {
+ rasprintf(&emsg, _("Version required"));
+ goto exit;
+ }
+ EVR = xmalloc((ve-v) + 1);
+ rstrlcpy(EVR, v, (ve-v) + 1);
+ re = ve; /* ==> next token after EVR string starts here */
+ }
+ }
- if (r[0] == '/') {
- emsg = _("Versioned file name not permitted");
+ /* check that dependency is well-formed */
+ if (checkDep(spec, N, EVR, &emsg))
goto exit;
- }
- Flags |= rc->sense;
+ if (nametag == RPMTAG_OBSOLETENAME) {
+ if (rpmCharCheck(spec, N, WHITELIST_NAME)) {
+ rasprintf(&emsg, _("Only package names are allowed in "
+ "Obsoletes"));
+ goto exit;
+ }
+ if (!EVR) {
+ rasprintf(&emsg, _("It's not recommended to have "
+ "unversioned Obsoletes"));
+ } else if (Flags & RPMSENSE_GREATER) {
+ rasprintf(&emsg, _("It's not recommended to use "
+ "'>' in Obsoletes"));
+ }
+ }
- /* now parse EVR */
- v = ve;
- SKIPWHITE(v);
- ve = v;
- SKIPNONWHITE(ve);
- break;
- }
+ if (nametag == RPMTAG_FILETRIGGERNAME ||
+ nametag == RPMTAG_TRANSFILETRIGGERNAME) {
+ if (N[0] != '/') {
+ rasprintf(&emsg, _("Only absolute paths are allowed in "
+ "file triggers"));
+ }
}
- if (Flags & RPMSENSE_SENSEMASK) {
- if (*v == '\0' || ve == v) {
- emsg = _("Version required");
+
+ /* Deny more "normal" triggers fired by the same pakage. File triggers are ok */
+ if (nametag == RPMTAG_TRIGGERNAME) {
+ rpmds *pdsp = packageDependencies(pkg, nametag);
+ rpmds newds = rpmdsSingle(nametag, N, EVR, Flags);
+ rpmdsInit(*pdsp);
+ while (rpmdsNext(*pdsp) >= 0) {
+ if (rpmdsCompare(*pdsp, newds) && (rpmdsFlags(*pdsp) & tagflags )) {
+ rasprintf(&emsg, _("Trigger fired by the same package "
+ "is already defined in spec file"));
+ break;
+ }
+ }
+ rpmdsFree(newds);
+ if (emsg)
+ goto exit;
+ }
+
+ if (cb && cb(cbdata, nametag, N, EVR, Flags, index) != RPMRC_OK) {
+ rasprintf(&emsg, _("invalid dependency"));
goto exit;
- }
- EVR = xmalloc((ve-v) + 1);
- rstrlcpy(EVR, v, (ve-v) + 1);
- if (rpmCharCheck(spec, EVR, ve-v, ".-_+:%{}~")) goto exit;
- re = ve; /* ==> next token after EVR string starts here */
- } else
- EVR = NULL;
-
- if (addReqProv(h, nametag, N, EVR, Flags, index)) {
- emsg = _("invalid dependency");
- goto exit;
}
N = _free(N);
EVR = _free(EVR);
- }
- rc = RPMRC_OK;
+ }
+ rc = RPMRC_OK;
exit:
- if (emsg) {
+ if (emsg) {
+ int lvl = (rc == RPMRC_OK) ? RPMLOG_WARNING : RPMLOG_ERR;
/* Automatic dependencies don't relate to spec lines */
if (tagflags & (RPMSENSE_FIND_REQUIRES|RPMSENSE_FIND_PROVIDES)) {
- rpmlog(RPMLOG_ERR, "%s: %s\n", emsg, r);
+ rpmlog(lvl, "%s: %s\n", emsg, r);
} else {
- rpmlog(RPMLOG_ERR, _("line %d: %s: %s\n"),
+ rpmlog(lvl, _("line %d: %s: %s\n"),
spec->lineNum, emsg, spec->line);
}
- }
- free(N);
- free(EVR);
+ free(emsg);
+ }
+ _free(N);
+ _free(EVR);
- return rc;
+ return rc;
}
+
diff --git a/build/parseScript.c b/build/parseScript.c
index 1a149e137..bd0c2f072 100644
--- a/build/parseScript.c
+++ b/build/parseScript.c
@@ -15,16 +15,29 @@
#include "debug.h"
+#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
/**
*/
static int addTriggerIndex(Package pkg, const char *file,
- const char *script, const char *prog, rpmscriptFlags flags)
+ const char *script, const char *prog, rpmscriptFlags flags,
+ rpmTagVal tag, uint32_t priority)
{
struct TriggerFileEntry *tfe;
- struct TriggerFileEntry *list = pkg->triggerFiles;
+ struct TriggerFileEntry *list;
struct TriggerFileEntry *last = NULL;
int index = 0;
+ struct TriggerFileEntry **tfp;
+
+ if (tag == RPMTAG_FILETRIGGERSCRIPTS) {
+ tfp = &pkg->fileTriggerFiles;
+ } else if (tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) {
+ tfp = &pkg->transFileTriggerFiles;
+ } else {
+ tfp = &pkg->triggerFiles;
+ }
+
+ list = *tfp;
while (list) {
last = list;
@@ -41,12 +54,13 @@ static int addTriggerIndex(Package pkg, const char *file,
tfe->prog = xstrdup(prog);
tfe->flags = flags;
tfe->index = index;
+ tfe->priority = priority;
tfe->next = NULL;
if (last)
last->next = tfe;
else
- pkg->triggerFiles = tfe;
+ *tfp = tfe;
return index;
}
@@ -90,6 +104,7 @@ int parseScript(rpmSpec spec, int parsePart)
const char *name = NULL;
const char *prog = "/bin/sh";
const char *file = NULL;
+ int priority = 1000000;
struct poptOption optionsTable[] = {
{ NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL},
{ NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
@@ -98,6 +113,7 @@ int parseScript(rpmSpec spec, int parsePart)
NULL, NULL},
{ NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT,
NULL, NULL},
+ { NULL, 'P', POPT_ARG_INT, &priority, 'P', NULL, NULL},
{ 0, 0, 0, 0, 0, NULL, NULL}
};
@@ -183,19 +199,82 @@ int parseScript(rpmSpec spec, int parsePart)
flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
partname = "%triggerpostun";
break;
+ case PART_FILETRIGGERIN:
+ tag = RPMTAG_FILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_FILETRIGGERIN;
+ progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
+ partname = "%filetriggerin";
+ break;
+ case PART_FILETRIGGERUN:
+ tag = RPMTAG_FILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_FILETRIGGERUN;
+ progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
+ partname = "%filetriggerun";
+ break;
+ case PART_FILETRIGGERPOSTUN:
+ tag = RPMTAG_FILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_FILETRIGGERPOSTUN;
+ progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
+ partname = "%filetriggerpostun";
+ break;
+ case PART_TRANSFILETRIGGERIN:
+ tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRANSFILETRIGGERIN;
+ progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
+ partname = "%transfiletriggerin";
+ break;
+ case PART_TRANSFILETRIGGERUN:
+ tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRANSFILETRIGGERUN;
+ progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
+ partname = "%transfiletriggerun";
+ break;
+ case PART_TRANSFILETRIGGERPOSTUN:
+ tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
+ tagflags = 0;
+ reqtag = RPMTAG_TRANSFILETRIGGERPOSTUN;
+ progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
+ flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
+ partname = "%transfiletriggerpostun";
+ break;
}
- if (tag == RPMTAG_TRIGGERSCRIPTS) {
- /* break line into two */
- char *s = strstr(spec->line, "--");
- if (!s) {
+ if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS ||
+ tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) {
+ /* break line into two at the -- separator */
+ char *sep, *s = spec->line;
+ while ((s = strstr(s, "--")) != NULL) {
+ s += 2;
+ if (risblank(*(s-3)) && risblank(*s))
+ break;
+ }
+
+ if (s == NULL) {
rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
spec->lineNum, spec->line);
- return PART_ERROR;
+ goto exit;
+ }
+
+ sep = s;
+ SKIPSPACE(s);
+ if (*s == '\0') {
+ rpmlog(RPMLOG_ERR, _("line %d: missing trigger condition: %s\n"),
+ spec->lineNum, spec->line);
+ goto exit;
}
- *s = '\0';
- reqargs = xstrdup(s + 2);
+ *sep = '\0';
+ reqargs = xstrdup(s);
}
if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
@@ -225,9 +304,19 @@ int parseScript(rpmSpec spec, int parsePart)
case 'n':
flag = PART_NAME;
break;
+ case 'P':
+ if (tag != RPMTAG_TRIGGERSCRIPTS &&
+ tag != RPMTAG_FILETRIGGERSCRIPTS &&
+ tag != RPMTAG_TRANSFILETRIGGERSCRIPTS) {
+
+ rpmlog(RPMLOG_ERR,
+ _("line %d: Priorities are allowed only for file "
+ "triggers : %s\n"), spec->lineNum, prog);
+ goto exit;
+ }
}
}
-
+
if (arg < -1) {
rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
spec->lineNum,
@@ -247,11 +336,8 @@ int parseScript(rpmSpec spec, int parsePart)
}
}
- if (lookupPackage(spec, name, flag, &pkg)) {
- rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
- spec->lineNum, spec->line);
+ if (lookupPackage(spec, name, flag, &pkg))
goto exit;
- }
if (tag != RPMTAG_TRIGGERSCRIPTS) {
if (headerIsEntry(pkg->header, progtag)) {
@@ -292,8 +378,7 @@ int parseScript(rpmSpec spec, int parsePart)
if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
goto exit;
}
- (void) rpmlibNeedsFeature(pkg->header,
- "BuiltinLuaScripts", "4.2.2-1");
+ (void) rpmlibNeedsFeature(pkg, "BuiltinLuaScripts", "4.2.2-1");
} else
#endif
if (progArgv[0][0] == '<') {
@@ -302,17 +387,24 @@ int parseScript(rpmSpec spec, int parsePart)
spec->lineNum, progArgv[0]);
goto exit;
} else {
- (void) addReqProv(pkg->header, RPMTAG_REQUIRENAME,
+ (void) addReqProv(pkg, RPMTAG_REQUIRENAME,
progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
}
if (scriptFlags) {
- rpmlibNeedsFeature(pkg->header, "ScriptletExpansion", "4.9.0-1");
+ rpmlibNeedsFeature(pkg, "ScriptletExpansion", "4.9.0-1");
}
/* Trigger script insertion is always delayed in order to */
/* get the index right. */
- if (tag == RPMTAG_TRIGGERSCRIPTS) {
+ if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS ||
+ tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) {
+ if (tag != RPMTAG_TRIGGERSCRIPTS && *reqargs != '/') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: file trigger condition must begin with '/': %s"),
+ spec->lineNum, reqargs);
+ goto exit;
+ }
if (progArgc > 1) {
rpmlog(RPMLOG_ERR,
_("line %d: interpreter arguments not allowed in triggers: %s\n"),
@@ -320,10 +412,11 @@ int parseScript(rpmSpec spec, int parsePart)
goto exit;
}
/* Add file/index/prog triple to the trigger file list */
- index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags);
+ index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags, tag,
+ priority);
/* Generate the trigger tags */
- if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags))
+ if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags, addReqProvPkg, NULL))
goto exit;
} else {
struct rpmtd_s td;
@@ -339,7 +432,7 @@ int parseScript(rpmSpec spec, int parsePart)
td.data = (void *) *progArgv;
td.type = RPM_STRING_TYPE;
} else {
- (void) rpmlibNeedsFeature(pkg->header,
+ (void) rpmlibNeedsFeature(pkg,
"ScriptletInterpreterArgs", "4.0.3-1");
td.data = progArgv;
td.type = RPM_STRING_ARRAY_TYPE;
diff --git a/build/parseSpec.c b/build/parseSpec.c
index 729d4fad9..d0c42a43e 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -6,6 +6,9 @@
#include "system.h"
#include <errno.h>
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
#include <rpm/rpmtypes.h>
#include <rpm/rpmlib.h> /* RPM_MACHTABLE & related */
@@ -28,7 +31,8 @@ typedef struct OpenFileInfo {
char * fileName;
FILE *fp;
int lineNum;
- char readBuf[BUFSIZ];
+ char *readBuf;
+ size_t readBufLen;
const char * readPtr;
struct OpenFileInfo * next;
} OFI_t;
@@ -60,6 +64,16 @@ static const struct PartRec {
{ PART_TRIGGERIN, LEN_AND_STR("%trigger")},
{ PART_VERIFYSCRIPT, LEN_AND_STR("%verifyscript")},
{ PART_POLICIES, LEN_AND_STR("%sepolicy")},
+ { PART_FILETRIGGERIN, LEN_AND_STR("%filetriggerin")},
+ { PART_FILETRIGGERIN, LEN_AND_STR("%filetrigger")},
+ { PART_FILETRIGGERUN, LEN_AND_STR("%filetriggerun")},
+ { PART_FILETRIGGERPOSTUN, LEN_AND_STR("%filetriggerpostun")},
+ { PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletriggerin")},
+ { PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletrigger")},
+ { PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")},
+ { PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")},
+ { PART_TRANSFILETRIGGERPOSTUN, LEN_AND_STR("%transfiletriggerpostun")},
+ { PART_EMPTY, LEN_AND_STR("%end")},
{0, 0, 0}
};
@@ -102,11 +116,14 @@ static int matchTok(const char *token, const char *line)
return rc;
}
-void handleComments(char *s)
+int handleComments(char *s)
{
SKIPSPACE(s);
- if (*s == '#')
+ if (*s == '#') {
*s = '\0';
+ return 1;
+ }
+ return 0;
}
/* Push a file to spec's file stack, return the newly pushed entry */
@@ -117,6 +134,8 @@ static OFI_t * pushOFI(rpmSpec spec, const char *fn)
ofi->fp = NULL;
ofi->fileName = xstrdup(fn);
ofi->lineNum = 0;
+ ofi->readBufLen = BUFSIZ;
+ ofi->readBuf = xmalloc(ofi->readBufLen);
ofi->readBuf[0] = '\0';
ofi->readPtr = NULL;
ofi->next = spec->fileStack;
@@ -135,6 +154,7 @@ static OFI_t * popOFI(rpmSpec spec)
if (ofi->fp)
fclose(ofi->fp);
free(ofi->fileName);
+ free(ofi->readBuf);
free(ofi);
}
return spec->fileStack;
@@ -151,8 +171,57 @@ static int restoreFirstChar(rpmSpec spec)
return 0;
}
+static int expandMacrosInSpecBuf(rpmSpec spec, int strip)
+{
+ char *lbuf = NULL;
+ int isComment = 0;
+
+ /* Don't expand macros (eg. %define) in false branch of %if clause */
+ if (!spec->readStack->reading)
+ return 0;
+
+ lbuf = spec->lbuf;
+ SKIPSPACE(lbuf);
+ if (lbuf[0] == '#')
+ isComment = 1;
+
+
+ if (rpmExpandMacros(spec->macros, spec->lbuf, &lbuf, 0) < 0) {
+ rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
+ spec->lineNum, spec->lbuf);
+ return 1;
+ }
+
+ if (strip & STRIP_COMMENTS && isComment) {
+ char *bufA = spec->lbuf;
+ char *bufB = lbuf;
+
+ while (*bufA != '\0' && *bufB != '\0') {
+ if (*bufA == '%' && *(bufA + 1) == '%')
+ bufA++;
+
+ if (*bufA != *bufB)
+ break;
+
+ bufA++;
+ bufB++;
+ }
+
+ if (*bufA != '\0' || *bufB != '\0')
+ rpmlog(RPMLOG_WARNING,
+ _("Macro expanded in comment on line %d: %s\n"),
+ spec->lineNum, bufA);
+ }
+
+ free(spec->lbuf);
+ spec->lbuf = lbuf;
+ spec->lbufSize = strlen(spec->lbuf) + 1;
+
+ return 0;
+}
+
/* Return zero on success, 1 if we need to read more and -1 on errors. */
-static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
+static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi, int strip)
{
/* Expand next line from file into line buffer */
if (!(spec->nextline && *spec->nextline)) {
@@ -203,13 +272,9 @@ static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
}
spec->lbufOff = 0;
- /* Don't expand macros (eg. %define) in false branch of %if clause */
- if (spec->readStack->reading &&
- expandMacros(spec, spec->macros, spec->lbuf, spec->lbufSize)) {
- rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
- spec->lineNum, spec->lbuf);
- return -1;
- }
+ if (expandMacrosInSpecBuf(spec, strip))
+ return -1;
+
spec->nextline = spec->lbuf;
}
return 0;
@@ -258,7 +323,7 @@ retry:
/* Make sure we have something in the read buffer */
if (!(ofi->readPtr && *(ofi->readPtr))) {
- if (!fgets(ofi->readBuf, BUFSIZ, ofi->fp)) {
+ if (getline(&ofi->readBuf, &ofi->readBufLen, ofi->fp) <= 0) {
/* EOF, remove this file from the stack */
ofi = popOFI(spec);
@@ -280,8 +345,8 @@ retry:
do { \
char *os = s; \
char *exp = rpmExpand(token, NULL); \
- while(*s && !risblank(*s)) s++; \
- while(*s && risblank(*s)) s++; \
+ while (*s && !risblank(*s)) s++; \
+ while (*s && risblank(*s)) s++; \
if (!*s) { \
rpmlog(RPMLOG_ERR, _("%s:%d: Argument expected for %s\n"), ofi->fileName, ofi->lineNum, os); \
free(exp); \
@@ -319,7 +384,7 @@ int readLine(rpmSpec spec, int strip)
ofi = spec->fileStack;
/* Copy next file line into the spec line buffer */
- rc = copyNextLineFromOFI(spec, ofi);
+ rc = copyNextLineFromOFI(spec, ofi, strip);
if (rc > 0) {
if (startLine == 0)
startLine = spec->lineNum;
@@ -349,7 +414,7 @@ int readLine(rpmSpec spec, int strip)
match = !match;
} else if (ISMACROWITHARG(s, "%if")) {
s += 3;
- match = parseExpressionBoolean(spec, s);
+ match = parseExpressionBoolean(s);
if (match < 0) {
rpmlog(RPMLOG_ERR,
_("%s:%d: bad %%if condition\n"),
@@ -385,10 +450,13 @@ int readLine(rpmSpec spec, int strip)
fileName = s+8;
SKIPSPACE(fileName);
endFileName = fileName;
- SKIPNONSPACE(endFileName);
- p = endFileName;
- SKIPSPACE(p);
- if (*fileName == '\0' || *p != '\0') {
+ do {
+ SKIPNONSPACE(endFileName);
+ p = endFileName;
+ SKIPSPACE(p);
+ if (*p != '\0') endFileName = p;
+ } while (*p != '\0');
+ if (*fileName == '\0') {
rpmlog(RPMLOG_ERR, _("%s:%d: malformed %%include statement\n"),
ofi->fileName, ofi->lineNum);
return PART_ERROR;
@@ -453,22 +521,26 @@ static const rpmTagVal sourceTags[] = {
static void initSourceHeader(rpmSpec spec)
{
+ Package sourcePkg = spec->sourcePackage;
struct Source *srcPtr;
- if (spec->sourceHeader)
+ if (headerIsEntry(sourcePkg->header, RPMTAG_NAME))
return;
- spec->sourceHeader = headerNew();
/* Only specific tags are added to the source package header */
- headerCopyTags(spec->packages->header, spec->sourceHeader, sourceTags);
+ headerCopyTags(spec->packages->header, sourcePkg->header, sourceTags);
/* Add the build restrictions */
+ for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
+ rpmdsPutToHeader(sourcePkg->dependencies[i], sourcePkg->header);
+ }
+
{
HeaderIterator hi = headerInitIterator(spec->buildRestrictions);
struct rpmtd_s td;
while (headerNext(hi, &td)) {
if (rpmtdCount(&td) > 0) {
- (void) headerPut(spec->sourceHeader, &td, HEADERPUT_DEFAULT);
+ (void) headerPut(sourcePkg->header, &td, HEADERPUT_DEFAULT);
}
rpmtdFreeData(&td);
}
@@ -476,23 +548,23 @@ static void initSourceHeader(rpmSpec spec)
}
if (spec->BANames && spec->BACount > 0) {
- headerPutStringArray(spec->sourceHeader, RPMTAG_BUILDARCHS,
+ headerPutStringArray(sourcePkg->header, RPMTAG_BUILDARCHS,
spec->BANames, spec->BACount);
}
/* Add tags for sources and patches */
for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
if (srcPtr->flags & RPMBUILD_ISSOURCE) {
- headerPutString(spec->sourceHeader, RPMTAG_SOURCE, srcPtr->source);
+ headerPutString(sourcePkg->header, RPMTAG_SOURCE, srcPtr->source);
if (srcPtr->flags & RPMBUILD_ISNO) {
- headerPutUint32(spec->sourceHeader, RPMTAG_NOSOURCE,
+ headerPutUint32(sourcePkg->header, RPMTAG_NOSOURCE,
&srcPtr->num, 1);
}
}
if (srcPtr->flags & RPMBUILD_ISPATCH) {
- headerPutString(spec->sourceHeader, RPMTAG_PATCH, srcPtr->source);
+ headerPutString(sourcePkg->header, RPMTAG_PATCH, srcPtr->source);
if (srcPtr->flags & RPMBUILD_ISNO) {
- headerPutUint32(spec->sourceHeader, RPMTAG_NOPATCH,
+ headerPutUint32(sourcePkg->header, RPMTAG_NOPATCH,
&srcPtr->num, 1);
}
}
@@ -500,19 +572,17 @@ static void initSourceHeader(rpmSpec spec)
}
/* Add extra provides to package. */
-static void addPackageProvides(Header h)
+void addPackageProvides(Package pkg)
{
const char *arch, *name;
char *evr, *isaprov;
rpmsenseFlags pflags = RPMSENSE_EQUAL;
/* <name> = <evr> provide */
- name = headerGetString(h, RPMTAG_NAME);
- arch = headerGetString(h, RPMTAG_ARCH);
- evr = headerGetAsString(h, RPMTAG_EVR);
- headerPutString(h, RPMTAG_PROVIDENAME, name);
- headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
+ name = headerGetString(pkg->header, RPMTAG_NAME);
+ arch = headerGetString(pkg->header, RPMTAG_ARCH);
+ evr = headerGetAsString(pkg->header, RPMTAG_EVR);
+ addReqProv(pkg, RPMTAG_PROVIDENAME, name, evr, pflags, 0);
/*
* <name>(<isa>) = <evr> provide
@@ -521,9 +591,7 @@ static void addPackageProvides(Header h)
*/
isaprov = rpmExpand(name, "%{?_isa}", NULL);
if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) {
- headerPutString(h, RPMTAG_PROVIDENAME, isaprov);
- headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
- headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
+ addReqProv(pkg, RPMTAG_PROVIDENAME, isaprov, evr, pflags, 0);
}
free(isaprov);
free(evr);
@@ -545,8 +613,13 @@ static void addTargets(Package Pkgs)
headerPutString(pkg->header, RPMTAG_PLATFORM, platform);
headerPutString(pkg->header, RPMTAG_OPTFLAGS, optflags);
+ /* Add manual dependencies early for rpmspec etc to look at */
+ addPackageProvides(pkg);
+ for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
+ rpmdsPutToHeader(pkg->dependencies[i], pkg->header);
+ }
+
pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
- addPackageProvides(pkg->header);
}
free(platform);
free(arch);
@@ -554,10 +627,134 @@ static void addTargets(Package Pkgs)
free(optflags);
}
+rpmRC checkForEncoding(Header h, int addtag)
+{
+ rpmRC rc = RPMRC_OK;
+#if HAVE_ICONV
+ const char *encoding = "utf-8";
+ rpmTagVal tag;
+ iconv_t ic;
+ char *dest = NULL;
+ size_t destlen = 0;
+ int strict = rpmExpandNumeric("%{_invalid_encoding_terminates_build}");
+ HeaderIterator hi = headerInitIterator(h);
+
+ ic = iconv_open(encoding, encoding);
+ if (ic == (iconv_t) -1) {
+ rpmlog(RPMLOG_WARNING,
+ _("encoding %s not supported by system\n"), encoding);
+ goto exit;
+ }
+
+ while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
+ struct rpmtd_s td;
+ const char *src = NULL;
+
+ if (rpmTagGetClass(tag) != RPM_STRING_CLASS)
+ continue;
+
+ headerGet(h, tag, &td, (HEADERGET_RAW|HEADERGET_MINMEM));
+ while ((src = rpmtdNextString(&td)) != NULL) {
+ size_t srclen = strlen(src);
+ size_t outlen, inlen = srclen;
+ char *out, *in = (char *) src;
+
+ if (destlen < srclen) {
+ destlen = srclen * 2;
+ dest = xrealloc(dest, destlen);
+ }
+ out = dest;
+ outlen = destlen;
+
+ /* reset conversion state */
+ iconv(ic, NULL, &inlen, &out, &outlen);
+
+ if (iconv(ic, &in, &inlen, &out, &outlen) == (size_t) -1) {
+ rpmlog(strict ? RPMLOG_ERR : RPMLOG_WARNING,
+ _("Package %s: invalid %s encoding in %s: %s - %s\n"),
+ headerGetString(h, RPMTAG_NAME),
+ encoding, rpmTagGetName(tag), src, strerror(errno));
+ rc = RPMRC_FAIL;
+ }
+
+ }
+ rpmtdFreeData(&td);
+ }
+
+ /* Stomp "known good utf" mark in header if requested */
+ if (rc == RPMRC_OK && addtag)
+ headerPutString(h, RPMTAG_ENCODING, encoding);
+ if (!strict)
+ rc = RPMRC_OK;
+
+exit:
+ if (ic != (iconv_t) -1)
+ iconv_close(ic);
+ headerFreeIterator(hi);
+ free(dest);
+#endif /* HAVE_ICONV */
+
+ return rc;
+}
+
+static int parseEmpty(rpmSpec spec, int prevParsePart)
+{
+ int res = PART_ERROR;
+ int nextPart, rc;
+ char *line;
+
+ line = spec->line + sizeof("%end") - 1;
+ SKIPSPACE(line);
+ if (line[0] != '\0') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: %%end doesn't take any arguments: %s\n"),
+ spec->lineNum, spec->line);
+ goto exit;
+ }
+
+ if (prevParsePart == PART_EMPTY) {
+ rpmlog(RPMLOG_ERR,
+ _("line %d: %%end not expected here, no section to close: %s\n"),
+ spec->lineNum, spec->line);
+ goto exit;
+ }
+
+ if ((rc = readLine(spec, STRIP_TRAILINGSPACE|STRIP_COMMENTS)) > 0) {
+ nextPart = PART_NONE;
+ } else if (rc < 0) {
+ goto exit;
+ } else {
+ while (! (nextPart = isPart(spec->line))) {
+ line = spec->line;
+ SKIPSPACE(line);
+
+ if (line[0] != '\0') {
+ rpmlog(RPMLOG_ERR,
+ _("line %d doesn't belong to any section: %s\n"),
+ spec->lineNum, spec->line);
+ goto exit;
+ }
+ if ((rc = readLine(spec, STRIP_TRAILINGSPACE|STRIP_COMMENTS)) > 0) {
+ nextPart = PART_NONE;
+ break;
+ } else if (rc < 0) {
+ goto exit;
+ }
+ }
+ }
+
+ res = nextPart;
+
+exit:
+ return res;
+}
+
static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
const char *buildRoot, int recursing)
{
int parsePart = PART_PREAMBLE;
+ int prevParsePart = PART_EMPTY;
+ int storedParsePart;
int initialPackage = 1;
rpmSpec spec;
@@ -572,8 +769,8 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
} else {
spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL);
}
- addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
- addMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC);
+ rpmPushMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
+ rpmPushMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC);
spec->recursing = recursing;
spec->flags = flags;
@@ -583,11 +780,15 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
while (parsePart != PART_NONE) {
int goterror = 0;
+ storedParsePart = parsePart;
switch (parsePart) {
case PART_ERROR: /* fallthrough */
default:
goterror = 1;
break;
+ case PART_EMPTY:
+ parsePart = parseEmpty(spec, prevParsePart);
+ break;
case PART_PREAMBLE:
parsePart = parsePreamble(spec, initialPackage);
initialPackage = 0;
@@ -619,6 +820,12 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
case PART_TRIGGERIN:
case PART_TRIGGERUN:
case PART_TRIGGERPOSTUN:
+ case PART_FILETRIGGERIN:
+ case PART_FILETRIGGERUN:
+ case PART_FILETRIGGERPOSTUN:
+ case PART_TRANSFILETRIGGERIN:
+ case PART_TRANSFILETRIGGERUN:
+ case PART_TRANSFILETRIGGERPOSTUN:
parsePart = parseScript(spec, parsePart);
break;
@@ -635,6 +842,7 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
case PART_BUILDARCHITECTURES:
break;
}
+ prevParsePart = storedParsePart;
if (goterror || parsePart >= PART_LAST) {
goto errxit;
@@ -654,13 +862,13 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
/* Skip if not arch is not compatible. */
if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
continue;
- addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
+ rpmPushMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
spec->BASpecs[index] = parseSpec(specFile, flags, buildRoot, 1);
if (spec->BASpecs[index] == NULL) {
spec->BACount = index;
goto errxit;
}
- delMacro(NULL, "_target_cpu");
+ rpmPopMacro(NULL, "_target_cpu");
index++;
}
@@ -710,6 +918,18 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
/* Add arch, os and platform, self-provides etc for each package */
addTargets(spec->packages);
+ /* Check for encoding in each package unless disabled */
+ if (!(spec->flags & RPMSPEC_NOUTF8)) {
+ int badenc = 0;
+ for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
+ if (checkForEncoding(pkg->header, 0) != RPMRC_OK) {
+ badenc = 1;
+ }
+ }
+ if (badenc)
+ goto errxit;
+ }
+
closeSpec(spec);
exit:
/* Assemble source header from parsed components */
diff --git a/build/reqprov.c b/build/reqprov.c
index bc2f7ea26..5fa0a1c6b 100644
--- a/build/reqprov.c
+++ b/build/reqprov.c
@@ -7,124 +7,49 @@
#include <rpm/header.h>
#include <rpm/rpmstring.h>
-#include "build/rpmbuild_misc.h"
+#include <rpm/rpmlog.h>
+#include "build/rpmbuild_internal.h"
#include "debug.h"
-static int isNewDep(Header h, rpmTagVal nametag,
- const char *N, const char *EVR, rpmsenseFlags Flags,
- rpmTagVal indextag, uint32_t index)
-{
- int isnew = 1;
- struct rpmtd_s idx;
- rpmds ads = rpmdsNew(h, nametag, 0);
- rpmds bds = rpmdsSingle(nametag, N, EVR, Flags);
-
- if (indextag) {
- headerGet(h, indextag, &idx, HEADERGET_MINMEM);
- }
-
- /* XXX there's no guarantee the ds is sorted here so rpmdsFind() wont do */
- rpmdsInit(ads);
- while (isnew && rpmdsNext(ads) >= 0) {
- if (!rstreq(rpmdsN(ads), rpmdsN(bds))) continue;
- if (!rstreq(rpmdsEVR(ads), rpmdsEVR(bds))) continue;
- if (rpmdsFlags(ads) != rpmdsFlags(bds)) continue;
- if (indextag && rpmtdSetIndex(&idx, rpmdsIx(ads)) >= 0 &&
- rpmtdGetNumber(&idx) != index) continue;
- isnew = 0;
- }
-
- if (indextag) {
- rpmtdFreeData(&idx);
- }
- rpmdsFree(ads);
- rpmdsFree(bds);
- return isnew;
-}
-
-int addReqProv(Header h, rpmTagVal tagN,
+int addReqProv(Package pkg, rpmTagVal tagN,
const char * N, const char * EVR, rpmsenseFlags Flags,
uint32_t index)
{
- rpmTagVal versiontag = 0;
- rpmTagVal flagtag = 0;
- rpmTagVal indextag = 0;
- rpmsenseFlags extra = RPMSENSE_ANY;
+ rpmds newds, *dsp = NULL;
- switch (tagN) {
- case RPMTAG_PROVIDENAME:
- versiontag = RPMTAG_PROVIDEVERSION;
- flagtag = RPMTAG_PROVIDEFLAGS;
- extra = Flags & RPMSENSE_FIND_PROVIDES;
- break;
- case RPMTAG_OBSOLETENAME:
- versiontag = RPMTAG_OBSOLETEVERSION;
- flagtag = RPMTAG_OBSOLETEFLAGS;
- break;
- case RPMTAG_CONFLICTNAME:
- versiontag = RPMTAG_CONFLICTVERSION;
- flagtag = RPMTAG_CONFLICTFLAGS;
- break;
- case RPMTAG_ORDERNAME:
- versiontag = RPMTAG_ORDERVERSION;
- flagtag = RPMTAG_ORDERFLAGS;
- break;
- case RPMTAG_TRIGGERNAME:
- versiontag = RPMTAG_TRIGGERVERSION;
- flagtag = RPMTAG_TRIGGERFLAGS;
- indextag = RPMTAG_TRIGGERINDEX;
- extra = Flags & RPMSENSE_TRIGGER;
- break;
- case RPMTAG_SUGGESTSNAME:
- versiontag = RPMTAG_SUGGESTSVERSION;
- flagtag = RPMTAG_SUGGESTSFLAGS;
- extra = Flags & _ALL_REQUIRES_MASK;
- break;
- case RPMTAG_ENHANCESNAME:
- versiontag = RPMTAG_ENHANCESVERSION;
- flagtag = RPMTAG_ENHANCESFLAGS;
- extra = Flags & _ALL_REQUIRES_MASK;
- break;
- case RPMTAG_REQUIRENAME:
- default:
- tagN = RPMTAG_REQUIRENAME;
- versiontag = RPMTAG_REQUIREVERSION;
- flagtag = RPMTAG_REQUIREFLAGS;
- extra = Flags & _ALL_REQUIRES_MASK;
- }
+ dsp = packageDependencies(pkg, tagN);
/* rpmlib() dependency sanity: only requires permitted, ensure sense bit */
if (rstreqn(N, "rpmlib(", sizeof("rpmlib(")-1)) {
if (tagN != RPMTAG_REQUIRENAME) return 1;
- extra |= RPMSENSE_RPMLIB;
+ Flags |= RPMSENSE_RPMLIB;
}
- Flags = (Flags & RPMSENSE_SENSEMASK) | extra;
+ newds = rpmdsSinglePoolTix(pkg->pool, tagN, N, EVR,
+ rpmSanitizeDSFlags(tagN, Flags), index);
- if (EVR == NULL)
- EVR = "";
-
- /* Avoid adding duplicate dependencies. */
- if (isNewDep(h, tagN, N, EVR, Flags, indextag, index)) {
- headerPutString(h, tagN, N);
- headerPutString(h, versiontag, EVR);
- headerPutUint32(h, flagtag, &Flags, 1);
- if (indextag) {
- headerPutUint32(h, indextag, &index, 1);
- }
- }
+ rpmdsMerge(dsp, newds);
+ rpmdsFree(newds);
return 0;
}
-int rpmlibNeedsFeature(Header h, const char * feature, const char * featureEVR)
+rpmRC addReqProvPkg(void *cbdata, rpmTagVal tagN,
+ const char * N, const char *EVR, rpmsenseFlags Flags,
+ int index)
+{
+ Package pkg = cbdata;
+ return addReqProv(pkg, tagN, N, EVR, Flags, index) ? RPMRC_FAIL : RPMRC_OK;
+}
+
+int rpmlibNeedsFeature(Package pkg, const char * feature, const char * featureEVR)
{
char *reqname = NULL;
int res;
rasprintf(&reqname, "rpmlib(%s)", feature);
- res = addReqProv(h, RPMTAG_REQUIRENAME, reqname, featureEVR,
+ res = addReqProv(pkg, RPMTAG_REQUIRENAME, reqname, featureEVR,
RPMSENSE_RPMLIB|(RPMSENSE_LESS|RPMSENSE_EQUAL), 0);
free(reqname);
diff --git a/build/rpmbuild.h b/build/rpmbuild.h
index 51a735d3d..4777f587e 100644
--- a/build/rpmbuild.h
+++ b/build/rpmbuild.h
@@ -15,7 +15,8 @@ extern "C" {
#endif
/** \ingroup rpmbuild
- * Bit(s) to control rpmSpecBuild() operation.
+ * Bit(s) to control rpmSpecBuild() operation. Also used as argument to
+ * rpmSpecGetSection and rpmSpecPkgGetSection.
*/
enum rpmBuildFlags_e {
RPMBUILD_NONE = 0,
@@ -31,6 +32,9 @@ enum rpmBuildFlags_e {
RPMBUILD_RMBUILD = (1 << 9), /*!< Remove build sub-tree. */
RPMBUILD_STRINGBUF = (1 << 10), /*!< Internal use only */
RPMBUILD_RMSPEC = (1 << 11), /*!< Remove spec file. */
+ RPMBUILD_FILE_FILE = (1 << 16), /*!< rpmSpecPkgGetSection: %files -f */
+ RPMBUILD_FILE_LIST = (1 << 17), /*!< rpmSpecPkgGetSection: %files */
+ RPMBUILD_POLICY = (1 << 18), /*!< rpmSpecPkgGetSection: %policy */
RPMBUILD_NOBUILD = (1 << 31) /*!< Don't execute or package. */
};
diff --git a/build/rpmbuild_internal.h b/build/rpmbuild_internal.h
index fb6198d76..86a4f6274 100644
--- a/build/rpmbuild_internal.h
+++ b/build/rpmbuild_internal.h
@@ -3,8 +3,22 @@
#include <rpm/rpmbuild.h>
#include <rpm/rpmutil.h>
+#include <rpm/rpmstrpool.h>
#include "build/rpmbuild_misc.h"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE fileRenameHash
+#define HTKEYTYPE const char *
+#define HTDATATYPE const char *
+#include "lib/rpmhash.H"
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+
+#define WHITELIST_NAME ".-_+%{}"
+
struct TriggerFileEntry {
int index;
char * fileName;
@@ -12,6 +26,7 @@ struct TriggerFileEntry {
char * prog;
uint32_t flags;
struct TriggerFileEntry * next;
+ uint32_t priority;
};
typedef struct ReadLevelEntry {
@@ -36,6 +51,9 @@ typedef struct Package_s * Package;
* The structure used to store values parsed from a spec file.
*/
struct rpmSpec_s {
+ char * buildHost;
+ rpm_time_t buildTime;
+
char * specFile; /*!< Name of the spec file. */
char * buildRoot;
char * buildSubdir;
@@ -66,10 +84,10 @@ struct rpmSpec_s {
char * sourceRpmName;
unsigned char * sourcePkgId;
- Header sourceHeader;
- rpmfi sourceCpioList;
+ Package sourcePackage;
rpmMacroContext macros;
+ rpmstrPool pool;
StringBuf prep; /*!< %prep scriptlet. */
StringBuf build; /*!< %build scriptlet. */
@@ -82,13 +100,19 @@ struct rpmSpec_s {
Package packages; /*!< Package list. */
};
+#define PACKAGE_NUM_DEPS 12
+
/** \ingroup rpmbuild
* The structure used to store values for a package.
*/
struct Package_s {
+ rpmsid name;
+ rpmstrPool pool;
Header header;
rpmds ds; /*!< Requires: N = EVR */
- rpmfi cpioList;
+ rpmds dependencies[PACKAGE_NUM_DEPS];
+ rpmfiles cpioList;
+ ARGV_t dpaths;
struct Source * icon;
@@ -104,9 +128,14 @@ struct Package_s {
char * verifyFile; /*!< %verifyscript scriptlet. */
struct TriggerFileEntry * triggerFiles;
+ struct TriggerFileEntry * fileTriggerFiles;
+ struct TriggerFileEntry * transFileTriggerFiles;
ARGV_t fileFile;
ARGV_t fileList; /* If NULL, package will not be written */
+ ARGV_t fileExcludeList;
+ ARGV_t removePostfixes;
+ fileRenameHash fileRenameMap;
ARGV_t policyList;
Package next;
@@ -114,6 +143,7 @@ struct Package_s {
#define PART_SUBNAME 0
#define PART_NAME 1
+#define PART_QUIET 2
/** \ingroup rpmbuild
* rpmSpec file parser states.
@@ -145,7 +175,14 @@ typedef enum rpmParseState_e {
PART_TRIGGERPOSTUN = 30+PART_BASE, /*!< */
PART_TRIGGERPREIN = 31+PART_BASE, /*!< */
PART_POLICIES = 32+PART_BASE, /*!< */
- PART_LAST = 33+PART_BASE /*!< */
+ PART_FILETRIGGERIN = 33+PART_BASE, /*!< */
+ PART_FILETRIGGERUN = 34+PART_BASE, /*!< */
+ PART_FILETRIGGERPOSTUN = 35+PART_BASE, /*!< */
+ PART_TRANSFILETRIGGERIN = 36+PART_BASE, /*!< */
+ PART_TRANSFILETRIGGERUN = 37+PART_BASE, /*!< */
+ PART_TRANSFILETRIGGERPOSTUN = 38+PART_BASE, /*!< */
+ PART_EMPTY = 39+PART_BASE, /*!< */
+ PART_LAST = 40+PART_BASE /*!< */
} rpmParseState;
@@ -259,12 +296,15 @@ int parseScript(rpmSpec spec, int parsePart);
* Check for inappropriate characters. All alphanums are considered sane.
* @param spec spec
* @param field string to check
- * @param fsize size of string to check
* @param whitelist string of permitted characters
* @return RPMRC_OK if OK
*/
RPM_GNUC_INTERNAL
-rpmRC rpmCharCheck(rpmSpec spec, const char *field, size_t fsize, const char *whitelist);
+rpmRC rpmCharCheck(rpmSpec spec, const char *field, const char *whitelist);
+
+typedef rpmRC (*addReqProvFunction) (void *cbdata, rpmTagVal tagN,
+ const char * N, const char * EVR, rpmsenseFlags Flags,
+ int index);
/** \ingroup rpmbuild
* Parse dependency relations from spec file and/or autogenerated output buffer.
@@ -274,20 +314,21 @@ rpmRC rpmCharCheck(rpmSpec spec, const char *field, size_t fsize, const char *wh
* @param tagN tag, identifies type of dependency
* @param index (0 always)
* @param tagflags dependency flags already known from context
+ * @param cb Callback for adding dependency (nullable)
+ * @param cbdata Callback data (@pkg if NULL)
* @return RPMRC_OK on success, RPMRC_FAIL on failure
*/
RPM_GNUC_INTERNAL
rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char * field, rpmTagVal tagN,
- int index, rpmsenseFlags tagflags);
+ int index, rpmsenseFlags tagflags, addReqProvFunction cb, void *cbdata);
/** \ingroup rpmbuild
* Evaluate boolean expression.
- * @param spec spec file control structure
* @param expr expression to parse
* @return
*/
RPM_GNUC_INTERNAL
-int parseExpressionBoolean(rpmSpec spec, const char * expr);
+int parseExpressionBoolean(const char * expr);
/** \ingroup rpmbuild
* Run a build script, assembled from spec file scriptlet section.
@@ -317,23 +358,35 @@ rpmRC lookupPackage(rpmSpec spec, const char * name, int flag,
/** \ingroup rpmbuild
* Create and initialize package control structure.
- * @param spec spec file control structure
+ * @param name package name for sub-packages (or NULL)
+ * @param pool string pool
+ * @param pkglist package list pointer to append to (or NULL)
* @return package control structure
*/
RPM_GNUC_INTERNAL
-Package newPackage(rpmSpec spec);
+Package newPackage(const char *name, rpmstrPool pool, Package * pkglist);
+
+
+/** \ingroup rpmbuild
+ * Return rpmds containing the dependencies of a given type
+ * @param pkg package
+ * @param tag name tag denominating the dependency
+ * @return pointer to dependency set
+ */
+RPM_GNUC_INTERNAL
+rpmds * packageDependencies(Package pkg, rpmTagVal tag);
/** \ingroup rpmbuild
* Post-build processing for binary package(s).
* @param spec spec file control structure
* @param pkgFlags bit(s) to control package generation
- * @param installSpecialDoc
+ * @param didInstall was %install executed?
* @param test don't execute scripts or package if testing
* @return 0 on success
*/
RPM_GNUC_INTERNAL
rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
- int installSpecialDoc, int test);
+ int didInstall, int test);
/** \ingroup rpmfc
* Generate package dependencies.
@@ -393,6 +446,59 @@ rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating);
RPM_GNUC_INTERNAL
rpmRC packageSources(rpmSpec spec, char **cookie);
+RPM_GNUC_INTERNAL
+int addLangTag(rpmSpec spec, Header h, rpmTagVal tag,
+ const char *field, const char *lang);
+
+/** \ingroup rpmbuild
+ * Add dependency to package, filtering duplicates.
+ * @param pkg package
+ * @param tagN tag, identifies type of dependency
+ * @param N (e.g. Requires: foo < 0:1.2-3, "foo")
+ * @param EVR (e.g. Requires: foo < 0:1.2-3, "0:1.2-3")
+ * @param Flags (e.g. Requires: foo < 0:1.2-3, both "Requires:" and "<")
+ * @param index (# trigger script for triggers, 0 for others)
+ * @return 0 on success, 1 on error
+ */
+RPM_GNUC_INTERNAL
+int addReqProv(Package pkg, rpmTagVal tagN,
+ const char * N, const char * EVR, rpmsenseFlags Flags,
+ uint32_t index);
+
+RPM_GNUC_INTERNAL
+rpmRC addReqProvPkg(void *cbdata, rpmTagVal tagN,
+ const char * N, const char * EVR, rpmsenseFlags Flags,
+ int index);
+
+/** \ingroup rpmbuild
+ * Add self-provides to package.
+ * @param pkg package
+ */
+RPM_GNUC_INTERNAL
+void addPackageProvides(Package pkg);
+
+/** \ingroup rpmbuild
+ * Add rpmlib feature dependency.
+ * @param pkg package
+ * @param feature rpm feature name (i.e. "rpmlib(Foo)" for feature Foo)
+ * @param featureEVR rpm feature epoch/version/release
+ * @return 0 always
+ */
+RPM_GNUC_INTERNAL
+int rpmlibNeedsFeature(Package pkg, const char * feature, const char * featureEVR);
+
+RPM_GNUC_INTERNAL
+rpmRC checkForEncoding(Header h, int addtag);
+
+
+/** \ingroup rpmbuild
+ * Copy tags inherited by subpackages from the source header to the target header
+ * @param h target header
+ * @param fromh source header
+ */
+RPM_GNUC_INTERNAL
+void copyInheritedTags(Header h, Header fromh);
+
#ifdef __cplusplus
}
#endif
diff --git a/build/rpmbuild_misc.h b/build/rpmbuild_misc.h
index 9665c975f..843dfea78 100644
--- a/build/rpmbuild_misc.h
+++ b/build/rpmbuild_misc.h
@@ -12,9 +12,10 @@ extern "C" {
/** \ingroup rpmbuild
* Truncate comment lines.
* @param s skip white space, truncate line at '#'
+ * @return 1 on comment lines, 0 otherwise
*/
RPM_GNUC_INTERNAL
-void handleComments(char * s);
+int handleComments(char * s);
/** \ingroup rpmstring
*/
@@ -62,31 +63,6 @@ void appendStringBufAux(StringBuf sb, const char * s, int nl);
RPM_GNUC_INTERNAL
uint32_t parseUnsignedNum(const char * line, uint32_t * res);
-/** \ingroup rpmbuild
- * Add dependency to header, filtering duplicates.
- * @param h header
- * @param tagN tag, identifies type of dependency
- * @param N (e.g. Requires: foo < 0:1.2-3, "foo")
- * @param EVR (e.g. Requires: foo < 0:1.2-3, "0:1.2-3")
- * @param Flags (e.g. Requires: foo < 0:1.2-3, both "Requires:" and "<")
- * @param index (0 always)
- * @return 0 on success, 1 on error
- */
-RPM_GNUC_INTERNAL
-int addReqProv(Header h, rpmTagVal tagN,
- const char * N, const char * EVR, rpmsenseFlags Flags,
- uint32_t index);
-
-/** \ingroup rpmbuild
- * Add rpmlib feature dependency.
- * @param h header
- * @param feature rpm feature name (i.e. "rpmlib(Foo)" for feature Foo)
- * @param featureEVR rpm feature epoch/version/release
- * @return 0 always
- */
-RPM_GNUC_INTERNAL
-int rpmlibNeedsFeature(Header h, const char * feature, const char * featureEVR);
-
#ifdef __cplusplus
}
#endif
diff --git a/build/rpmfc.c b/build/rpmfc.c
index f8e340288..2fbfc69ab 100644
--- a/build/rpmfc.c
+++ b/build/rpmfc.c
@@ -1,6 +1,7 @@
#include "system.h"
#include <errno.h>
+#include <libgen.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <signal.h>
@@ -16,6 +17,7 @@
#include <rpm/rpmfi.h>
#include <rpm/rpmstrpool.h>
+#include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */
#include "build/rpmbuild_internal.h"
#include "debug.h"
@@ -32,13 +34,24 @@ typedef struct rpmfcAttr_s {
struct matchRule excl;
} * rpmfcAttr;
+typedef struct {
+ int fileIx;
+ rpmds dep;
+} rpmfcFileDep;
+
+typedef struct {
+ rpmfcFileDep *data;
+ int size;
+ int alloced;
+} rpmfcFileDeps;
+
/**
*/
struct rpmfc_s {
+ Package pkg;
int nfiles; /*!< no. of files */
int fknown; /*!< no. of classified files */
int fwhite; /*!< no. of "white" files */
- int ix; /*!< current file index */
int skipProv; /*!< Don't auto-generate Provides:? */
int skipReq; /*!< Don't auto-generate Requires:? */
char *buildRoot; /*!< (Build) root dir */
@@ -54,11 +67,9 @@ struct rpmfc_s {
ARGI_t fddictn; /*!< (no. files) file depends dictionary no. entries */
ARGI_t ddictx; /*!< (no. dependencies) file->dependency mapping */
rpmstrPool cdict; /*!< file class dictionary */
- rpmstrPool ddict; /*!< file depends dictionary */
+ rpmfcFileDeps fileDeps; /*!< file dependency mapping */
- rpmds provides; /*!< (no. provides) package provides */
- rpmds requires; /*!< (no. requires) package requires */
- rpmds supplements; /*!< (no. supplements) package supplements */
+ rpmstrPool pool; /*!< general purpose string storage */
};
struct rpmfcTokens_s {
@@ -87,22 +98,62 @@ static void ruleFree(struct matchRule *rule)
argvFree(rule->flags);
}
-static char *rpmfcAttrMacro(const char *name,
- const char *attr_prefix, const char *attr)
+static char *rpmfcAttrMacroV(const char *arg, va_list args)
{
- char *ret;
- if (attr_prefix && attr_prefix[0] != '\0')
- ret = rpmExpand("%{?__", name, "_", attr_prefix, "_", attr, "}", NULL);
- else
- ret = rpmExpand("%{?__", name, "_", attr, "}", NULL);
- return rstreq(ret, "") ? _free(ret) : ret;
+ const char *s;
+ int blen;
+ char *buf = NULL, *obuf;
+ char *pe;
+ va_list args2;
+
+ if (arg == NULL || rstreq(arg, ""))
+ return NULL;
+
+ va_copy(args2, args);
+ blen = sizeof("%{?_") - 1;
+ for (s = arg; s != NULL; s = va_arg(args, const char *)) {
+ blen += sizeof("_") - 1 + strlen(s);
+ }
+ blen += sizeof("}") - 1;
+
+ buf = xmalloc(blen + 1);
+
+ pe = buf;
+ pe = stpcpy(pe, "%{?_");
+ for (s = arg; s != NULL; s = va_arg(args2, const char *)) {
+ *pe++ = '_';
+ pe = stpcpy(pe, s);
+ }
+ va_end(args2);
+ *pe++ = '}';
+ *pe = '\0';
+
+ obuf = rpmExpand(buf, NULL);
+ free(buf);
+
+ return rstreq(obuf, "") ? _free(obuf) : obuf;
}
-static regex_t *rpmfcAttrReg(const char *name,
- const char *attr_prefix, const char *attr)
+static char *rpmfcAttrMacro(const char *arg, ...)
+{
+ va_list args;
+ char *s;
+
+ va_start(args, arg);
+ s = rpmfcAttrMacroV(arg, args);
+ va_end(args);
+ return s;
+}
+
+static regex_t *rpmfcAttrReg(const char *arg, ...)
{
regex_t *reg = NULL;
- char *pattern = rpmfcAttrMacro(name, attr_prefix, attr);
+ char *pattern;
+ va_list args;
+
+ va_start(args, arg);
+ pattern = rpmfcAttrMacroV(arg, args);
+ va_end(args);
if (pattern) {
reg = xcalloc(1, sizeof(*reg));
if (regcomp(reg, pattern, REG_EXTENDED) != 0) {
@@ -122,10 +173,19 @@ static rpmfcAttr rpmfcAttrNew(const char *name)
attr->name = xstrdup(name);
for (struct matchRule **rule = rules; rule && *rule; rule++) {
const char *prefix = (*rule == &attr->incl) ? NULL : "exclude";
- char *flags = rpmfcAttrMacro(name, prefix, "flags");
+ char *flags;
+
+ if (prefix) {
+ flags = rpmfcAttrMacro(name, prefix, "flags", NULL);
- (*rule)->path = rpmfcAttrReg(name, prefix, "path");
- (*rule)->magic = rpmfcAttrReg(name, prefix, "magic");
+ (*rule)->path = rpmfcAttrReg(name, prefix, "path", NULL);
+ (*rule)->magic = rpmfcAttrReg(name, prefix, "magic", NULL);
+ } else {
+ flags = rpmfcAttrMacro(name, "flags", NULL);
+
+ (*rule)->path = rpmfcAttrReg(name, "path", NULL);
+ (*rule)->magic = rpmfcAttrReg(name, "magic", NULL);
+ }
(*rule)->flags = argvSplitString(flags, ",", ARGV_SKIPEMPTY);
argvSort((*rule)->flags, NULL);
@@ -163,16 +223,17 @@ static int rpmfcExpandAppend(ARGV_t * argvp, ARGV_const_t av)
return 0;
}
-static rpmds rpmdsSingleNS(rpmTagVal tagN, const char *namespace,
+static rpmds rpmdsSingleNS(rpmstrPool pool,
+ rpmTagVal tagN, const char *namespace,
const char * N, const char * EVR, rpmsenseFlags Flags)
{
rpmds ds = NULL;
if (namespace) {
char *NSN = rpmExpand(namespace, "(", N, ")", NULL);
- ds = rpmdsSingle(tagN, NSN, EVR, Flags);
+ ds = rpmdsSinglePool(pool, tagN, NSN, EVR, Flags);
free(NSN);
} else {
- ds = rpmdsSingle(tagN, N, EVR, Flags);
+ ds = rpmdsSinglePool(pool, tagN, N, EVR, Flags);
}
return ds;
}
@@ -208,8 +269,6 @@ static StringBuf getOutputFrom(ARGV_t argv,
child = fork();
if (child == 0) {
- /* NSPR messes with SIGPIPE, reset to default for the kids */
- signal(SIGPIPE, SIG_DFL);
close(toProg[1]);
close(fromProg[0]);
@@ -369,6 +428,12 @@ int rpmfcExec(ARGV_const_t av, StringBuf sb_stdin, StringBuf * sb_stdoutp,
buf_stdin_len = strlen(buf_stdin);
}
+ if (_rpmfc_debug) {
+ char *cmd = argvJoin(xav, " ");
+ rpmlog(RPMLOG_DEBUG, "Executing %s on %s\n", cmd, buf_stdin);
+ free(cmd);
+ }
+
/* Read output from exec'd helper. */
sb = getOutputFrom(xav, buf_stdin, buf_stdin_len, failnonzero, buildRoot);
@@ -397,15 +462,15 @@ static void argvAddUniq(ARGV_t * argvp, const char * key)
#define hasAttr(_a, _n) (argvSearch((_a), (_n), NULL) != NULL)
-static void rpmfcAddFileDep(rpmstrPool ddict, int ix, rpmds ds, char deptype)
+static void rpmfcAddFileDep(rpmfcFileDeps *fileDeps, rpmds ds, int ix)
{
- if (ds) {
- char *key = NULL;
- rasprintf(&key, "%08d%c %s %s 0x%08x", ix, deptype,
- rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
- rpmstrPoolId(ddict, key, 1);
- free(key);
+ if (fileDeps->size == fileDeps->alloced) {
+ fileDeps->alloced <<= 2;
+ fileDeps->data = xrealloc(fileDeps->data,
+ fileDeps->alloced * sizeof(fileDeps->data[0]));
}
+ fileDeps->data[fileDeps->size].fileIx = ix;
+ fileDeps->data[fileDeps->size++].dep = ds;
}
static ARGV_t runCmd(const char *nsdep, const char *depname,
@@ -424,7 +489,7 @@ static ARGV_t runCmd(const char *nsdep, const char *depname,
appendLineStringBuf(sb_stdin, fn);
if (rpmfcExec(av, sb_stdin, &sb_stdout, 0, buildRoot) == 0) {
- argvSplit(&output, getStringBuf(sb_stdout), " \t\n\r");
+ argvSplit(&output, getStringBuf(sb_stdout), "\n\r");
}
argvFree(av);
@@ -436,74 +501,77 @@ static ARGV_t runCmd(const char *nsdep, const char *depname,
return output;
}
+struct addReqProvDataFc {
+ rpmfc fc;
+ const char *namespace;
+ regex_t *exclude;
+};
+
+static rpmRC addReqProvFc(void *cbdata, rpmTagVal tagN,
+ const char * N, const char * EVR, rpmsenseFlags Flags,
+ int index)
+{
+ struct addReqProvDataFc *data = cbdata;
+ rpmfc fc = data->fc;
+ const char *namespace = data->namespace;
+ regex_t *exclude = data->exclude;
+
+ rpmds ds = rpmdsSingleNS(fc->pool, tagN, namespace, N, EVR, Flags);
+ /* Add to package and file dependencies unless filtered */
+ if (regMatch(exclude, rpmdsDNEVR(ds)+2) == 0)
+ rpmfcAddFileDep(&fc->fileDeps, ds, index);
+
+ return RPMRC_OK;
+}
+
/**
* Run per-interpreter dependency helper.
* @param fc file classifier
+ * @param ix file index
* @param nsdep class name for interpreter (e.g. "perl")
* @param depname "provides" or "requires"
- * @param depsp fc->provides or fc->requires
* @param dsContext RPMSENSE_FIND_PROVIDES or RPMSENSE_FIND_REQUIRES
* @param tagN RPMTAG_PROVIDENAME or RPMTAG_REQUIRENAME
- * @return 0
+ * @return 0 on success
*/
-static int rpmfcHelper(rpmfc fc, const char *nsdep, const char *depname,
- rpmds *depsp, rpmsenseFlags dsContext, rpmTagVal tagN)
+static int rpmfcHelper(rpmfc fc, int ix,
+ const char *nsdep, const char *depname,
+ rpmsenseFlags dsContext, rpmTagVal tagN)
{
ARGV_t pav = NULL;
- const char * fn = fc->fn[fc->ix];
+ const char * fn = fc->fn[ix];
char *namespace = NULL;
int pac;
+ int rc = 0;
regex_t *exclude = NULL;
regex_t *exclude_from = NULL;
+ regex_t *global_exclude_from = NULL;
/* If the entire path is filtered out, there's nothing more to do */
- exclude_from = rpmfcAttrReg(depname, "exclude", "from");
+ exclude_from = rpmfcAttrReg(depname, "exclude", "from", NULL);
if (regMatch(exclude_from, fn+fc->brlen))
goto exit;
+ global_exclude_from = rpmfcAttrReg("global", depname, "exclude", "from", NULL);
+ if (regMatch(global_exclude_from, fn+fc->brlen))
+ goto exit;
+
pav = runCmd(nsdep, depname, fc->buildRoot, fn);
if (pav == NULL)
goto exit;
pac = argvCount(pav);
- namespace = rpmfcAttrMacro(nsdep, NULL, "namespace");
- exclude = rpmfcAttrReg(depname, NULL, "exclude");
-
- for (int i = 0; i < pac; i++) {
- rpmds ds = NULL;
- const char *N = pav[i];
- const char *EVR = "";
- rpmsenseFlags Flags = dsContext;
- if (pav[i+1] && strchr("=<>", *pav[i+1])) {
- i++;
- for (const char *s = pav[i]; *s; s++) {
- switch(*s) {
- default:
- break;
- case '=':
- Flags |= RPMSENSE_EQUAL;
- break;
- case '<':
- Flags |= RPMSENSE_LESS;
- break;
- case '>':
- Flags |= RPMSENSE_GREATER;
- break;
- }
- }
- i++;
- EVR = pav[i];
- }
-
- ds = rpmdsSingleNS(tagN, namespace, N, EVR, Flags);
+ namespace = rpmfcAttrMacro(nsdep, "namespace", NULL);
+ exclude = rpmfcAttrReg(depname, "exclude", NULL);
- /* Add to package and file dependencies unless filtered */
- if (regMatch(exclude, rpmdsDNEVR(ds)+2) == 0) {
- (void) rpmdsMerge(depsp, ds);
- rpmfcAddFileDep(fc->ddict, fc->ix, ds, tagN == RPMTAG_PROVIDENAME ? 'P' : 'R');
- }
+ struct addReqProvDataFc data;
+ data.fc = fc;
+ data.namespace = namespace;
+ data.exclude = exclude;
- rpmdsFree(ds);
+ for (int i = 0; i < pac; i++) {
+ if (parseRCPOT(NULL, fc->pkg, pav[i], tagN, ix, dsContext, addReqProvFc, &data))
+ rc++;
}
argvFree(pav);
@@ -512,55 +580,8 @@ static int rpmfcHelper(rpmfc fc, const char *nsdep, const char *depname,
exit:
regFree(exclude_from);
- return 0;
-}
-
-/**
- * Run per-interpreter Provides: dependency helper.
- * @param fc file classifier
- * @param nsdep class name for interpreter (e.g. "perl")
- * @return 0
- */
-static int rpmfcHelperProvides(rpmfc fc, const char * nsdep)
-{
- if (fc->skipProv)
- return 0;
-
- rpmfcHelper(fc, nsdep, "provides", &fc->provides, RPMSENSE_FIND_PROVIDES, RPMTAG_PROVIDENAME);
-
- return 0;
-}
-
-/**
- * Run per-interpreter Requires: dependency helper.
- * @param fc file classifier
- * @param nsdep class name for interpreter (e.g. "perl")
- * @return 0
- */
-static int rpmfcHelperRequires(rpmfc fc, const char * nsdep)
-{
- if (fc->skipReq)
- return 0;
-
- rpmfcHelper(fc, nsdep, "requires", &fc->requires, RPMSENSE_FIND_REQUIRES, RPMTAG_REQUIRENAME);
-
- return 0;
-}
-
-/**
- * Run per-interpreter Supplements: dependency helper.
- * @param fc file classifier
- * @param nsdep class name for interpreter (e.g. "perl")
- * @return 0
- */
-static int rpmfcHelperSupplements(rpmfc fc, const char * nsdep)
-{
- if (fc->skipReq)
- return 0;
-
- rpmfcHelper(fc, nsdep, "supplements", &fc->supplements, RPMSENSE_FIND_REQUIRES|RPMSENSE_STRONG|RPMSENSE_MISSINGOK, RPMTAG_ENHANCESNAME);
-
- return 0;
+ regFree(global_exclude_from);
+ return rc;
}
/* Only used for elf coloring and controlling RPMTAG_FILECLASS inclusion now */
@@ -635,7 +656,7 @@ static int matches(const struct matchRule *rule,
}
}
-static void rpmfcAttributes(rpmfc fc, const char *ftype, const char *fullpath)
+static void rpmfcAttributes(rpmfc fc, int ix, const char *ftype, const char *fullpath)
{
const char *path = fullpath + fc->brlen;
int is_executable = 0;
@@ -652,7 +673,7 @@ static void rpmfcAttributes(rpmfc fc, const char *ftype, const char *fullpath)
/* Add attributes on libmagic type & path pattern matches */
if (matches(&(*attr)->incl, ftype, path, is_executable))
- argvAddTokens(&fc->fattrs[fc->ix], (*attr)->name);
+ argvAddTokens(&fc->fattrs[ix], (*attr)->name);
}
}
@@ -676,39 +697,34 @@ static rpm_color_t rpmfcColor(const char * fmstr)
void rpmfcPrint(const char * msg, rpmfc fc, FILE * fp)
{
- rpm_color_t fcolor;
int ndx;
int dx;
int fx;
-int nprovides;
-int nrequires;
-
if (fp == NULL) fp = stderr;
if (msg)
fprintf(fp, "===================================== %s\n", msg);
-nprovides = rpmdsCount(fc->provides);
-nrequires = rpmdsCount(fc->requires);
-
if (fc)
for (fx = 0; fx < fc->nfiles; fx++) {
- rpmsid cx = fc->fcdictx[fx] + 1; /* id's are one off */
- fcolor = fc->fcolor[fx];
- ARGV_t fattrs = fc->fattrs[fx];
-
fprintf(fp, "%3d %s", fx, fc->fn[fx]);
- if (fcolor != RPMFC_BLACK)
+ if (_rpmfc_debug) {
+ rpmsid cx = fc->fcdictx[fx] + 1; /* id's are one off */
+ rpm_color_t fcolor = fc->fcolor[fx];
+ ARGV_t fattrs = fc->fattrs[fx];
+
+ if (fcolor != RPMFC_BLACK)
fprintf(fp, "\t0x%x", fc->fcolor[fx]);
- else
+ else
fprintf(fp, "\t%s", rpmstrPoolStr(fc->cdict, cx));
- if (fattrs) {
- char *attrs = argvJoin(fattrs, ",");
- fprintf(fp, " [%s]", attrs);
- free(attrs);
- } else {
- fprintf(fp, " [none]");
+ if (fattrs) {
+ char *attrs = argvJoin(fattrs, ",");
+ fprintf(fp, " [%s]", attrs);
+ free(attrs);
+ } else {
+ fprintf(fp, " [none]");
+ }
}
fprintf(fp, "\n");
@@ -724,32 +740,16 @@ assert(fx < fc->fddictn->nvals);
const char * depval;
unsigned char deptype;
unsigned ix;
+ rpmds ds;
ix = fc->ddictx->vals[dx++];
deptype = ((ix >> 24) & 0xff);
ix &= 0x00ffffff;
depval = NULL;
- switch (deptype) {
- default:
-assert(depval != NULL);
- break;
- case 'P':
- if (nprovides > 0) {
-assert(ix < nprovides);
- (void) rpmdsSetIx(fc->provides, ix-1);
- if (rpmdsNext(fc->provides) >= 0)
- depval = rpmdsDNEVR(fc->provides);
- }
- break;
- case 'R':
- if (nrequires > 0) {
-assert(ix < nrequires);
- (void) rpmdsSetIx(fc->requires, ix-1);
- if (rpmdsNext(fc->requires) >= 0)
- depval = rpmdsDNEVR(fc->requires);
- }
- break;
- }
+ ds = rpmfcDependencies(fc, rpmdsDToTagN(deptype));
+ (void) rpmdsSetIx(ds, ix-1);
+ if (rpmdsNext(ds) >= 0)
+ depval = rpmdsDNEVR(ds);
if (depval)
fprintf(fp, "\t%s\n", depval);
}
@@ -771,16 +771,19 @@ rpmfc rpmfcFree(rpmfc fc)
free(fc->fattrs);
free(fc->fcolor);
free(fc->fcdictx);
+ free(fc->pkg);
argiFree(fc->fddictx);
argiFree(fc->fddictn);
argiFree(fc->ddictx);
- rpmstrPoolFree(fc->ddict);
+ for (int i = 0; i < fc->fileDeps.size; i++) {
+ rpmdsFree(fc->fileDeps.data[i].dep);
+ }
+ free(fc->fileDeps.data);
+
rpmstrPoolFree(fc->cdict);
- rpmdsFree(fc->provides);
- rpmdsFree(fc->requires);
- rpmdsFree(fc->supplements);
+ rpmstrPoolFree(fc->pool);
memset(fc, 0, sizeof(*fc)); /* trash and burn */
free(fc);
}
@@ -794,6 +797,11 @@ rpmfc rpmfcCreate(const char *buildRoot, rpmFlags flags)
fc->buildRoot = xstrdup(buildRoot);
fc->brlen = strlen(buildRoot);
}
+ fc->pool = rpmstrPoolCreate();
+ fc->pkg = xcalloc(1, sizeof(*fc->pkg));
+ fc->fileDeps.alloced = 10;
+ fc->fileDeps.data = xmalloc(fc->fileDeps.alloced *
+ sizeof(fc->fileDeps.data[0]));
return fc;
}
@@ -802,97 +810,183 @@ rpmfc rpmfcNew(void)
return rpmfcCreate(NULL, 0);
}
+rpmds rpmfcDependencies(rpmfc fc, rpmTagVal tag)
+{
+ if (fc) {
+ return *packageDependencies(fc->pkg, tag);
+ }
+ return NULL;
+}
+
rpmds rpmfcProvides(rpmfc fc)
{
- return (fc != NULL ? fc->provides : NULL);
+ return rpmfcDependencies(fc, RPMTAG_PROVIDENAME);
}
rpmds rpmfcRequires(rpmfc fc)
{
- return (fc != NULL ? fc->requires : NULL);
+ return rpmfcDependencies(fc, RPMTAG_REQUIRENAME);
+}
+
+rpmds rpmfcRecommends(rpmfc fc)
+{
+ return rpmfcDependencies(fc, RPMTAG_RECOMMENDNAME);
+}
+
+rpmds rpmfcSuggests(rpmfc fc)
+{
+ return rpmfcDependencies(fc, RPMTAG_SUGGESTNAME);
}
rpmds rpmfcSupplements(rpmfc fc)
{
- return (fc != NULL ? fc->supplements : NULL);
+ return rpmfcDependencies(fc, RPMTAG_SUPPLEMENTNAME);
}
-rpmRC rpmfcApply(rpmfc fc)
+rpmds rpmfcEnhances(rpmfc fc)
{
- const char * s;
- char * se;
- rpmds ds;
- const char * N;
- const char * EVR;
- rpmsenseFlags Flags;
- unsigned char deptype;
- int nddict;
+ return rpmfcDependencies(fc, RPMTAG_ENHANCENAME);
+}
+
+rpmds rpmfcConflicts(rpmfc fc)
+{
+ return rpmfcDependencies(fc, RPMTAG_CONFLICTNAME);
+}
+
+rpmds rpmfcObsoletes(rpmfc fc)
+{
+ return rpmfcDependencies(fc, RPMTAG_OBSOLETENAME);
+}
+
+
+/* Versioned deps are less than unversioned deps */
+static int cmpVerDeps(const void *a, const void *b)
+{
+ rpmfcFileDep *fDepA = (rpmfcFileDep *) a;
+ rpmfcFileDep *fDepB = (rpmfcFileDep *) b;
+
+ int aIsVersioned = rpmdsFlags(fDepA->dep) & RPMSENSE_SENSEMASK ? 1 : 0;
+ int bIsVersioned = rpmdsFlags(fDepB->dep) & RPMSENSE_SENSEMASK ? 1 : 0;
+
+ return bIsVersioned - aIsVersioned;
+}
+
+/* Sort by index */
+static int cmpIndexDeps(const void *a, const void *b)
+{
+ rpmfcFileDep *fDepA = (rpmfcFileDep *) a;
+ rpmfcFileDep *fDepB = (rpmfcFileDep *) b;
+
+ return fDepA->fileIx - fDepB->fileIx;
+}
+
+/*
+ * Remove unversioned deps if corresponding versioned deps exist but only
+ * if the versioned dependency has the same type and the same color as the versioned.
+ */
+static void rpmfcNormalizeFDeps(rpmfc fc)
+{
+ rpmstrPool versionedDeps = rpmstrPoolCreate();
+ rpmfcFileDep *normalizedFDeps = xmalloc(fc->fileDeps.size *
+ sizeof(normalizedFDeps[0]));
+ int ix = 0;
+ char *depStr;
+
+ /* Sort. Versioned dependencies first */
+ qsort(fc->fileDeps.data, fc->fileDeps.size, sizeof(fc->fileDeps.data[0]),
+ cmpVerDeps);
+
+ for (int i = 0; i < fc->fileDeps.size; i++) {
+ switch (rpmdsTagN(fc->fileDeps.data[i].dep)) {
+ case RPMTAG_REQUIRENAME:
+ case RPMTAG_RECOMMENDNAME:
+ case RPMTAG_SUGGESTNAME:
+ rasprintf(&depStr, "%08x_%c_%s",
+ fc->fcolor[fc->fileDeps.data[i].fileIx],
+ rpmdsD(fc->fileDeps.data[i].dep),
+ rpmdsN(fc->fileDeps.data[i].dep));
+
+ if (rpmdsFlags(fc->fileDeps.data[i].dep) & RPMSENSE_SENSEMASK) {
+ /* preserve versioned require dependency */
+ normalizedFDeps[ix++] = fc->fileDeps.data[i];
+ rpmstrPoolId(versionedDeps, depStr, 1);
+ } else if (!rpmstrPoolId(versionedDeps, depStr, 0)) {
+ /* preserve unversioned require dep only if versioned dep doesn't exist */
+ normalizedFDeps[ix++] =fc-> fileDeps.data[i];
+ } else {
+ rpmdsFree(fc->fileDeps.data[i].dep);
+ }
+ free(depStr);
+ break;
+ default:
+ /* Preserve all non-require dependencies */
+ normalizedFDeps[ix++] = fc->fileDeps.data[i];
+ break;
+ }
+ }
+ rpmstrPoolFree(versionedDeps);
+
+ free(fc->fileDeps.data);
+ fc->fileDeps.data = normalizedFDeps;
+ fc->fileDeps.size = ix;
+}
+
+static rpmRC rpmfcApplyInternal(rpmfc fc)
+{
+ rpmds ds, * dsp;
int previx;
unsigned int val;
int dix;
int ix;
/* Generate package and per-file dependencies. */
- for (fc->ix = 0; fc->ix < fc->nfiles && fc->fn[fc->ix] != NULL; fc->ix++) {
- for (ARGV_t fattr = fc->fattrs[fc->ix]; fattr && *fattr; fattr++) {
- rpmfcHelperProvides(fc, *fattr);
- rpmfcHelperRequires(fc, *fattr);
- rpmfcHelperSupplements(fc, *fattr);
+ for (ix = 0; ix < fc->nfiles && fc->fn[ix] != NULL; ix++) {
+ for (ARGV_t fattr = fc->fattrs[ix]; fattr && *fattr; fattr++) {
+ if (!fc->skipProv) {
+ rpmfcHelper(fc, ix, *fattr, "provides",
+ RPMSENSE_FIND_PROVIDES, RPMTAG_PROVIDENAME);
+ }
+ if (!fc->skipReq) {
+ rpmfcHelper(fc, ix, *fattr, "requires",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_REQUIRENAME);
+ rpmfcHelper(fc, ix, *fattr, "recommends",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_RECOMMENDNAME);
+ rpmfcHelper(fc, ix, *fattr, "suggests",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_SUGGESTNAME);
+ rpmfcHelper(fc, ix, *fattr, "supplements",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_SUPPLEMENTNAME);
+ rpmfcHelper(fc, ix, *fattr, "enhances",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_ENHANCENAME);
+ rpmfcHelper(fc, ix, *fattr, "conflicts",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_CONFLICTNAME);
+ rpmfcHelper(fc, ix, *fattr, "obsoletes",
+ RPMSENSE_FIND_REQUIRES, RPMTAG_OBSOLETENAME);
+ }
}
}
/* No more additions after this, freeze pool to minimize memory use */
- rpmstrPoolFreeze(fc->ddict, 0);
+
+ rpmfcNormalizeFDeps(fc);
+ for (int i = 0; i < fc->fileDeps.size; i++) {
+ ds = fc->fileDeps.data[i].dep;
+ rpmdsMerge(packageDependencies(fc->pkg, rpmdsTagN(ds)), ds);
+ }
+
+ /* Sort by index */
+ qsort(fc->fileDeps.data, fc->fileDeps.size,
+ sizeof(fc->fileDeps.data[0]), cmpIndexDeps);
/* Generate per-file indices into package dependencies. */
- nddict = rpmstrPoolNumStr(fc->ddict);
previx = -1;
- for (rpmsid id = 1; id <= nddict; id++) {
- s = rpmstrPoolStr(fc->ddict, id);
-
- /* Parse out (file#,deptype,N,EVR,Flags) */
- ix = strtol(s, &se, 10);
- if ( se == NULL ) {
- rpmlog(RPMLOG_ERR, _("Conversion of %s to long integer failed.\n"), s);
- return RPMRC_FAIL;
- }
-
- deptype = *se++;
- se++;
- N = se;
- while (*se && *se != ' ')
- se++;
- *se++ = '\0';
- EVR = se;
- while (*se && *se != ' ')
- se++;
- *se++ = '\0';
- Flags = strtol(se, NULL, 16);
-
- dix = -1;
- switch (deptype) {
- default:
- break;
- case 'P':
- ds = rpmdsSingle(RPMTAG_PROVIDENAME, N, EVR, Flags);
- dix = rpmdsFind(fc->provides, ds);
- rpmdsFree(ds);
- break;
- case 'R':
- ds = rpmdsSingle(RPMTAG_REQUIRENAME, N, EVR, Flags);
- dix = rpmdsFind(fc->requires, ds);
- rpmdsFree(ds);
- break;
- case 'S':
- ds = rpmdsSingle(RPMTAG_ENHANCESNAME, N, EVR, Flags);
- dix = rpmdsFind(fc->supplements, ds);
- ds = rpmdsFree(ds);
- break;
- }
-
+ for (int i = 0; i < fc->fileDeps.size; i++) {
+ ds = fc->fileDeps.data[i].dep;
+ ix = fc->fileDeps.data[i].fileIx;
+ dsp = packageDependencies(fc->pkg, rpmdsTagN(ds));
+ dix = rpmdsFind(*dsp, ds);
if (dix < 0)
continue;
- val = (deptype << 24) | (dix & 0x00ffffff);
+ val = (rpmdsD(ds) << 24) | (dix & 0x00ffffff);
argiAdd(&fc->ddictx, -1, val);
if (previx != ix) {
@@ -901,8 +995,8 @@ rpmRC rpmfcApply(rpmfc fc)
}
if (fc->fddictn && fc->fddictn->vals)
fc->fddictn->vals[ix]++;
- }
+ }
return RPMRC_OK;
}
@@ -960,7 +1054,6 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
/* Build (sorted) file class dictionary. */
fc->cdict = rpmstrPoolCreate();
- fc->ddict = rpmstrPoolCreate();
ms = magic_open(msflags);
if (ms == NULL) {
@@ -974,13 +1067,13 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
goto exit;
}
- for (fc->ix = 0; fc->ix < fc->nfiles; fc->ix++) {
+ for (int ix = 0; ix < fc->nfiles; ix++) {
rpmsid ftypeId;
const char * ftype;
- const char * s = argv[fc->ix];
+ const char * s = argv[ix];
size_t slen = strlen(s);
int fcolor = RPMFC_BLACK;
- rpm_mode_t mode = (fmode ? fmode[fc->ix] : 0);
+ rpm_mode_t mode = (fmode ? fmode[ix] : 0);
int is_executable = (mode & (S_IXUSR|S_IXGRP|S_IXOTH));
switch (mode & S_IFMT) {
@@ -1026,15 +1119,15 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
rpmlog(RPMLOG_DEBUG, "%s: %s\n", s, ftype);
/* Save the path. */
- fc->fn[fc->ix] = xstrdup(s);
+ fc->fn[ix] = xstrdup(s);
/* Add (filtered) file coloring */
fcolor |= rpmfcColor(ftype);
/* Add attributes based on file type and/or path */
- rpmfcAttributes(fc, ftype, s);
+ rpmfcAttributes(fc, ix, ftype, s);
- fc->fcolor[fc->ix] = fcolor;
+ fc->fcolor[ix] = fcolor;
/* Add to file class dictionary and index array */
if (fcolor != RPMFC_WHITE && (fcolor & RPMFC_INCLUDE)) {
@@ -1045,7 +1138,7 @@ rpmRC rpmfcClassify(rpmfc fc, ARGV_t argv, rpm_mode_t * fmode)
fc->fwhite++;
}
/* Pool id's start from 1, for headers we want it from 0 */
- fc->fcdictx[fc->ix] = ftypeId - 1;
+ fc->fcdictx[ix] = ftypeId - 1;
}
rc = RPMRC_OK;
@@ -1101,6 +1194,12 @@ static struct DepMsg_s depMsgs[] = {
{ "Requires(postun)", { NULL, "postun", NULL, NULL },
-1, -1, RPMTAG_REQUIREFLAGS,
RPMSENSE_SCRIPT_POSTUN, 0 },
+ { "Requires(pretrans)", { NULL, "pretrans", NULL, NULL },
+ -1, -1, RPMTAG_REQUIREFLAGS,
+ RPMSENSE_PRETRANS, 0 },
+ { "Requires(posttrans)", { NULL, "posttrans", NULL, NULL },
+ -1, -1, RPMTAG_REQUIREFLAGS,
+ RPMSENSE_POSTTRANS, 0 },
{ "Requires", { "%{?__find_requires}", NULL, NULL, NULL },
-1, -1, RPMTAG_REQUIREFLAGS, /* XXX inherit name/version arrays */
RPMSENSE_FIND_REQUIRES|RPMSENSE_TRIGGERIN|RPMSENSE_TRIGGERUN|RPMSENSE_TRIGGERPOSTUN|RPMSENSE_TRIGGERPREIN, 0 },
@@ -1110,12 +1209,18 @@ static struct DepMsg_s depMsgs[] = {
{ "Obsoletes", { "%{?__find_obsoletes}", NULL, NULL, NULL },
RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
0, -1 },
- { "Enhances", { "%{?__find_enhances}", NULL, NULL, NULL },
- RPMTAG_ENHANCESNAME, RPMTAG_ENHANCESVERSION, RPMTAG_ENHANCESFLAGS,
- RPMSENSE_STRONG, RPMSENSE_STRONG },
+ { "Recommends", { "%{?__find_recommends}", NULL, NULL, NULL },
+ RPMTAG_RECOMMENDNAME, RPMTAG_RECOMMENDVERSION, RPMTAG_RECOMMENDFLAGS,
+ 0, -1 },
+ { "Suggests", { "%{?__find_suggests}", NULL, NULL, NULL },
+ RPMTAG_SUGGESTNAME, RPMTAG_SUGGESTVERSION, RPMTAG_SUGGESTFLAGS,
+ 0, -1 },
{ "Supplements", { "%{?__find_supplements}", NULL, NULL, NULL },
- RPMTAG_ENHANCESNAME, RPMTAG_ENHANCESVERSION, RPMTAG_ENHANCESFLAGS,
- RPMSENSE_STRONG, 0 },
+ RPMTAG_SUPPLEMENTNAME, RPMTAG_SUPPLEMENTVERSION, RPMTAG_SUPPLEMENTFLAGS,
+ 0, -1 },
+ { "Enhances", { "%{?__find_enhances}", NULL, NULL, NULL },
+ RPMTAG_ENHANCENAME, RPMTAG_ENHANCEVERSION, RPMTAG_ENHANCEFLAGS,
+ 0, -1 },
{ NULL, { NULL, NULL, NULL, NULL }, 0, 0, 0, 0, 0 }
};
@@ -1123,7 +1228,7 @@ static DepMsg_t DepMsgs = depMsgs;
/**
*/
-static void printDeps(Header h)
+static void printDeps(rpmfc fc)
{
DepMsg_t dm;
rpmds ds = NULL;
@@ -1133,8 +1238,7 @@ static void printDeps(Header h)
for (dm = DepMsgs; dm->msg != NULL; dm++) {
if (dm->ntag != -1) {
- rpmdsFree(ds);
- ds = rpmdsNew(h, dm->ntag, 0);
+ ds = rpmfcDependencies(fc, dm->ntag);
}
if (dm->ftag == 0)
continue;
@@ -1161,18 +1265,16 @@ static void printDeps(Header h)
if (bingo)
rpmlog(RPMLOG_NOTICE, "\n");
}
- rpmdsFree(ds);
}
-static rpmRC rpmfcGenerateDependsHelper(const rpmSpec spec, Package pkg, rpmfi fi)
+static rpmRC rpmfcApplyExternal(rpmfc fc)
{
StringBuf sb_stdin = newStringBuf();
rpmRC rc = RPMRC_OK;
/* Create file manifest buffer to deliver to dependency finder. */
- fi = rpmfiInit(fi, 0);
- while (rpmfiNext(fi) >= 0)
- appendLineStringBuf(sb_stdin, rpmfiFN(fi));
+ for (int i = 0; i < fc->nfiles; i++)
+ appendLineStringBuf(sb_stdin, fc->fn[i]);
for (DepMsg_t dm = DepMsgs; dm->msg != NULL; dm++) {
rpmTagVal tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
@@ -1181,25 +1283,23 @@ static rpmRC rpmfcGenerateDependsHelper(const rpmSpec spec, Package pkg, rpmfi f
StringBuf sb_stdout = NULL;
int failnonzero = (tag == RPMTAG_PROVIDEFLAGS);
- switch(tag) {
+ switch (tag) {
case RPMTAG_PROVIDEFLAGS:
- if (!pkg->autoProv)
+ if (fc->skipProv)
continue;
tagflags = RPMSENSE_FIND_PROVIDES;
break;
case RPMTAG_REQUIREFLAGS:
- if (!pkg->autoReq)
+ case RPMTAG_RECOMMENDFLAGS:
+ case RPMTAG_SUGGESTFLAGS:
+ case RPMTAG_SUPPLEMENTFLAGS:
+ case RPMTAG_ENHANCEFLAGS:
+ case RPMTAG_CONFLICTFLAGS:
+ case RPMTAG_OBSOLETEFLAGS:
+ if (fc->skipReq)
continue;
tagflags = RPMSENSE_FIND_REQUIRES;
break;
- case RPMTAG_ENHANCESFLAGS:
- if (!pkg->autoProv)
- continue;
- failnonzero = 0;
- tagflags = RPMSENSE_FIND_REQUIRES | RPMSENSE_MISSINGOK;
- if (strcmp(dm->msg, "Supplements") == 0)
- tagflags |= RPMSENSE_STRONG;
- break;
default:
continue;
break;
@@ -1210,7 +1310,7 @@ static rpmRC rpmfcGenerateDependsHelper(const rpmSpec spec, Package pkg, rpmfi f
free(s);
if (rpmfcExec(dm->argv, sb_stdin, &sb_stdout,
- failnonzero, spec->buildRoot) == -1)
+ failnonzero, fc->buildRoot) == -1)
continue;
if (sb_stdout == NULL) {
@@ -1220,7 +1320,7 @@ static rpmRC rpmfcGenerateDependsHelper(const rpmSpec spec, Package pkg, rpmfi f
}
/* Parse dependencies into header */
- rc = parseRCPOT(spec, pkg, getStringBuf(sb_stdout), tag, 0, tagflags);
+ rc = parseRCPOT(NULL, fc->pkg, getStringBuf(sb_stdout), dm->ntag != -1 ? dm->ntag : RPMTAG_REQUIRENAME, 0, tagflags, addReqProvPkg, NULL);
freeStringBuf(sb_stdout);
if (rc) {
@@ -1234,11 +1334,26 @@ static rpmRC rpmfcGenerateDependsHelper(const rpmSpec spec, Package pkg, rpmfi f
return rc;
}
+rpmRC rpmfcApply(rpmfc fc)
+{
+ rpmRC rc;
+ /* If new-fangled dependency generation is disabled ... */
+ if (!rpmExpandNumeric("%{?_use_internal_dependency_generator}")) {
+ /* ... then generate dependencies using %{__find_requires} et al. */
+ rpmlog(RPMLOG_WARNING,
+ _("Deprecated external dependency generator is used!\n"));
+ rc = rpmfcApplyExternal(fc);
+ } else {
+ /* ... otherwise generate per-file dependencies */
+ rc = rpmfcApplyInternal(fc);
+ }
+ return rc;
+}
+
rpmRC rpmfcGenerateDepends(const rpmSpec spec, Package pkg)
{
- rpmfi fi = pkg->cpioList;
+ rpmfi fi = rpmfilesIter(pkg->cpioList, RPMFI_ITER_FWD);
rpmfc fc = NULL;
- ARGV_t av = NULL;
rpm_mode_t * fmode = NULL;
int ac = rpmfiFC(fi);
int genConfigDeps = 0;
@@ -1250,82 +1365,46 @@ rpmRC rpmfcGenerateDepends(const rpmSpec spec, Package pkg)
if (ac <= 0)
goto exit;
- /* Skip packages that have dependency generation disabled. */
- if (! (pkg->autoReq || pkg->autoProv))
- goto exit;
-
- /* If new-fangled dependency generation is disabled ... */
- if (!rpmExpandNumeric("%{?_use_internal_dependency_generator}")) {
- /* ... then generate dependencies using %{__find_requires} et al. */
- rc = rpmfcGenerateDependsHelper(spec, pkg, fi);
- goto exit;
- }
-
/* Extract absolute file paths in argv format. */
- av = xcalloc(ac+1, sizeof(*av));
fmode = xcalloc(ac+1, sizeof(*fmode));
fi = rpmfiInit(fi, 0);
while ((idx = rpmfiNext(fi)) >= 0) {
/* Does package have any %config files? */
genConfigDeps |= (rpmfiFFlags(fi) & RPMFILE_CONFIG);
-
- av[idx] = xstrdup(rpmfiFN(fi));
fmode[idx] = rpmfiFMode(fi);
}
- av[ac] = NULL;
fc = rpmfcCreate(spec->buildRoot, 0);
+ free(fc->pkg);
+ fc->pkg = pkg;
fc->skipProv = !pkg->autoProv;
fc->skipReq = !pkg->autoReq;
- /* Copy (and delete) manually generated dependencies to dictionary. */
- if (!fc->skipProv) {
- rpmds ds = rpmdsNew(pkg->header, RPMTAG_PROVIDENAME, 0);
- rpmdsMerge(&fc->provides, ds);
- rpmdsFree(ds);
-
- headerDel(pkg->header, RPMTAG_PROVIDENAME);
- headerDel(pkg->header, RPMTAG_PROVIDEVERSION);
- headerDel(pkg->header, RPMTAG_PROVIDEFLAGS);
-
+ if (!fc->skipProv && genConfigDeps) {
/* Add config dependency, Provides: config(N) = EVR */
- if (genConfigDeps) {
- ds = rpmdsSingleNS(RPMTAG_PROVIDENAME, "config",
- rpmdsN(pkg->ds), rpmdsEVR(pkg->ds),
- (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
- rpmdsMerge(&fc->provides, ds);
- rpmdsFree(ds);
- }
+ rpmds ds = rpmdsSingleNS(fc->pool, RPMTAG_PROVIDENAME, "config",
+ rpmdsN(pkg->ds), rpmdsEVR(pkg->ds),
+ (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
+ rpmdsMerge(packageDependencies(pkg, RPMTAG_PROVIDENAME), ds);
+ rpmdsFree(ds);
}
-
- if (!fc->skipReq) {
- rpmds ds = rpmdsNew(pkg->header, RPMTAG_REQUIRENAME, 0);
- rpmdsMerge(&fc->requires, ds);
+ if (!fc->skipReq && genConfigDeps) {
+ rpmds ds = rpmdsSingleNS(fc->pool, RPMTAG_REQUIRENAME, "config",
+ rpmdsN(pkg->ds), rpmdsEVR(pkg->ds),
+ (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
+ rpmdsMerge(packageDependencies(pkg, RPMTAG_REQUIRENAME), ds);
rpmdsFree(ds);
-
- headerDel(pkg->header, RPMTAG_REQUIRENAME);
- headerDel(pkg->header, RPMTAG_REQUIREVERSION);
- headerDel(pkg->header, RPMTAG_REQUIREFLAGS);
-
- /* Add config dependency, Requires: config(N) = EVR */
- if (genConfigDeps) {
- ds = rpmdsSingleNS(RPMTAG_REQUIRENAME, "config",
- rpmdsN(pkg->ds), rpmdsEVR(pkg->ds),
- (RPMSENSE_EQUAL|RPMSENSE_CONFIG));
- rpmdsMerge(&fc->requires, ds);
- rpmdsFree(ds);
- }
}
/* Build file class dictionary. */
- rc = rpmfcClassify(fc, av, fmode);
+ rc = rpmfcClassify(fc, pkg->dpaths, fmode);
if ( rc != RPMRC_OK )
goto exit;
/* Build file/package dependency dictionary. */
rc = rpmfcApply(fc);
- if ( rc != RPMRC_OK )
+ if (rc != RPMRC_OK)
goto exit;
/* Add per-file colors(#files) */
@@ -1343,54 +1422,18 @@ rpmRC rpmfcGenerateDepends(const rpmSpec spec, Package pkg)
/* Add per-file classes(#files) */
headerPutUint32(pkg->header, RPMTAG_FILECLASS, fc->fcdictx, fc->nfiles);
- /* Add Provides: */
- if (!fc->skipProv) {
- rpmds pi = rpmdsInit(fc->provides);
- while (rpmdsNext(pi) >= 0) {
- rpmsenseFlags flags = rpmdsFlags(pi);
-
- headerPutString(pkg->header, RPMTAG_PROVIDENAME, rpmdsN(pi));
- headerPutString(pkg->header, RPMTAG_PROVIDEVERSION, rpmdsEVR(pi));
- headerPutUint32(pkg->header, RPMTAG_PROVIDEFLAGS, &flags, 1);
- }
- }
-
- /* Add Requires: */
- if (!fc->skipReq) {
- rpmds pi = rpmdsInit(fc->requires);
- while (rpmdsNext(pi) >= 0) {
- rpmsenseFlags flags = rpmdsFlags(pi);
-
- headerPutString(pkg->header, RPMTAG_REQUIRENAME, rpmdsN(pi));
- headerPutString(pkg->header, RPMTAG_REQUIREVERSION, rpmdsEVR(pi));
- headerPutUint32(pkg->header, RPMTAG_REQUIREFLAGS, &flags, 1);
- }
- }
-
- /* Add Supplements: */
- if (!fc->skipReq) {
- rpmds pi = rpmdsInit(fc->supplements);
- while (rpmdsNext(pi) >= 0) {
- rpmsenseFlags flags = rpmdsFlags(pi);
-
- headerPutString(pkg->header, RPMTAG_ENHANCESNAME, rpmdsN(pi));
- headerPutString(pkg->header, RPMTAG_ENHANCESVERSION, rpmdsEVR(pi));
- headerPutUint32(pkg->header, RPMTAG_ENHANCESFLAGS, &flags, 1);
- }
- }
-
/* Add dependency dictionary(#dependencies) */
if (rpmtdFromArgi(&td, RPMTAG_DEPENDSDICT, fc->ddictx)) {
headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
- }
- /* Add per-file dependency (start,number) pairs (#files) */
- if (rpmtdFromArgi(&td, RPMTAG_FILEDEPENDSX, fc->fddictx)) {
- headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
- }
+ /* Add per-file dependency (start,number) pairs (#files) */
+ if (rpmtdFromArgi(&td, RPMTAG_FILEDEPENDSX, fc->fddictx)) {
+ headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
+ }
- if (rpmtdFromArgi(&td, RPMTAG_FILEDEPENDSN, fc->fddictn)) {
- headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
+ if (rpmtdFromArgi(&td, RPMTAG_FILEDEPENDSN, fc->fddictn)) {
+ headerPut(pkg->header, &td, HEADERPUT_DEFAULT);
+ }
}
@@ -1403,12 +1446,14 @@ rpmRC rpmfcGenerateDepends(const rpmSpec spec, Package pkg)
free(msg);
}
exit:
- printDeps(pkg->header);
+ printDeps(fc);
/* Clean up. */
+ if (fc)
+ fc->pkg = NULL;
free(fmode);
rpmfcFree(fc);
- argvFree(av);
+ rpmfiFree(fi);
return rc;
}
diff --git a/build/rpmfc.h b/build/rpmfc.h
index a05fd0e78..3d87b31cf 100644
--- a/build/rpmfc.h
+++ b/build/rpmfc.h
@@ -45,7 +45,6 @@ typedef const struct rpmfcTokens_s * rpmfcToken;
/** \ingroup rpmfc
* Print results of file classification.
- * @todo Remove debugging routine.
* @param msg message prefix (NULL for none)
* @param fc file classifier
* @param fp output file handle (NULL for stderr)
@@ -107,12 +106,55 @@ rpmds rpmfcProvides(rpmfc fc);
rpmds rpmfcRequires(rpmfc fc);
/** \ingroup rpmfc
+ * Retrieve file classification recommends
+ * @param fc file classifier
+ * @return rpmds dependency set of fc recommends
+ */
+rpmds rpmfcRecommends(rpmfc fc);
+
+/** \ingroup rpmfc
+ * Retrieve file classification suggests
+ * @param fc file classifier
+ * @return rpmds dependency set of fc suggests
+ */
+rpmds rpmfcSuggests(rpmfc fc);
+
+/** \ingroup rpmfc
* Retrieve file classification supplements
* @param fc file classifier
- * @return rpmds dependency set of fc requires
+ * @return rpmds dependency set of fc supplements
*/
rpmds rpmfcSupplements(rpmfc fc);
+/** \ingroup rpmfc
+ * Retrieve file classification enhances
+ * @param fc file classifier
+ * @return rpmds dependency set of fc enhances
+ */
+rpmds rpmfcEnhances(rpmfc fc);
+
+/** \ingroup rpmfc
+ * Retrieve file classification conflicts
+ * @param fc file classifier
+ * @return rpmds dependency set of fc conflicts
+ */
+rpmds rpmfcConflicts(rpmfc fc);
+
+/** \ingroup rpmfc
+ * Retrieve file classification obsoletes
+ * @param fc file classifier
+ * @return rpmds dependency set of fc obsoletes
+ */
+rpmds rpmfcObsoletes(rpmfc fc);
+
+/** \ingroup rpmfc
+ * Retrieve file classification dependencies
+ * @param fc file classifier
+ * @param tagN name tag of the wanted dependency
+ * @return rpmds dependency set of fc requires
+ */
+rpmds rpmfcDependencies(rpmfc fc, rpmTagVal tagN);
+
#ifdef __cplusplus
}
#endif
diff --git a/build/rpmspec.h b/build/rpmspec.h
index 195fc720c..164c9b6ac 100644
--- a/build/rpmspec.h
+++ b/build/rpmspec.h
@@ -36,6 +36,7 @@ enum rpmSpecFlags_e {
RPMSPEC_ANYARCH = (1 << 0),
RPMSPEC_FORCE = (1 << 1),
RPMSPEC_NOLANG = (1 << 2),
+ RPMSPEC_NOUTF8 = (1 << 3),
};
typedef rpmFlags rpmSpecFlags;
@@ -55,6 +56,13 @@ rpmSpecPkgIter rpmSpecPkgIterFree(rpmSpecPkgIter iter);
/* Getters for spec package attributes */
Header rpmSpecPkgHeader(rpmSpecPkg pkg);
+/*
+ * Retrieve package specific parsed spec script section (RPMBUILD_FILE_LIST,
+ * RPMBUILD_FILE_FILE, RPMBUILD_POLICY) as a malloc'ed string.
+ */
+char * rpmSpecPkgGetSection(rpmSpecPkg pkg, int section);
+
+
/* Iterator for spec sources */
rpmSpecSrcIter rpmSpecSrcIterInit(rpmSpec spec);
rpmSpecSrc rpmSpecSrcIterNext(rpmSpecSrcIter iter);
diff --git a/build/spec.c b/build/spec.c
index 4b6b6805d..39599e284 100644
--- a/build/spec.c
+++ b/build/spec.c
@@ -13,6 +13,7 @@
#include <rpm/rpmfileutil.h>
#include "rpmio/rpmlua.h"
+#include "lib/rpmfi_internal.h" /* rpmfiles stuff */
#include "build/rpmbuild_internal.h"
#include "debug.h"
@@ -60,8 +61,8 @@ struct Source * freeSources(struct Source * s)
rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
{
- const char *pname;
char *fullName = NULL;
+ rpmsid nameid = 0;
Package p;
/* "main" package */
@@ -71,46 +72,66 @@ rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
return RPMRC_OK;
}
- /* Construct package name */
- if (flag == PART_SUBNAME) {
- pname = headerGetString(spec->packages->header, RPMTAG_NAME);
- rasprintf(&fullName, "%s-%s", pname, name);
- } else {
- fullName = xstrdup(name);
+ /* Construct partial package name */
+ if (!(flag & PART_NAME)) {
+ rasprintf(&fullName, "%s-%s",
+ headerGetString(spec->packages->header, RPMTAG_NAME), name);
+ name = fullName;
}
+ nameid = rpmstrPoolId(spec->pool, name, 1);
- /* Locate package with fullName */
+ /* Locate package the name */
for (p = spec->packages; p != NULL; p = p->next) {
- pname = headerGetString(p->header, RPMTAG_NAME);
- if (pname && (rstreq(fullName, pname))) {
+ if (p->name && p->name == nameid) {
break;
}
}
- free(fullName);
+
+ if (!(flag & PART_QUIET)) {
+ if (p == NULL && pkg != NULL) {
+ rpmlog(RPMLOG_ERR, _("line %d: %s: package %s does not exist\n"),
+ spec->lineNum, spec->line, name);
+ } else if (p != NULL && pkg == NULL) {
+ rpmlog(RPMLOG_ERR, _("line %d: %s: package %s already exists\n"),
+ spec->lineNum, spec->line, name);
+ }
+ }
+
+ if (fullName == name)
+ free(fullName);
if (pkg)
*pkg = p;
return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
}
-Package newPackage(rpmSpec spec)
+Package newPackage(const char *name, rpmstrPool pool, Package *pkglist)
{
Package p = xcalloc(1, sizeof(*p));
p->header = headerNew();
p->autoProv = 1;
p->autoReq = 1;
p->fileList = NULL;
+ p->fileExcludeList = NULL;
p->fileFile = NULL;
p->policyList = NULL;
-
- if (spec->packages == NULL) {
- spec->packages = p;
- } else {
- Package pp;
- /* Always add package to end of list */
- for (pp = spec->packages; pp->next != NULL; pp = pp->next)
- {};
- pp->next = p;
+ p->fileRenameMap = NULL;
+ p->pool = rpmstrPoolLink(pool);
+ p->dpaths = NULL;
+
+ if (name)
+ p->name = rpmstrPoolId(p->pool, name, 1);
+
+ if (pkglist) {
+ if (*pkglist == NULL) {
+ *pkglist = p;
+ } else {
+ Package pp;
+ /* Always add package to end of list */
+ for (pp = *pkglist; pp->next != NULL; pp = pp->next)
+ {};
+ pp->next = p;
+ }
}
p->next = NULL;
@@ -129,13 +150,25 @@ static Package freePackage(Package pkg)
pkg->header = headerFree(pkg->header);
pkg->ds = rpmdsFree(pkg->ds);
+
+ for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
+ pkg->dependencies[i] = rpmdsFree(pkg->dependencies[i]);
+ }
+
pkg->fileList = argvFree(pkg->fileList);
+ pkg->fileExcludeList = argvFree(pkg->fileExcludeList);
pkg->fileFile = argvFree(pkg->fileFile);
pkg->policyList = argvFree(pkg->policyList);
- pkg->cpioList = rpmfiFree(pkg->cpioList);
+ pkg->removePostfixes = argvFree(pkg->removePostfixes);
+ pkg->fileRenameMap = fileRenameHashFree(pkg->fileRenameMap);
+ pkg->cpioList = rpmfilesFree(pkg->cpioList);
+ pkg->dpaths = argvFree(pkg->dpaths);
pkg->icon = freeSources(pkg->icon);
pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
+ pkg->fileTriggerFiles = freeTriggerFiles(pkg->fileTriggerFiles);
+ pkg->transFileTriggerFiles = freeTriggerFiles(pkg->transFileTriggerFiles);
+ pkg->pool = rpmstrPoolFree(pkg->pool);
free(pkg);
return NULL;
@@ -153,6 +186,21 @@ static Package freePackages(Package packages)
return NULL;
}
+rpmds * packageDependencies(Package pkg, rpmTagVal tag)
+{
+ for (int i=0; i<PACKAGE_NUM_DEPS; i++) {
+ if (pkg->dependencies[i] == NULL) {
+ return &pkg->dependencies[i];
+ }
+ rpmTagVal tagN = rpmdsTagN(pkg->dependencies[i]);
+ if (tagN == tag || tagN == 0) {
+ return &pkg->dependencies[i];
+ }
+ }
+ return NULL;
+}
+
+
rpmSpec newSpec(void)
{
rpmSpec spec = xcalloc(1, sizeof(*spec));
@@ -186,8 +234,7 @@ rpmSpec newSpec(void)
spec->sourceRpmName = NULL;
spec->sourcePkgId = NULL;
- spec->sourceHeader = NULL;
- spec->sourceCpioList = NULL;
+ spec->sourcePackage = NULL;
spec->buildRoot = NULL;
spec->buildSubdir = NULL;
@@ -201,11 +248,14 @@ rpmSpec newSpec(void)
spec->flags = RPMSPEC_NONE;
spec->macros = rpmGlobalMacroContext;
+ spec->pool = rpmstrPoolCreate();
#ifdef WITH_LUA
{
/* make sure patches and sources tables always exist */
rpmlua lua = NULL; /* global state */
+ rpmluaDelVar(lua, "patches");
+ rpmluaDelVar(lua, "sources");
rpmluaPushTable(lua, "patches");
rpmluaPushTable(lua, "sources");
rpmluaPop(lua);
@@ -243,8 +293,7 @@ rpmSpec rpmSpecFree(rpmSpec spec)
spec->sourceRpmName = _free(spec->sourceRpmName);
spec->sourcePkgId = _free(spec->sourcePkgId);
- spec->sourceHeader = headerFree(spec->sourceHeader);
- spec->sourceCpioList = rpmfiFree(spec->sourceCpioList);
+ spec->sourcePackage = freePackage(spec->sourcePackage);
spec->buildRestrictions = headerFree(spec->buildRestrictions);
@@ -266,6 +315,7 @@ rpmSpec rpmSpecFree(rpmSpec spec)
spec->sources = freeSources(spec->sources);
spec->packages = freePackages(spec->packages);
+ spec->pool = rpmstrPoolFree(spec->pool);
spec = _free(spec);
@@ -274,12 +324,12 @@ rpmSpec rpmSpecFree(rpmSpec spec)
Header rpmSpecSourceHeader(rpmSpec spec)
{
- return spec->sourceHeader;
+ return (spec && spec->sourcePackage) ? spec->sourcePackage->header : NULL;
}
rpmds rpmSpecDS(rpmSpec spec, rpmTagVal tag)
{
- return (spec != NULL) ? rpmdsNew(spec->buildRestrictions, tag, 0) : NULL;
+ return (spec != NULL) ? rpmdsNew(spec->sourcePackage->header, tag, 0) : NULL;
}
rpmps rpmSpecCheckDeps(rpmts ts, rpmSpec spec)
@@ -341,6 +391,18 @@ Header rpmSpecPkgHeader(rpmSpecPkg pkg)
return (pkg != NULL) ? pkg->header : NULL;
}
+char* rpmSpecPkgGetSection(rpmSpecPkg pkg, int section)
+{
+ if (pkg) {
+ switch (section) {
+ case RPMBUILD_FILE_FILE: return argvJoin(pkg->fileFile, "");
+ case RPMBUILD_FILE_LIST: return argvJoin(pkg->fileList, "");
+ case RPMBUILD_POLICY: return argvJoin(pkg->policyList, "");
+ }
+ }
+ return NULL;
+}
+
rpmSpecSrcIter rpmSpecSrcIterInit(rpmSpec spec)
{
SPEC_LISTITER_INIT(rpmSpecSrcIter, sources);
@@ -405,21 +467,20 @@ int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
goto exit;
}
- if (qva->qva_source == RPMQV_SPECRPMS) {
+ if (qva->qva_source == RPMQV_SPECRPMS ||
+ qva->qva_source == RPMQV_SPECBUILTRPMS) {
+
res = 0;
for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
-#if 0
- /*
- * XXX FIXME: whether to show all or just the packages that
- * would be built needs to be made caller specifiable, for now
- * revert to "traditional" behavior as existing tools rely on this.
- */
- if (pkg->fileList == NULL) continue;
-#endif
+
+ if (qva->qva_source == RPMQV_SPECBUILTRPMS && pkg->fileList == NULL)
+ continue;
+
res += qva->qva_showPackage(qva, ts, pkg->header);
}
} else {
- res = qva->qva_showPackage(qva, ts, spec->sourceHeader);
+ Package sourcePkg = spec->sourcePackage;
+ res = qva->qva_showPackage(qva, ts, sourcePkg->header);
}
exit: