static int addPrefixes(Header h, rpmRelocation *relocations, int numRelocations) { struct rpmtd_s validRelocs; const char *validprefix; const char ** actualRelocations; int numActual = 0; headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM); /* * If no relocations are specified (usually the case), then return the * original header. If there are prefixes, however, then INSTPREFIXES * should be added for RPM_INSTALL_PREFIX environ variables in scriptlets, * but, since relocateFileList() can be called more than once for * the same header, don't bother if already present. */ if (relocations == NULL || numRelocations == 0) { if (rpmtdCount(&validRelocs) > 0) { if (!headerIsEntry(h, RPMTAG_INSTPREFIXES)) { rpmtdSetTag(&validRelocs, RPMTAG_INSTPREFIXES); headerPut(h, &validRelocs, HEADERPUT_DEFAULT); } rpmtdFreeData(&validRelocs); } return 0; } actualRelocations = xmalloc(rpmtdCount(&validRelocs) * sizeof(*actualRelocations)); rpmtdInit(&validRelocs); while ((validprefix = rpmtdNextString(&validRelocs))) { int j; for (j = 0; j < numRelocations; j++) { if (relocations[j].oldPath == NULL || /* XXX can't happen */ !rstreq(validprefix, relocations[j].oldPath)) continue; /* On install, a relocate to NULL means skip the path. */ if (relocations[j].newPath) { actualRelocations[numActual] = relocations[j].newPath; numActual++; } break; } if (j == numRelocations) { actualRelocations[numActual] = validprefix; numActual++; } } rpmtdFreeData(&validRelocs); if (numActual) { headerPutStringArray(h, RPMTAG_INSTPREFIXES, actualRelocations, numActual); } free(actualRelocations); /* When any relocations are present there'll be more work to do */ return 1; }
int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix) { mode_t amode = rpmfiFModeIndex(afi, aix); mode_t bmode = rpmfiFModeIndex(bfi, bix); rpmFileTypes awhat = rpmfiWhatis(amode); if ((rpmfiFFlagsIndex(afi, aix) & RPMFILE_GHOST) || (rpmfiFFlagsIndex(bfi, bix) & RPMFILE_GHOST)) return 0; if (amode != bmode) return 1; if (!rstreq(rpmfiFUserIndex(afi, aix), rpmfiFUserIndex(bfi, bix))) return 1; if (!rstreq(rpmfiFGroupIndex(afi, aix), rpmfiFGroupIndex(bfi, bix))) return 1; if (awhat == LINK) { const char * alink = rpmfiFLinkIndex(afi, aix); const char * blink = rpmfiFLinkIndex(bfi, bix); if (alink == blink) return 0; if (alink == NULL) return 1; if (blink == NULL) return -1; return strcmp(alink, blink); } else if (awhat == REG) { size_t adiglen, bdiglen; int aalgo, balgo; const unsigned char * adigest, * bdigest; adigest = rpmfiFDigestIndex(afi, aix, &aalgo, &adiglen); bdigest = rpmfiFDigestIndex(bfi, bix, &balgo, &bdiglen); if (adigest == bdigest) return 0; if (adigest == NULL) return 1; if (bdigest == NULL) return -1; /* can't meaningfully compare different hash types */ if (aalgo != balgo || adiglen != bdiglen) return -1; return memcmp(adigest, bdigest, adiglen); } else if (awhat == CDEV || awhat == BDEV) { if (rpmfiFRdevIndex(afi, aix) != rpmfiFRdevIndex(bfi, bix)) return 1; } return 0; }
int rpmugUid(const char * thisUname, uid_t * uid) { static char * lastUname = NULL; static size_t lastUnameLen = 0; static size_t lastUnameAlloced; static uid_t lastUid; struct passwd * pwent; size_t thisUnameLen; if (!thisUname) { lastUnameLen = 0; return -1; } else if (rstreq(thisUname, "root")) { *uid = 0; return 0; } thisUnameLen = strlen(thisUname); if (lastUname == NULL || thisUnameLen != lastUnameLen || !rstreq(thisUname, lastUname)) { if (lastUnameAlloced < thisUnameLen + 1) { lastUnameAlloced = thisUnameLen + 10; lastUname = xrealloc(lastUname, lastUnameAlloced); /* XXX memory leak */ } strcpy(lastUname, thisUname); pwent = getpwnam(thisUname); if (pwent == NULL) { /* FIX: shrug */ endpwent(); pwent = getpwnam(thisUname); if (pwent == NULL) return -1; } lastUid = pwent->pw_uid; } *uid = lastUid; return 0; }
static rpmPlugin rpmpluginsGetPlugin(rpmPlugins plugins, const char *name) { int i; for (i = 0; i < plugins->count; i++) { rpmPlugin plugin = plugins->plugins[i]; if (rstreq(plugin->name, name)) { return plugin; } } return NULL; }
headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt) { const struct headerFormatFunc_s * ext; headerTagFormatFunction func = NULL; for (ext = rpmHeaderFormats; ext->name != NULL; ext++) { if (rstreq(ext->name, fmt)) { func = ext->func; break; } } return func; }
int rpmtsSetRootDir(rpmts ts, const char * rootDir) { if (ts == NULL || (rootDir && rootDir[0] != '/')) { return -1; } ts->rootDir = _free(ts->rootDir); /* Ensure clean path with a trailing slash */ ts->rootDir = rootDir ? rpmGetPath(rootDir, NULL) : xstrdup("/"); if (!rstreq(ts->rootDir, "/")) { rstrcat(&ts->rootDir, "/"); } return 0; }
static char * writeScript(const char *cmd, const char *script) { char *fn = NULL; size_t slen = strlen(script); int ok = 0; FD_t fd = rpmMkTempFile("/", &fn); if (Ferror(fd)) goto exit; if (rpmIsDebug() && (rstreq(cmd, "/bin/sh") || rstreq(cmd, "/bin/bash"))) { static const char set_x[] = "set -x\n"; /* Assume failures will be caught by the write below */ Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd); } ok = (Fwrite(script, sizeof(script[0]), slen, fd) == slen); exit: if (!ok) fn = _free(fn); Fclose(fd); return fn; }
/* Add extra provides to package. */ static void addPackageProvides(Package pkg) { const char *arch, *name; char *evr, *isaprov; rpmsenseFlags pflags = RPMSENSE_EQUAL; /* <name> = <evr> provide */ 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 * 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)) { addReqProv(pkg, RPMTAG_PROVIDENAME, isaprov, evr, pflags, 0); } free(isaprov); free(evr); }
urltype urlIsURL(const char * url) { const struct urlstring *us; if (url && *url) { for (us = urlstrings; us->leadin != NULL; us++) { if (!rstreqn(url, us->leadin, strlen(us->leadin))) continue; return us->ret; } if (rstreq(url, "-")) return URL_IS_DASH; } return URL_IS_UNKNOWN; }
void rpmdsNotify(rpmds ds, const char * where, int rc) { const char *DNEVR; if (!rpmIsDebug()) return; if (!(ds != NULL && ds->i >= 0 && ds->i < ds->Count)) return; if (!(ds->Type != NULL && (DNEVR = rpmdsDNEVR(ds)) != NULL)) return; rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type, (rstreq(DNEVR, "cached") ? DNEVR : DNEVR+2), (rc ? _("NO ") : _("YES")), (where != NULL ? where : "")); }
int rpmfiConfigConflict(const rpmfi fi) { const char * fn = rpmfiFN(fi); rpmfileAttrs flags = rpmfiFFlags(fi); char buffer[1024]; rpmFileTypes newWhat, diskWhat; struct stat sb; if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) { return 0; } diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); newWhat = rpmfiWhatis(rpmfiFMode(fi)); if (newWhat != LINK && newWhat != REG) return 1; if (diskWhat != newWhat) return 1; memset(buffer, 0, sizeof(buffer)); if (newWhat == REG) { int algo; size_t diglen; const unsigned char *ndigest = rpmfiFDigest(fi, &algo, &diglen); if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL)) return 0; /* assume file has been removed */ if (ndigest && !memcmp(ndigest, buffer, diglen)) return 0; /* unmodified config file */ } else /* newWhat == LINK */ { const char * nFLink; ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1); if (link_len == -1) return 0; /* assume file has been removed */ buffer[link_len] = '\0'; nFLink = rpmfiFLink(fi); if (nFLink && rstreq(nFLink, buffer)) return 0; /* unmodified config file */ } return 1; }
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd, ARGV_const_t prefixes, int warn_only, rpmPlugins plugins) { ARGV_t args = NULL; rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR; rpmRC rc; int script_type = RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC; if (script == NULL) return RPMRC_OK; /* construct a new argv as we can't modify the one from header */ if (script->args) { argvAppend(&args, script->args); } else { argvAdd(&args, "/bin/sh"); } if (rstreq(args[0], "<lua>")) script_type = RPMSCRIPTLET_NONE; /* Run scriptlet pre hook for all plugins */ rc = rpmpluginsCallScriptletPre(plugins, script->descr, script_type); if (rc != RPMRC_FAIL) { if (script_type & RPMSCRIPTLET_EXEC) { rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2); } else { rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2); } } /* Run scriptlet post hook for all plugins */ rpmpluginsCallScriptletPost(plugins, script->descr, script_type, rc); argvFree(args); return rc; }
rpmRC rpmtsSetupTransactionPlugins(rpmts ts) { rpmRC rc = RPMRC_OK; char *plugins = NULL, *plugin = NULL; const char *delims = ","; rpmPlugins tsplugins; /* * Assume allocated equals initialized. There are some oddball cases * (verification of non-installed package) where this is not true * currently but that's not a new issue. */ if (ts->plugins != NULL) return RPMRC_OK; plugins = rpmExpand("%{?__transaction_plugins}", NULL); if (!plugins || rstreq(plugins, "")) { goto exit; } tsplugins = rpmtsPlugins(ts); plugin = strtok(plugins, delims); while(plugin != NULL) { rpmlog(RPMLOG_DEBUG, "plugin is %s\n", plugin); if (!rpmpluginsPluginAdded(tsplugins, plugin)) { if (rpmpluginsAddPlugin(tsplugins, "transaction", plugin) == RPMRC_FAIL) { /* any configured plugin failing to load is a failure */ rc = RPMRC_FAIL; } } plugin = strtok(NULL, delims); } exit: free(plugins); return rc; }
static scidx_t strcachePut(strcache cache, const char *str) { int found = 0; scidx_t ret; for (scidx_t i = 0; i < cache->num; i++) { if (rstreq(str, cache->uniq[i])) { ret = i; found = 1; break; } } if (!found) { /* blow up on index wraparound */ assert((scidx_t)(cache->num + 1) > cache->num); cache->uniq = xrealloc(cache->uniq, sizeof(cache->uniq) * (cache->num+1)); cache->uniq[cache->num] = xstrdup(str); ret = cache->num; cache->num++; } return ret; }
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; }
/* Check a dependency set for problems */ static void checkDS(rpmts ts, depCache dcache, rpmte te, const char * pkgNEVRA, rpmds ds, const char * depName, rpm_color_t tscolor) { rpm_color_t dscolor; /* require-problems are unsatisfied, others appear "satisfied" */ int is_problem = (rpmdsTagN(ds) == RPMTAG_REQUIRENAME); ds = rpmdsInit(ds); while (rpmdsNext(ds) >= 0) { /* Filter out dependencies that came along for the ride. */ if (depName != NULL && !rstreq(depName, rpmdsN(ds))) continue; /* Ignore colored dependencies not in our rainbow. */ dscolor = rpmdsColor(ds); if (tscolor && dscolor && !(tscolor & dscolor)) continue; if (unsatisfiedDepend(ts, dcache, ds) == is_problem) rpmteAddDepProblem(te, pkgNEVRA, ds, NULL); } }
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; }
static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName, CSA_t csa, char **cookie) { FD_t fd = NULL; FD_t ifd = NULL; ssize_t count; char * sigtarget = NULL;; char * rpmio_flags = NULL; char * SHA1 = NULL; const char *s; char *buf = NULL; 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)) rpmio_flags = rpmExpand("%{?_source_payload}", NULL); else rpmio_flags = rpmExpand("%{?_binary_payload}", NULL); if (!(rpmio_flags && *rpmio_flags)) { rpmio_flags = _free(rpmio_flags); rpmio_flags = xstrdup("w9.gzdio"); } s = strchr(rpmio_flags, '.'); if (s) { const char *compr = NULL; headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio"); if (rstreq(s+1, "ufdio")) { compr = NULL; } else if (rstreq(s+1, "gzdio")) { compr = "gzip"; #if HAVE_BZLIB_H } 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"); #endif #if HAVE_LZMA_H } else if (rstreq(s+1, "xzdio")) { compr = "xz"; (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1"); } else if (rstreq(s+1, "lzdio")) { compr = "lzma"; (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1"); #endif } else { rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"), rpmio_flags); rc = RPMRC_FAIL; goto exit; } if (compr) headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr); buf = xstrdup(rpmio_flags); buf[s - rpmio_flags] = '\0'; headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1); free(buf); } /* Create and add the cookie */ if (cookie) { rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime())); headerPutString(h, RPMTAG_COOKIE, *cookie); } /* 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; } /* 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")); 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 if (Fileno(csa->cpioFdIn) >= 0) { rc = cpio_copy(fd, csa); } else { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Bad CSA data\n")); } } if (rc != RPMRC_OK) goto exit; (void) Fclose(fd); fd = NULL; (void) unlink(fileName); /* Generate the signature */ (void) fflush(stdout); sig = rpmNewSignature(); /* * 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. */ 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); } { /* 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); } } /* 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")); goto exit; } /* Open the output file */ 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); lead = rpmLeadFree(lead); if (rc != RPMRC_OK) { rc = RPMRC_FAIL; 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; goto exit; } /* 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)); 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); if (nh == NULL) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } #ifdef NOTYET (void) headerMergeLegacySigs(nh, sig); #endif xx = headerWrite(fd, nh, HEADER_MAGIC_YES); nh = headerFree(nh); 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. */ buf = xmalloc(BUFSIZ); while ((count = Fread(buf, 1, BUFSIZ, ifd)) > 0) { if (count == -1) { free(buf); rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) { free(buf); rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } } free(buf); rc = RPMRC_OK; exit: rpmio_flags = _free(rpmio_flags); SHA1 = _free(SHA1); h = headerFree(h); /* 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; } } sig = rpmFreeSignature(sig); if (ifd) { (void) Fclose(ifd); ifd = NULL; } if (fd) { (void) Fclose(fd); fd = NULL; } if (sigtarget) { (void) unlink(sigtarget); sigtarget = _free(sigtarget); } if (rc == RPMRC_OK) rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName); else (void) unlink(fileName); return rc; }
rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing) { const char * fn = rpmfiFN(nfi); rpmfileAttrs newFlags = rpmfiFFlags(nfi); char buffer[1024]; rpmFileTypes dbWhat, newWhat, diskWhat; struct stat sb; int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE; if (lstat(fn, &sb)) { /* * The file doesn't exist on the disk. Create it unless the new * package has marked it as missingok, or allfiles is requested. */ if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) { rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n", fn); return FA_SKIP; } else { return FA_CREATE; } } diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); dbWhat = rpmfiWhatis(rpmfiFMode(ofi)); newWhat = rpmfiWhatis(rpmfiFMode(nfi)); /* * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore * them in older packages as well. */ if (newWhat == XDIR) return FA_CREATE; if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK) return save; else if (newWhat != dbWhat && diskWhat != dbWhat) return save; else if (dbWhat != newWhat) return FA_CREATE; else if (dbWhat != LINK && dbWhat != REG) return FA_CREATE; /* * This order matters - we'd prefer to CREATE the file if at all * possible in case something else (like the timestamp) has changed. */ memset(buffer, 0, sizeof(buffer)); if (dbWhat == REG) { pgpHashAlgo oalgo, nalgo; size_t odiglen, ndiglen; const unsigned char * odigest, * ndigest; odigest = rpmfiFDigest(ofi, &oalgo, &odiglen); if (diskWhat == REG) { if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL)) return FA_CREATE; /* assume file has been removed */ if (odigest && !memcmp(odigest, buffer, odiglen)) return FA_CREATE; /* unmodified config file, replace. */ } ndigest = rpmfiFDigest(nfi, &nalgo, &ndiglen); /* Can't compare different hash types, backup to avoid data loss */ if (oalgo != nalgo || odiglen != ndiglen) return save; if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen)) return FA_SKIP; /* identical file, don't bother. */ } else /* dbWhat == LINK */ { const char * oFLink, * nFLink; oFLink = rpmfiFLink(ofi); if (diskWhat == LINK) { if (readlink(fn, buffer, sizeof(buffer) - 1) == -1) return FA_CREATE; /* assume file has been removed */ if (oFLink && rstreq(oFLink, buffer)) return FA_CREATE; /* unmodified config file, replace. */ } nFLink = rpmfiFLink(nfi); if (oFLink && nFLink && rstreq(oFLink, nFLink)) return FA_SKIP; /* identical file, don't bother. */ } /* * The config file on the disk has been modified, but * the ones in the two packages are different. It would * be nice if RPM was smart enough to at least try and * merge the difference ala CVS, but... */ return save; }
static rpmRC processPolicies(rpmSpec spec, Package pkg, int test) { const char *path = NULL; char *name = NULL; char *types = NULL; uint32_t flags = 0; poptContext optCon = NULL; rpmRC rc = RPMRC_FAIL; struct poptOption optionsTable[] = { {"name", 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL}, {"types", 't', POPT_ARG_STRING, &types, 't', NULL, NULL}, {"base", 'b', POPT_ARGFLAG_OR, &flags, RPMPOL_FLAG_BASE, NULL, NULL}, POPT_TABLEEND }; if (!spec || !pkg) { goto exit; } for (ARGV_const_t pol = pkg->policyList; *pol != NULL; pol++) { ModuleRec mod; const char *line = *pol; const char **argv = NULL; int argc = 0; int err; if ((err = poptParseArgvString(line, &argc, &argv))) { rpmlog(RPMLOG_ERR, _("Error parsing %s: %s\n"), line, poptStrerror(err)); goto exit; } if (!rstreq(argv[0], "%semodule")) { rpmlog(RPMLOG_ERR, _("Expecting %%semodule tag: %s\n"), line); goto exit; } optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); while (poptGetNextOpt(optCon) > 0) { } path = poptGetArg(optCon); if (!path) { rpmlog(RPMLOG_ERR, _("Missing module path in line: %s\n"), line); goto exit; } if (poptPeekArg(optCon)) { rpmlog(RPMLOG_ERR, _("Too many arguments in line: %s\n"), line); goto exit; } mod = newModule(path, name, types, flags); if (!mod) { goto exit; } if (writeModuleToHeader(mod, pkg) != RPMRC_OK) { freeModule(mod); goto exit; } freeModule(mod); } rc = RPMRC_OK; exit: return rc; }
void rpmRelocationBuild(Header h, rpmRelocation *rawrelocs, int *rnrelocs, rpmRelocation **rrelocs, uint8_t **rbadrelocs) { int i; struct rpmtd_s validRelocs; rpmRelocation * relocs = NULL; uint8_t *badrelocs = NULL; int nrelocs = 0; for (rpmRelocation *r = rawrelocs; r->oldPath || r->newPath; r++) nrelocs++; headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM); relocs = xmalloc(sizeof(*relocs) * (nrelocs+1)); /* Build sorted relocation list from raw relocations. */ for (i = 0; i < nrelocs; i++) { char * t; /* * Default relocations (oldPath == NULL) are handled in the UI, * not rpmlib. */ if (rawrelocs[i].oldPath == NULL) continue; /* XXX can't happen */ /* FIXME: Trailing /'s will confuse us greatly. Internal ones will too, but those are more trouble to fix up. :-( */ t = xstrdup(rawrelocs[i].oldPath); relocs[i].oldPath = (t[0] == '/' && t[1] == '\0') ? t : stripTrailingChar(t, '/'); /* An old path w/o a new path is valid, and indicates exclusion */ if (rawrelocs[i].newPath) { int valid = 0; const char *validprefix; t = xstrdup(rawrelocs[i].newPath); relocs[i].newPath = (t[0] == '/' && t[1] == '\0') ? t : stripTrailingChar(t, '/'); /* FIX: relocations[i].oldPath == NULL */ /* Verify that the relocation's old path is in the header. */ rpmtdInit(&validRelocs); while ((validprefix = rpmtdNextString(&validRelocs))) { if (rstreq(validprefix, relocs[i].oldPath)) { valid = 1; break; } } if (!valid) { if (badrelocs == NULL) badrelocs = xcalloc(nrelocs, sizeof(*badrelocs)); badrelocs[i] = 1; } } else { relocs[i].newPath = NULL; } } relocs[i].oldPath = NULL; relocs[i].newPath = NULL; sortRelocs(relocs, nrelocs); rpmtdFreeData(&validRelocs); *rrelocs = relocs; *rnrelocs = nrelocs; *rbadrelocs = badrelocs; }
int headerAddI18NString(Header h, rpmTagVal tag, const char * string, const char * lang) { indexEntry table, entry; const char ** strArray; int length; int ghosts; rpm_count_t i, langNum; char * buf; table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE); entry = findEntry(h, tag, RPM_I18NSTRING_TYPE); if (!table && entry) return 0; /* this shouldn't ever happen!! */ if (!table && !entry) { const char * charArray[2]; rpm_count_t count = 0; struct rpmtd_s td; if (!lang || (lang[0] == 'C' && lang[1] == '\0')) { charArray[count++] = "C"; } else { charArray[count++] = "C"; charArray[count++] = lang; } rpmtdReset(&td); td.tag = RPMTAG_HEADERI18NTABLE; td.type = RPM_STRING_ARRAY_TYPE; td.data = (void *) charArray; td.count = count; if (!headerPut(h, &td, HEADERPUT_DEFAULT)) return 0; table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE); } if (!table) return 0; if (!lang) lang = "C"; { const char * l = table->data; for (langNum = 0; langNum < table->info.count; langNum++) { if (rstreq(l, lang)) break; l += strlen(l) + 1; } } if (langNum >= table->info.count) { length = strlen(lang) + 1; if (ENTRY_IN_REGION(table)) { char * t = xmalloc(table->length + length); memcpy(t, table->data, table->length); table->data = t; table->info.offset = 0; } else table->data = xrealloc(table->data, table->length + length); memmove(((char *)table->data) + table->length, lang, length); table->length += length; table->info.count++; } if (!entry) { int rc; struct rpmtd_s td; strArray = xmalloc(sizeof(*strArray) * (langNum + 1)); for (i = 0; i < langNum; i++) strArray[i] = ""; strArray[langNum] = string; rpmtdReset(&td); td.tag = tag; td.type = RPM_I18NSTRING_TYPE; td.data = strArray; td.count = langNum + 1; rc = headerPut(h, &td, HEADERPUT_DEFAULT); free(strArray); return rc; } else if (langNum >= entry->info.count) { ghosts = langNum - entry->info.count; length = strlen(string) + 1 + ghosts; if (ENTRY_IN_REGION(entry)) { char * t = xmalloc(entry->length + length); memcpy(t, entry->data, entry->length); entry->data = t; entry->info.offset = 0; } else entry->data = xrealloc(entry->data, entry->length + length); memset(((char *)entry->data) + entry->length, '\0', ghosts); memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1); entry->length += length; entry->info.count = langNum + 1; } else { char *b, *be, *e, *ee, *t; size_t bn, sn, en; /* Set beginning/end pointers to previous data */ b = be = e = ee = entry->data; for (i = 0; i < table->info.count; i++) { if (i == langNum) be = ee; ee += strlen(ee) + 1; if (i == langNum) e = ee; } /* Get storage for new buffer */ bn = (be-b); sn = strlen(string) + 1; en = (ee-e); length = bn + sn + en; t = buf = xmalloc(length); /* Copy values into new storage */ memcpy(t, b, bn); t += bn; memcpy(t, string, sn); t += sn; memcpy(t, e, en); t += en; /* Replace i18N string array */ entry->length -= strlen(be) + 1; entry->length += sn; if (ENTRY_IN_REGION(entry)) { entry->info.offset = 0; } else entry->data = _free(entry->data); entry->data = buf; } return 0; }
void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, rpmfs fs, Header h) { char ** baseNames; char ** dirNames; uint32_t * dirIndexes; rpm_count_t fileCount, dirCount; int nrelocated = 0; int fileAlloced = 0; char * fn = NULL; int haveRelocatedBase = 0; size_t maxlen = 0; int i, j; struct rpmtd_s bnames, dnames, dindexes, fmodes; if (!addPrefixes(h, relocations, numRelocations)) return; if (rpmIsDebug()) { rpmlog(RPMLOG_DEBUG, "========== relocations\n"); for (i = 0; i < numRelocations; i++) { if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */ if (relocations[i].newPath == NULL) rpmlog(RPMLOG_DEBUG, "%5d exclude %s\n", i, relocations[i].oldPath); else rpmlog(RPMLOG_DEBUG, "%5d relocate %s -> %s\n", i, relocations[i].oldPath, relocations[i].newPath); } } for (i = 0; i < numRelocations; i++) { if (relocations[i].newPath == NULL) continue; size_t len = strlen(relocations[i].newPath); if (len > maxlen) maxlen = len; } headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, HEADERGET_ALLOC); headerGet(h, RPMTAG_DIRNAMES, &dnames, HEADERGET_MINMEM); headerGet(h, RPMTAG_FILEMODES, &fmodes, HEADERGET_MINMEM); /* TODO XXX ugh.. use rpmtd iterators & friends instead */ baseNames = bnames.data; dirIndexes = dindexes.data; fileCount = rpmtdCount(&bnames); dirCount = rpmtdCount(&dnames); /* XXX TODO: use rpmtdDup() instead */ dirNames = dnames.data = duparray(dnames.data, dirCount); dnames.flags |= RPMTD_PTR_ALLOCED; /* * For all relocations, we go through sorted file/relocation lists * backwards so that /usr/local relocations take precedence over /usr * ones. */ /* Relocate individual paths. */ for (i = fileCount - 1; i >= 0; i--) { rpmFileTypes ft; int fnlen; size_t len = maxlen + strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; if (len >= fileAlloced) { fileAlloced = len * 2; fn = xrealloc(fn, fileAlloced); } assert(fn != NULL); /* XXX can't happen */ *fn = '\0'; fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn; /* * See if this file path needs relocating. */ /* * XXX FIXME: Would a bsearch of the (already sorted) * relocation list be a good idea? */ for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (fnlen < len) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (!(fn[len] == '/' || fnlen == len)) continue; if (!rstreqn(relocations[j].oldPath, fn, len)) continue; break; } if (j < 0) continue; rpmtdSetIndex(&fmodes, i); ft = rpmfiWhatis(rpmtdGetNumber(&fmodes)); /* On install, a relocate to NULL means skip the path. */ if (relocations[j].newPath == NULL) { if (ft == XDIR) { /* Start with the parent, looking for directory to exclude. */ for (j = dirIndexes[i]; j < dirCount; j++) { len = strlen(dirNames[j]) - 1; while (len > 0 && dirNames[j][len-1] == '/') len--; if (fnlen != len) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } } rpmfsSetAction(fs, i, FA_SKIPNSTATE); rpmlog(RPMLOG_DEBUG, "excluding %s %s\n", ftstring(ft), fn); continue; } /* Relocation on full paths only, please. */ if (fnlen != len) continue; rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", fn, relocations[j].newPath); nrelocated++; strcpy(fn, relocations[j].newPath); { char * te = strrchr(fn, '/'); if (te) { if (te > fn) te++; /* root is special */ fnlen = te - fn; } else te = fn + strlen(fn); if (!rstreq(baseNames[i], te)) { /* basename changed too? */ if (!haveRelocatedBase) { /* XXX TODO: use rpmtdDup() instead */ bnames.data = baseNames = duparray(baseNames, fileCount); bnames.flags |= RPMTD_PTR_ALLOCED; haveRelocatedBase = 1; } free(baseNames[i]); baseNames[i] = xstrdup(te); } *te = '\0'; /* terminate new directory name */ } /* Does this directory already exist in the directory list? */ for (j = 0; j < dirCount; j++) { if (fnlen != strlen(dirNames[j])) continue; if (!rstreqn(fn, dirNames[j], fnlen)) continue; break; } if (j < dirCount) { dirIndexes[i] = j; continue; } /* Creating new paths is a pita */ dirNames = dnames.data = xrealloc(dnames.data, sizeof(*dirNames) * (dirCount + 1)); dirNames[dirCount] = xstrdup(fn); dirIndexes[i] = dirCount; dirCount++; dnames.count++; } /* Finish off by relocating directories. */ for (i = dirCount - 1; i >= 0; i--) { for (j = numRelocations - 1; j >= 0; j--) { if (relocations[j].oldPath == NULL) /* XXX can't happen */ continue; size_t len = !rstreq(relocations[j].oldPath, "/") ? strlen(relocations[j].oldPath) : 0; if (len && !rstreqn(relocations[j].oldPath, dirNames[i], len)) continue; /* * Only subdirectories or complete file paths may be relocated. We * don't check for '\0' as our directory names all end in '/'. */ if (dirNames[i][len] != '/') continue; if (relocations[j].newPath) { /* Relocate the path */ char *t = NULL; rstrscat(&t, relocations[j].newPath, (dirNames[i] + len), NULL); /* Unfortunately rpmCleanPath strips the trailing slash.. */ (void) rpmCleanPath(t); rstrcat(&t, "/"); rpmlog(RPMLOG_DEBUG, "relocating directory %s to %s\n", dirNames[i], t); free(dirNames[i]); dirNames[i] = t; nrelocated++; } } } /* Save original filenames in header and replace (relocated) filenames. */ if (nrelocated) { saveOrig(h); headerMod(h, &bnames); headerMod(h, &dnames); headerMod(h, &dindexes); } rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); rpmtdFreeData(&fmodes); free(fn); }
static int skipPrivate(const char *s) { return (filter_private && rstreq(s, "GLIBC_PRIVATE")); }
int main(int argc, char *argv[]) { FD_t fdi, fdo; Header h; char * rpmio_flags = NULL; rpmRC rc; FD_t gzdi; setprogname(argv[0]); /* Retrofit glibc __progname */ rpmReadConfigFiles(NULL, NULL); if (argc == 1) fdi = fdDup(STDIN_FILENO); else { if (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")) { fprintf(stderr, "Usage: rpm2cpio file.rpm\n"); exit(EXIT_FAILURE); } fdi = Fopen(argv[1], "r.ufdio"); } if (Ferror(fdi)) { fprintf(stderr, "%s: %s: %s\n", argv[0], (argc == 1 ? "<stdin>" : argv[1]), Fstrerror(fdi)); exit(EXIT_FAILURE); } fdo = fdDup(STDOUT_FILENO); { rpmts ts = rpmtsCreate(); rpmVSFlags vsflags = 0; /* XXX retain the ageless behavior of rpm2cpio */ vsflags |= _RPMVSF_NODIGESTS; vsflags |= _RPMVSF_NOSIGNATURES; vsflags |= RPMVSF_NOHDRCHK; (void) rpmtsSetVSFlags(ts, vsflags); rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h); ts = rpmtsFree(ts); } switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: fprintf(stderr, _("argument is not an RPM package\n")); exit(EXIT_FAILURE); break; case RPMRC_FAIL: default: fprintf(stderr, _("error reading header from package\n")); exit(EXIT_FAILURE); break; } /* Retrieve type of payload compression. */ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); } gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ free(rpmio_flags); if (gzdi == NULL) { fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); exit(EXIT_FAILURE); } rc = ufdCopy(gzdi, fdo); rc = (rc <= 0) ? EXIT_FAILURE : EXIT_SUCCESS; Fclose(fdo); Fclose(gzdi); /* XXX gzdi == fdi */ return rc; }
static char *getIOFlags(Package pkg) { char *rpmio_flags; const char *s; /* Save payload information */ if (headerIsSource(pkg->header)) rpmio_flags = rpmExpand("%{?_source_payload}", NULL); else rpmio_flags = rpmExpand("%{?_binary_payload}", NULL); /* If not configured or bogus, fall back to gz */ if (rpmio_flags[0] != 'w') { free(rpmio_flags); rpmio_flags = xstrdup("w9.gzdio"); } s = strchr(rpmio_flags, '.'); if (s) { char *buf = NULL; const char *compr = NULL; headerPutString(pkg->header, RPMTAG_PAYLOADFORMAT, "cpio"); if (rstreq(s+1, "ufdio")) { compr = NULL; } else if (rstreq(s+1, "gzdio")) { compr = "gzip"; #if HAVE_BZLIB_H } else if (rstreq(s+1, "bzdio")) { compr = "bzip2"; /* Add prereq on rpm version that understands bzip2 payloads */ (void) rpmlibNeedsFeature(pkg, "PayloadIsBzip2", "3.0.5-1"); #endif #if HAVE_LZMA_H } else if (rstreq(s+1, "xzdio")) { compr = "xz"; (void) rpmlibNeedsFeature(pkg, "PayloadIsXz", "5.2-1"); } else if (rstreq(s+1, "lzdio")) { compr = "lzma"; (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); rpmio_flags = _free(rpmio_flags); goto exit; } if (compr) headerPutString(pkg->header, RPMTAG_PAYLOADCOMPRESSOR, compr); buf = xstrdup(rpmio_flags); buf[s - rpmio_flags] = '\0'; headerPutString(pkg->header, RPMTAG_PAYLOADFLAGS, buf+1); free(buf); } exit: return rpmio_flags; }
static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg) { rpmRC rc = RPMRC_FAIL; ARGV_t av; uint32_t count; struct rpmtd_s policies; struct rpmtd_s policynames; struct rpmtd_s policyflags; struct rpmtd_s policytypes; struct rpmtd_s policytypesidx; rpmtdReset(&policies); rpmtdReset(&policynames); rpmtdReset(&policyflags); rpmtdReset(&policytypes); rpmtdReset(&policytypesidx); if (!mod || !pkg) { goto exit; } /* check for duplicates */ if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) { int typeCount; const char *name; char *type; int i; int idx; headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM); headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM); headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM); headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM); typeCount = rpmtdCount(&policytypes); while ((name = rpmtdNextString(&policynames))) { int overlappingtypes = 0; idx = rpmtdGetIndex(&policynames); for (i = 0; i < typeCount; i++) { if (((int *) policytypesidx.data)[i] != idx) { continue; } type = ((char **) policytypes.data)[i]; if (rstreq(type, RPMPOL_TYPE_DEFAULT) || argvSearch(mod->types, type, NULL) || argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) { overlappingtypes = 1; break; } } if (!overlappingtypes) { continue; } if (rstreq(mod->name, name)) { rpmlog(RPMLOG_ERR, _("Policy module '%s' duplicated with overlapping types\n"), name); goto exit; } if ((mod->flags && RPMPOL_FLAG_BASE) && (((int *) policyflags.data)[idx] & RPMPOL_FLAG_BASE)) { rpmlog(RPMLOG_ERR, _("Base modules '%s' and '%s' have overlapping types\n"), mod->name, name); goto exit; } } } if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) { if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) { rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n")); goto exit; } count = rpmtdCount(&policies); } else { count = 0; } /* save everything to the header */ headerPutString(pkg->header, RPMTAG_POLICIES, mod->data); headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name); headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &mod->flags, 1); for (av = mod->types; av && *av; av++) { headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av); headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1); } rc = RPMRC_OK; exit: rpmtdFreeData(&policies); rpmtdFreeData(&policynames); rpmtdFreeData(&policyflags); rpmtdFreeData(&policytypes); rpmtdFreeData(&policytypesidx); return rc; }
int parseScript(rpmSpec spec, int parsePart) { /* There are a few options to scripts: */ /* <pkg> */ /* -n <pkg> */ /* -p <sh> */ /* -p "<sh> <args>..." */ /* -f <file> */ const char *p; const char **progArgv = NULL; int progArgc; const char *partname = NULL; rpmTagVal reqtag = 0; rpmTagVal tag = 0; rpmsenseFlags tagflags = 0; rpmTagVal progtag = 0; rpmTagVal flagtag = 0; rpmscriptFlags scriptFlags = 0; int flag = PART_SUBNAME; Package pkg; StringBuf sb = NULL; int nextPart; int index; char * reqargs = NULL; int res = PART_ERROR; /* assume failure */ int rc, argc; int arg; const char **argv = NULL; poptContext optCon = NULL; const char *name = NULL; const char *prog = "/bin/sh"; const char *file = NULL; struct poptOption optionsTable[] = { { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL}, { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL}, { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL}, { NULL, 'e', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_EXPAND, NULL, NULL}, { NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT, NULL, NULL}, { 0, 0, 0, 0, 0, NULL, NULL} }; switch (parsePart) { case PART_PRE: tag = RPMTAG_PREIN; tagflags = RPMSENSE_SCRIPT_PRE; progtag = RPMTAG_PREINPROG; flagtag = RPMTAG_PREINFLAGS; partname = "%pre"; break; case PART_POST: tag = RPMTAG_POSTIN; tagflags = RPMSENSE_SCRIPT_POST; progtag = RPMTAG_POSTINPROG; flagtag = RPMTAG_POSTINFLAGS; partname = "%post"; break; case PART_PREUN: tag = RPMTAG_PREUN; tagflags = RPMSENSE_SCRIPT_PREUN; progtag = RPMTAG_PREUNPROG; flagtag = RPMTAG_PREUNFLAGS; partname = "%preun"; break; case PART_POSTUN: tag = RPMTAG_POSTUN; tagflags = RPMSENSE_SCRIPT_POSTUN; progtag = RPMTAG_POSTUNPROG; flagtag = RPMTAG_POSTUNFLAGS; partname = "%postun"; break; case PART_PRETRANS: tag = RPMTAG_PRETRANS; tagflags = RPMSENSE_PRETRANS; progtag = RPMTAG_PRETRANSPROG; flagtag = RPMTAG_PRETRANSFLAGS; partname = "%pretrans"; break; case PART_POSTTRANS: tag = RPMTAG_POSTTRANS; tagflags = RPMSENSE_POSTTRANS; progtag = RPMTAG_POSTTRANSPROG; flagtag = RPMTAG_POSTTRANSFLAGS; partname = "%posttrans"; break; case PART_VERIFYSCRIPT: tag = RPMTAG_VERIFYSCRIPT; tagflags = RPMSENSE_SCRIPT_VERIFY; progtag = RPMTAG_VERIFYSCRIPTPROG; flagtag = RPMTAG_VERIFYSCRIPTFLAGS; partname = "%verifyscript"; break; case PART_TRIGGERPREIN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERPREIN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerprein"; break; case PART_TRIGGERIN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERIN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerin"; break; case PART_TRIGGERUN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERUN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerun"; break; case PART_TRIGGERPOSTUN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERPOSTUN; progtag = RPMTAG_TRIGGERSCRIPTPROG; 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 || tag == RPMTAG_FILETRIGGERSCRIPTS || tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) { /* break line into two */ char *s = strstr(spec->line, "--"); if (!s) { rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"), spec->lineNum, spec->line); return PART_ERROR; } *s = '\0'; reqargs = xstrdup(s + 2); } if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"), spec->lineNum, partname, poptStrerror(rc)); goto exit; } optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); while ((arg = poptGetNextOpt(optCon)) > 0) { switch (arg) { case 'p': if (prog[0] == '<') { if (prog[strlen(prog)-1] != '>') { rpmlog(RPMLOG_ERR, _("line %d: internal script must end " "with \'>\': %s\n"), spec->lineNum, prog); goto exit; } } else if (prog[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: script program must begin " "with \'/\': %s\n"), spec->lineNum, prog); goto exit; } break; case 'n': flag = PART_NAME; break; } } if (arg < -1) { rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"), spec->lineNum, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), spec->line); goto exit; } if (poptPeekArg(optCon)) { if (name == NULL) name = poptGetArg(optCon); if (poptPeekArg(optCon)) { rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"), spec->lineNum, spec->line); goto exit; } } if (lookupPackage(spec, name, flag, &pkg)) { rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"), spec->lineNum, spec->line); goto exit; } if (tag != RPMTAG_TRIGGERSCRIPTS) { if (headerIsEntry(pkg->header, progtag)) { rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"), spec->lineNum, partname); goto exit; } } if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"), spec->lineNum, partname, poptStrerror(rc)); goto exit; } sb = newStringBuf(); if ((rc = readLine(spec, STRIP_NOTHING)) > 0) { nextPart = PART_NONE; } else if (rc < 0) { goto exit; } else { while (! (nextPart = isPart(spec->line))) { appendStringBuf(sb, spec->line); if ((rc = readLine(spec, STRIP_NOTHING)) > 0) { nextPart = PART_NONE; break; } else if (rc < 0) { goto exit; } } } stripTrailingBlanksStringBuf(sb); p = getStringBuf(sb); #ifdef WITH_LUA if (rstreq(progArgv[0], "<lua>")) { rpmlua lua = NULL; /* Global state. */ if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) { goto exit; } (void) rpmlibNeedsFeature(pkg, "BuiltinLuaScripts", "4.2.2-1"); } else #endif if (progArgv[0][0] == '<') { rpmlog(RPMLOG_ERR, _("line %d: unsupported internal script: %s\n"), spec->lineNum, progArgv[0]); goto exit; } else { (void) addReqProv(pkg, RPMTAG_REQUIRENAME, progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0); } if (scriptFlags) { rpmlibNeedsFeature(pkg, "ScriptletExpansion", "4.9.0-1"); } /* Trigger script insertion is always delayed in order to */ /* get the index right. */ if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS || tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) { if (progArgc > 1) { rpmlog(RPMLOG_ERR, _("line %d: interpreter arguments not allowed in triggers: %s\n"), spec->lineNum, prog); goto exit; } /* Add file/index/prog triple to the trigger file list */ index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags, tag); /* Generate the trigger tags */ if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags)) goto exit; } else { struct rpmtd_s td; /* * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct * the td manually and preserve legacy compat for now... */ rpmtdReset(&td); td.tag = progtag; td.count = progArgc; if (progArgc == 1) { td.data = (void *) *progArgv; td.type = RPM_STRING_TYPE; } else { (void) rpmlibNeedsFeature(pkg, "ScriptletInterpreterArgs", "4.0.3-1"); td.data = progArgv; td.type = RPM_STRING_ARRAY_TYPE; } headerPut(pkg->header, &td, HEADERPUT_DEFAULT); if (*p != '\0') { headerPutString(pkg->header, tag, p); } if (scriptFlags) { headerPutUint32(pkg->header, flagtag, &scriptFlags, 1); } if (file) { switch (parsePart) { case PART_PRE: pkg->preInFile = xstrdup(file); break; case PART_POST: pkg->postInFile = xstrdup(file); break; case PART_PREUN: pkg->preUnFile = xstrdup(file); break; case PART_POSTUN: pkg->postUnFile = xstrdup(file); break; case PART_PRETRANS: pkg->preTransFile = xstrdup(file); break; case PART_POSTTRANS: pkg->postTransFile = xstrdup(file); break; case PART_VERIFYSCRIPT: pkg->verifyFile = xstrdup(file); break; } } } res = nextPart; exit: free(reqargs); freeStringBuf(sb); free(progArgv); free(argv); poptFreeContext(optCon); return res; }
int rpmdsCompare(const rpmds A, const rpmds B) { char *aEVR, *bEVR; const char *aE, *aV, *aR, *bE, *bV, *bR; int result; int sense; /* Different names don't overlap. */ if (!rstreq(A->N[A->i], B->N[B->i])) { result = 0; goto exit; } /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ if (!(A->EVR && A->Flags && B->EVR && B->Flags)) { result = 1; goto exit; } /* Same name. If either A or B is an existence test, always overlap. */ if (!((A->Flags[A->i] & RPMSENSE_SENSEMASK) && (B->Flags[B->i] & RPMSENSE_SENSEMASK))) { result = 1; goto exit; } /* If either EVR is non-existent or empty, always overlap. */ if (!(A->EVR[A->i] && *A->EVR[A->i] && B->EVR[B->i] && *B->EVR[B->i])) { result = 1; goto exit; } /* Both AEVR and BEVR exist. */ aEVR = xstrdup(A->EVR[A->i]); parseEVR(aEVR, &aE, &aV, &aR); bEVR = xstrdup(B->EVR[B->i]); parseEVR(bEVR, &bE, &bV, &bR); /* Compare {A,B} [epoch:]version[-release] */ sense = 0; if (aE && *aE && bE && *bE) sense = rpmvercmp(aE, bE); else if (aE && *aE && atol(aE) > 0) { if (!B->nopromote) { sense = 0; } else sense = 1; } else if (bE && *bE && atol(bE) > 0) sense = -1; if (sense == 0) { sense = rpmvercmp(aV, bV); if (sense == 0) { if (aR && *aR && bR && *bR) { sense = rpmvercmp(aR, bR); } else { /* always matches if the side with no release has SENSE_EQUAL */ if ((aR && *aR && (B->Flags[B->i] & RPMSENSE_EQUAL)) || (bR && *bR && (A->Flags[A->i] & RPMSENSE_EQUAL))) { aEVR = _free(aEVR); bEVR = _free(bEVR); result = 1; goto exit; } } } } aEVR = _free(aEVR); bEVR = _free(bEVR); /* Detect overlap of {A,B} range. */ result = 0; if (sense < 0 && ((A->Flags[A->i] & RPMSENSE_GREATER) || (B->Flags[B->i] & RPMSENSE_LESS))) { result = 1; } else if (sense > 0 && ((A->Flags[A->i] & RPMSENSE_LESS) || (B->Flags[B->i] & RPMSENSE_GREATER))) { result = 1; } else if (sense == 0 && (((A->Flags[A->i] & RPMSENSE_EQUAL) && (B->Flags[B->i] & RPMSENSE_EQUAL)) || ((A->Flags[A->i] & RPMSENSE_LESS) && (B->Flags[B->i] & RPMSENSE_LESS)) || ((A->Flags[A->i] & RPMSENSE_GREATER) && (B->Flags[B->i] & RPMSENSE_GREATER)))) { result = 1; } exit: return result; }
/** * Execute triggers. * @todo Trigger on any provides, not just package NVR. * @param ts transaction set * @param te transaction element * @param sense trigger type * @param sourceH header of trigger source * @param trigH header of triggered package * @param arg2 * @param triggersAlreadyRun * @return */ static rpmRC handleOneTrigger(rpmts ts, rpmte te, rpmsenseFlags sense, Header sourceH, Header trigH, int countCorrection, int arg2, unsigned char * triggersAlreadyRun) { rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0)); struct rpmtd_s pfx; const char * sourceName = headerGetString(sourceH, RPMTAG_NAME); const char * triggerName = headerGetString(trigH, RPMTAG_NAME); rpmRC rc = RPMRC_OK; int i; if (trigger == NULL) return rc; headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV); (void) rpmdsSetNoPromote(trigger, 1); while ((i = rpmdsNext(trigger)) >= 0) { uint32_t tix; if (!(rpmdsFlags(trigger) & sense)) continue; if (!rstreq(rpmdsN(trigger), sourceName)) continue; /* XXX Trigger on any provided dependency, not just the package NEVR */ if (!rpmdsAnyMatchesDep(sourceH, trigger, 1)) continue; tix = rpmdsTi(trigger); if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) { int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName); if (arg1 < 0) { /* XXX W2DO? fails as "execution of script failed" */ rc = RPMRC_FAIL; } else { rpmScript script = rpmScriptFromTriggerTag(trigH, triggertag(sense), tix); arg1 += countCorrection; rc = runScript(ts, te, pfx.data, script, arg1, arg2); if (triggersAlreadyRun != NULL) triggersAlreadyRun[tix] = 1; rpmScriptFree(script); } } /* * Each target/source header pair can only result in a single * script being run. */ break; } rpmtdFreeData(&pfx); rpmdsFree(trigger); return rc; }