diff options
Diffstat (limited to 'build')
-rw-r--r-- | build/Makefile.am | 11 | ||||
-rw-r--r-- | build/build.c | 26 | ||||
-rw-r--r-- | build/expression.c | 4 | ||||
-rw-r--r-- | build/files.c | 1832 | ||||
-rw-r--r-- | build/pack.c | 779 | ||||
-rw-r--r-- | build/parseBuildInstallClean.c | 2 | ||||
-rw-r--r-- | build/parseChangelog.c | 113 | ||||
-rw-r--r-- | build/parseDescription.c | 23 | ||||
-rw-r--r-- | build/parseFiles.c | 18 | ||||
-rw-r--r-- | build/parsePolicies.c | 5 | ||||
-rw-r--r-- | build/parsePreamble.c | 258 | ||||
-rw-r--r-- | build/parsePrep.c | 89 | ||||
-rw-r--r-- | build/parseReqs.c | 374 | ||||
-rw-r--r-- | build/parseScript.c | 139 | ||||
-rw-r--r-- | build/parseSpec.c | 308 | ||||
-rw-r--r-- | build/reqprov.c | 115 | ||||
-rw-r--r-- | build/rpmbuild.h | 6 | ||||
-rw-r--r-- | build/rpmbuild_internal.h | 132 | ||||
-rw-r--r-- | build/rpmbuild_misc.h | 28 | ||||
-rw-r--r-- | build/rpmfc.c | 775 | ||||
-rw-r--r-- | build/rpmfc.h | 46 | ||||
-rw-r--r-- | build/rpmspec.h | 8 | ||||
-rw-r--r-- | build/spec.c | 137 |
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 **) ×, &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, ¯o, 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: |