2006-12-19 00:17:44 +01:00
|
|
|
Add support for patch rpms. Maybe not needed that much any more,
|
|
|
|
as delta rpms are more efficient and do not need so much evil
|
|
|
|
rpm patchery.
|
|
|
|
rh#103205
|
|
|
|
|
|
|
|
Index: lib/depends.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/depends.c.orig
|
|
|
|
+++ lib/depends.c
|
|
|
|
@@ -159,6 +159,7 @@ int rpmtsAddInstallElement(rpmts ts, Hea
|
|
|
|
const char * os;
|
|
|
|
rpmds oldChk, newChk;
|
|
|
|
rpmds obsoletes;
|
|
|
|
+ rpmds patches;
|
|
|
|
alKey pkgKey; /* addedPackages key */
|
|
|
|
int xx;
|
|
|
|
int ec = 0;
|
|
|
|
@@ -387,6 +388,40 @@ addheader:
|
|
|
|
}
|
|
|
|
obsoletes = rpmdsFree(obsoletes);
|
|
|
|
|
|
|
|
+ patches = rpmdsLink(rpmteDS(p, RPMTAG_PATCHESNAME), "Patches");
|
|
|
|
+ patches = rpmdsInit(patches);
|
|
|
|
+ if (patches != NULL)
|
|
|
|
+ while (rpmdsNext(patches) >= 0) {
|
|
|
|
+ const char * Name;
|
|
|
|
+
|
|
|
|
+ if ((Name = rpmdsN(patches)) == NULL)
|
|
|
|
+ continue; /* XXX can't happen */
|
|
|
|
+
|
|
|
|
+ /* Ignore colored patches not in our rainbow. */
|
|
|
|
+ dscolor = rpmdsColor(patches);
|
|
|
|
+ if (tscolor && dscolor && !(tscolor & dscolor))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
|
|
|
|
+
|
|
|
|
+ xx = rpmdbPruneIterator(mi,
|
|
|
|
+ ts->removedPackages, ts->numRemovedPackages, 1);
|
|
|
|
+
|
|
|
|
+ while((oh = rpmdbNextIterator(mi)) != NULL) {
|
|
|
|
+ /* Ignore colored packages not in our rainbow. */
|
|
|
|
+ ohcolor = hGetColor(oh);
|
|
|
|
+ if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
|
|
|
|
+ /*@innercontinue@*/ continue;
|
|
|
|
+ if (rpmdsEVR(patches) == NULL
|
|
|
|
+ || rpmdsNVRMatchesDep(oh, patches, _rpmds_nopromote)) {
|
|
|
|
+ if (rpmVersionCompare(h, oh))
|
|
|
|
+ xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), pkgKey);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ mi = rpmdbFreeIterator(mi);
|
|
|
|
+ }
|
|
|
|
+ patches = rpmdsFree(patches);
|
|
|
|
+
|
|
|
|
ec = 0;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
@@ -644,6 +679,57 @@ exit:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int checkPatchDeps(rpmts ts, rpmte p, int reportprobs)
|
|
|
|
+{
|
|
|
|
+ const char * Name;
|
|
|
|
+ Header h;
|
|
|
|
+ rpmds patches;
|
|
|
|
+ rpmds this;
|
|
|
|
+ rpmdbMatchIterator mi;
|
|
|
|
+
|
|
|
|
+ patches = rpmdsInit(rpmteDS(p, RPMTAG_PATCHESNAME));
|
|
|
|
+ if (!patches)
|
|
|
|
+ return 0;
|
|
|
|
+ this = rpmteDS(p, RPMTAG_NAME);
|
|
|
|
+
|
|
|
|
+ mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmdsN(this), 0);
|
|
|
|
+ while ((h = rpmdbNextIterator(mi)) != NULL) {
|
|
|
|
+ if (rpmdsNVRMatchesDep(h, this, _rpmds_nopromote)) {
|
|
|
|
+ rpmdsNotify(this, _("(patch refresh)"), 0);
|
|
|
|
+ p->hPatched = headerLink(h);
|
|
|
|
+ p->isPatchRefresh = 1;
|
|
|
|
+ mi = rpmdbFreeIterator(mi);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ mi = rpmdbFreeIterator(mi);
|
|
|
|
+
|
|
|
|
+ while (rpmdsNext(patches) >= 0) {
|
|
|
|
+ if ((Name = rpmdsN(patches)) == NULL)
|
|
|
|
+ return 1; /* XXX can't happen */
|
|
|
|
+ mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
|
|
|
|
+ while ((h = rpmdbNextIterator(mi)) != NULL) {
|
|
|
|
+ if (rpmdsNVRMatchesDep(h, patches, _rpmds_nopromote)) {
|
|
|
|
+ rpmdsNotify(patches, _("(db package)"), 0);
|
|
|
|
+ p->hPatched = headerLink(h);
|
|
|
|
+ p->isPatchRefresh = 0;
|
|
|
|
+ mi = rpmdbFreeIterator(mi);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ mi = rpmdbFreeIterator(mi);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rpmdsNotify(patches, NULL, 1);
|
|
|
|
+ if (reportprobs) {
|
|
|
|
+ patches = rpmdsInit(patches);
|
|
|
|
+ rpmdsNext(patches);
|
|
|
|
+ rpmdsProblem(ts->probs, rpmteNEVR(p), patches, NULL, 1);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* Check added requires/conflicts against against installed+added packages.
|
|
|
|
* @param ts transaction set
|
|
|
|
@@ -1727,6 +1813,7 @@ int rpmtsCheck(rpmts ts)
|
|
|
|
rpmteDS(p, RPMTAG_CONFLICTNAME),
|
|
|
|
NULL,
|
|
|
|
tscolor, 1);
|
|
|
|
+ rc |= checkPatchDeps(ts, p, 1);
|
|
|
|
if (rc)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
@@ -1824,3 +1911,22 @@ exit:
|
|
|
|
/*@=branchstate@*/
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+void rpmtsPatchCheck(rpmts ts)
|
|
|
|
+{
|
|
|
|
+ int closeatexit = 0;
|
|
|
|
+ rpmtsi pi = NULL; rpmte p;
|
|
|
|
+
|
|
|
|
+ if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
|
|
|
|
+ if ((rpmtsOpenDB(ts, ts->dbmode)) != 0)
|
|
|
|
+ return;
|
|
|
|
+ closeatexit = 1;
|
|
|
|
+ }
|
|
|
|
+ pi = rpmtsiInit(ts);
|
|
|
|
+ while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL)
|
|
|
|
+ if (p->key) /* key is filename for install, zero for verify */
|
|
|
|
+ (void)checkPatchDeps(ts, p, 0);
|
|
|
|
+ pi = rpmtsiFree(pi);
|
|
|
|
+ if (closeatexit)
|
|
|
|
+ (void)rpmtsCloseDB(ts);
|
|
|
|
+}
|
|
|
|
Index: lib/formats.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/formats.c.orig
|
|
|
|
+++ lib/formats.c
|
|
|
|
@@ -232,6 +232,8 @@ static /*@only@*/ char * fflagsFormat(in
|
|
|
|
strcat(buf, "l");
|
|
|
|
if (anint & RPMFILE_README)
|
|
|
|
strcat(buf, "r");
|
|
|
|
+ if (anint & RPMFILE_UNPATCHED)
|
|
|
|
+ strcat(buf, "u");
|
|
|
|
/*@=boundswrite@*/
|
|
|
|
|
|
|
|
val = xmalloc(5 + padding);
|
|
|
|
Index: lib/fsm.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/fsm.c.orig
|
|
|
|
+++ lib/fsm.c
|
|
|
|
@@ -707,7 +707,7 @@ assert(rpmteType(fi->te) == TR_ADDED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FA_BACKUP:
|
|
|
|
- if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
|
|
|
|
+ if (!(fsm->fflags & (RPMFILE_GHOST|RPMFILE_UNPATCHED))) /* XXX Don't if %ghost file. */
|
|
|
|
switch (rpmteType(fi->te)) {
|
|
|
|
case TR_ADDED:
|
|
|
|
fsm->osuffix = SUFFIX_RPMORIG;
|
|
|
|
@@ -720,13 +720,13 @@ assert(rpmteType(fi->te) == TR_ADDED);
|
|
|
|
|
|
|
|
case FA_ALTNAME:
|
|
|
|
assert(rpmteType(fi->te) == TR_ADDED);
|
|
|
|
- if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
|
|
|
|
+ if (!(fsm->fflags & (RPMFILE_GHOST|RPMFILE_UNPATCHED))) /* XXX Don't if %ghost file. */
|
|
|
|
fsm->nsuffix = SUFFIX_RPMNEW;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FA_SAVE:
|
|
|
|
assert(rpmteType(fi->te) == TR_ADDED);
|
|
|
|
- if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
|
|
|
|
+ if (!(fsm->fflags & (RPMFILE_GHOST|RPMFILE_UNPATCHED))) /* XXX Don't if %ghost file. */
|
|
|
|
fsm->osuffix = SUFFIX_RPMSAVE;
|
|
|
|
break;
|
|
|
|
case FA_ERASE:
|
|
|
|
@@ -1740,7 +1740,7 @@ int fsmStage(FSM_t fsm, fileStage stage)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fsm->goal == FSM_PKGBUILD) {
|
|
|
|
- if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
|
|
|
|
+ if (fsm->fflags & (RPMFILE_GHOST|RPMFILE_UNPATCHED)) /* XXX Don't if %ghost file. */
|
|
|
|
break;
|
|
|
|
if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
|
|
|
|
struct hardLink_s * li, * prev;
|
|
|
|
Index: lib/poptQV.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/poptQV.c.orig
|
|
|
|
+++ lib/poptQV.c
|
|
|
|
@@ -171,6 +171,7 @@ static void queryArgCallback(poptContext
|
|
|
|
case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
|
|
|
|
case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST;
|
|
|
|
break;
|
|
|
|
+ case 'P': qva->qva_flags |= QUERY_FOR_PATCHES; break;
|
|
|
|
case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST;
|
|
|
|
break;
|
|
|
|
|
|
|
|
@@ -278,6 +279,8 @@ struct poptOption rpmQueryPoptTable[] =
|
|
|
|
N_("skip %%readme files"), NULL },
|
|
|
|
#endif
|
|
|
|
|
|
|
|
+ { "patches", 'P', 0, 0, 'P',
|
|
|
|
+ N_("list patches or patched files "), NULL },
|
|
|
|
{ "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
|
|
|
|
POPT_QUERYFORMAT, NULL, NULL },
|
|
|
|
{ "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
|
|
|
|
Index: lib/query.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/query.c.orig
|
|
|
|
+++ lib/query.c
|
|
|
|
@@ -225,6 +225,10 @@ int showQueryPackage(QVA_t qva, rpmts ts
|
|
|
|
if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
+ /* If querying patches, skip unpatched files. */
|
|
|
|
+ if ((qva->qva_flags & QUERY_FOR_PATCHES) && (fflags & RPMFILE_UNPATCHED))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
/*@-boundswrite@*/
|
|
|
|
if (!rpmIsVerbose() && prefix)
|
|
|
|
te = stpcpy(te, prefix);
|
|
|
|
@@ -362,6 +366,21 @@ void rpmDisplayQueryTags(FILE * fp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int isPatch(Header h)
|
|
|
|
+{
|
|
|
|
+ int i, requiresCount = 0;
|
|
|
|
+ const char ** requires;
|
|
|
|
+
|
|
|
|
+ if (!headerGetEntry(h, RPMTAG_REQUIRENAME, NULL, (void **) &requires, &requiresCount))
|
|
|
|
+ return 0;
|
|
|
|
+ for (i = 0; i < requiresCount; i++)
|
|
|
|
+ if (!strcmp("rpmlib(PatchRPMs)", requires[i]))
|
|
|
|
+ break;
|
|
|
|
+ if (requiresCount)
|
|
|
|
+ free(requires);
|
|
|
|
+ return i < requiresCount;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static int rpmgiShowMatches(QVA_t qva, rpmts ts)
|
|
|
|
/*@globals rpmGlobalMacroContext, h_errno, internalState @*/
|
|
|
|
/*@modifies qva, rpmGlobalMacroContext, h_errno, internalState @*/
|
|
|
|
@@ -376,6 +395,8 @@ static int rpmgiShowMatches(QVA_t qva, r
|
|
|
|
h = rpmgiHeader(gi);
|
|
|
|
if (h == NULL) /* XXX perhaps stricter break instead? */
|
|
|
|
continue;
|
|
|
|
+ if ((qva->qva_flags & QUERY_FOR_PATCHES) != 0 && !isPatch(h))
|
|
|
|
+ continue;
|
|
|
|
if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
|
|
|
|
ec = rc;
|
|
|
|
if (qva->qva_source == RPMQV_DBOFFSET)
|
|
|
|
@@ -391,6 +412,8 @@ int rpmcliShowMatches(QVA_t qva, rpmts t
|
|
|
|
|
|
|
|
while ((h = rpmdbNextIterator(qva->qva_mi)) != NULL) {
|
|
|
|
int rc;
|
|
|
|
+ if ((qva->qva_flags & QUERY_FOR_PATCHES) != 0 && !isPatch(h))
|
|
|
|
+ continue;
|
|
|
|
if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
|
|
|
|
ec = rc;
|
|
|
|
if (qva->qva_source == RPMQV_DBOFFSET)
|
2007-05-25 17:22:10 +02:00
|
|
|
@@ -685,7 +708,17 @@ int rpmcliArgIter(rpmts ts, QVA_t qva, A
|
2006-12-19 00:17:44 +01:00
|
|
|
|
|
|
|
switch (qva->qva_source) {
|
|
|
|
case RPMQV_ALL:
|
|
|
|
- qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
|
|
|
|
+ if ((!argv || !*argv) && (qva->qva_flags & QUERY_FOR_PATCHES) != 0) {
|
|
|
|
+ qva->qva_gi = rpmgiNew(ts, RPMTAG_REQUIRENAME, "rpmlib(PatchRPMs)", 0);
|
2007-05-25 17:22:10 +02:00
|
|
|
+ qva->qva_gi->mi = rpmtsInitIterator(qva->qva_gi->ts, qva->qva_gi->tag, qva->qva_gi->keyp, qva->qva_gi->keylen);
|
2006-12-19 00:17:44 +01:00
|
|
|
+ if (qva->qva_gi->mi == NULL) {
|
|
|
|
+ rpmError(RPMERR_QUERYINFO, _("no patch-rpm installed\n"));
|
|
|
|
+ break;
|
|
|
|
+ }
|
2007-05-25 17:22:10 +02:00
|
|
|
+ qva->qva_gi->mi = rpmdbFreeIterator(qva->qva_gi->mi);
|
2006-12-19 00:17:44 +01:00
|
|
|
+ } else {
|
|
|
|
+ qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
|
|
|
|
+ }
|
|
|
|
qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, RPMGI_NONE);
|
|
|
|
|
|
|
|
if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
|
|
|
|
Index: lib/rpmcli.h
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpmcli.h.orig
|
|
|
|
+++ lib/rpmcli.h
|
|
|
|
@@ -165,7 +165,7 @@ typedef enum rpmQueryFlags_e {
|
|
|
|
QUERY_SCRIPT = (1 << 18), /*!< verify: from --noscripts */
|
|
|
|
QUERY_DIGEST = (1 << 19), /*!< verify: from --nodigest */
|
|
|
|
QUERY_SIGNATURE = (1 << 20), /*!< verify: from --nosignature */
|
|
|
|
- QUERY_PATCHES = (1 << 21), /*!< verify: from --nopatches */
|
|
|
|
+ QUERY_FOR_PATCHES = (1 << 21), /*!< verify: from --patches */
|
|
|
|
QUERY_HDRCHK = (1 << 22), /*!< verify: from --nohdrchk */
|
|
|
|
/*@=enummemuse@*/
|
|
|
|
QUERY_FOR_LIST = (1 << 23), /*!< query: from --list */
|
|
|
|
Index: lib/rpmds.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpmds.c.orig
|
|
|
|
+++ lib/rpmds.c
|
|
|
|
@@ -87,6 +87,10 @@ fprintf(stderr, "*** ds %p\t%s[%d]\n", d
|
|
|
|
tagEVR = RPMTAG_TRIGGERVERSION;
|
|
|
|
tagF = RPMTAG_TRIGGERFLAGS;
|
|
|
|
} else
|
|
|
|
+ if (ds->tagN == RPMTAG_PATCHESNAME) {
|
|
|
|
+ tagEVR = RPMTAG_PATCHESVERSION;
|
|
|
|
+ tagF = RPMTAG_PATCHESFLAGS;
|
|
|
|
+ } else
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*@-branchstate@*/
|
|
|
|
@@ -325,6 +329,11 @@ rpmds rpmdsNew(Header h, rpmTag tagN, in
|
|
|
|
tagEVR = RPMTAG_ENHANCESVERSION;
|
|
|
|
tagF = RPMTAG_ENHANCESFLAGS;
|
|
|
|
} else
|
|
|
|
+ if (tagN == RPMTAG_PATCHESNAME) {
|
|
|
|
+ Type = "patches";
|
|
|
|
+ tagEVR = RPMTAG_PATCHESVERSION;
|
|
|
|
+ tagF = RPMTAG_PATCHESFLAGS;
|
|
|
|
+ } else
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
/*@-branchstate@*/
|
|
|
|
@@ -1127,14 +1136,28 @@ void rpmdsProblem(rpmps ps, const char *
|
|
|
|
if (DNEVR == NULL) DNEVR = "? ?N? ?OP? ?EVR?";
|
|
|
|
/*@=branchstate@*/
|
|
|
|
|
|
|
|
- rpmMessage(RPMMESS_DEBUG, _("package %s has unsatisfied %s: %s\n"),
|
|
|
|
- pkgNEVR, ds->Type, DNEVR+2);
|
|
|
|
-
|
|
|
|
switch ((unsigned)DNEVR[0]) {
|
|
|
|
case 'C': type = RPMPROB_CONFLICT; break;
|
|
|
|
default:
|
|
|
|
case 'R': type = RPMPROB_REQUIRES; break;
|
|
|
|
}
|
|
|
|
+ if (DNEVR[0] == 'p') {
|
|
|
|
+ const char *d;
|
|
|
|
+ char *dn;
|
|
|
|
+ rpmds pds = rpmdsInit(ds);
|
|
|
|
+ dn = xstrdup("p ");
|
|
|
|
+ while (rpmdsNext(pds) >= 0) {
|
|
|
|
+ d = rpmdsDNEVR(ds) + 2;
|
|
|
|
+ dn = xrealloc(dn, strlen(dn) + strlen(d) + 4);
|
|
|
|
+ if (dn[2])
|
|
|
|
+ strcat(dn, " | ");
|
|
|
|
+ strcat(dn, d);
|
|
|
|
+ }
|
|
|
|
+ DNEVR = (const char *)dn;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rpmMessage(RPMMESS_DEBUG, _("package %s has unsatisfied %s: %s\n"),
|
|
|
|
+ pkgNEVR, ds->Type, DNEVR+2);
|
|
|
|
|
|
|
|
key = (suggestedKeys ? suggestedKeys[0] : NULL);
|
|
|
|
rpmpsAppend(ps, type, pkgNEVR, key, NULL, NULL, DNEVR, adding);
|
|
|
|
Index: lib/rpminstall.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpminstall.c.orig
|
|
|
|
+++ lib/rpminstall.c
|
|
|
|
@@ -692,6 +692,11 @@ maybe_manifest:
|
|
|
|
/*@=branchstate@*/
|
|
|
|
}
|
|
|
|
ps = rpmpsFree(ps);
|
|
|
|
+ } else if (eiu->numRPMS) {
|
|
|
|
+ /* needed in rpmtsOrder */
|
|
|
|
+ rpmalMakeIndex(ts->addedPackages);
|
|
|
|
+ /* need patch references */
|
|
|
|
+ rpmtsPatchCheck(ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
|
|
|
|
@@ -797,7 +802,7 @@ int rpmErase(rpmts ts, struct rpmInstall
|
|
|
|
{ int notifyFlags;
|
|
|
|
notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
|
|
|
|
xx = rpmtsSetNotifyCallback(ts,
|
|
|
|
- rpmShowProgress, (void *) ((long)notifyFlags)
|
|
|
|
+ rpmShowProgress, (void *) ((long)notifyFlags))
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Index: lib/rpmlibprov.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpmlibprov.c.orig
|
|
|
|
+++ lib/rpmlibprov.c
|
|
|
|
@@ -33,6 +33,9 @@ static struct rpmlibProvides_s rpmlibPro
|
|
|
|
{ "rpmlib(PayloadIsBzip2)", "3.0.5-1",
|
|
|
|
(RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
|
|
|
|
N_("package payload can be compressed using bzip2.") },
|
|
|
|
+ { "rpmlib(PatchRPMs)", "3.0.6-1",
|
|
|
|
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
|
|
|
|
+ N_("understand rpms that replace a subset of files.") },
|
|
|
|
{ "rpmlib(PayloadFilesHavePrefix)", "4.0-1",
|
|
|
|
(RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
|
|
|
|
N_("package payload file(s) have \"./\" prefix.") },
|
|
|
|
Index: lib/rpmte.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpmte.c.orig
|
|
|
|
+++ lib/rpmte.c
|
|
|
|
@@ -64,6 +64,7 @@ static void delTE(rpmte p)
|
|
|
|
p->NEVRA = _free(p->NEVRA);
|
|
|
|
|
|
|
|
p->h = headerFree(p->h);
|
|
|
|
+ p->hPatched = headerFree(p->hPatched);
|
|
|
|
|
|
|
|
/*@-boundswrite@*/
|
|
|
|
memset(p, 0, sizeof(*p)); /* XXX trash and burn */
|
|
|
|
@@ -183,6 +184,9 @@ static void addTE(rpmts ts, rpmte p, Hea
|
|
|
|
p->requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
|
|
|
|
p->conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
|
|
|
|
p->obsoletes = rpmdsNew(h, RPMTAG_OBSOLETENAME, scareMem);
|
|
|
|
+ p->patches = rpmdsNew(h, RPMTAG_PATCHESNAME, scareMem | 2);
|
|
|
|
+ p->hPatched = NULL;
|
|
|
|
+ p->isPatchRefresh = 0;
|
|
|
|
|
|
|
|
savep = rpmtsSetRelocateElement(ts, p);
|
|
|
|
p->fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
|
|
|
|
@@ -520,6 +524,9 @@ rpmds rpmteDS(rpmte te, rpmTag tag)
|
|
|
|
if (tag == RPMTAG_OBSOLETENAME)
|
|
|
|
return te->obsoletes;
|
|
|
|
else
|
|
|
|
+ if (tag == RPMTAG_PATCHESNAME)
|
|
|
|
+ return te->patches;
|
|
|
|
+ else
|
|
|
|
return NULL;
|
|
|
|
/*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
|
|
|
|
}
|
|
|
|
Index: lib/rpmte.h
|
|
|
|
===================================================================
|
|
|
|
--- lib/rpmte.h.orig
|
|
|
|
+++ lib/rpmte.h
|
|
|
|
@@ -115,6 +115,9 @@ struct rpmte_s {
|
|
|
|
int autorelocatex; /*!< (TR_ADDED) Auto relocation entry index. */
|
|
|
|
/*@refcounted@*/ /*@null@*/
|
|
|
|
FD_t fd; /*!< (TR_ADDED) Payload file descriptor. */
|
|
|
|
+ rpmds patches; /*!< Patches: dependencies. */
|
|
|
|
+ Header hPatched; /*!< (TR_ADDED) Header of package we patch */
|
|
|
|
+ int isPatchRefresh; /*!< (TR_ADDED) is a patch refresh */
|
|
|
|
|
|
|
|
/*@-fielduse@*/ /* LCL: confused by union? */
|
|
|
|
union {
|
|
|
|
Index: lib/transaction.c
|
|
|
|
===================================================================
|
|
|
|
--- lib/transaction.c.orig
|
|
|
|
+++ lib/transaction.c
|
|
|
|
@@ -198,6 +198,11 @@ static int handleInstInstalledFiles(cons
|
|
|
|
int rConflicts;
|
|
|
|
|
|
|
|
rConflicts = reportConflicts;
|
|
|
|
+ if (rConflicts && p->hPatched && p->isPatchRefresh) {
|
|
|
|
+ /* If same package (patch refresh) turn off conflicts */
|
|
|
|
+ /* Handling of unpatched files not worth the trouble */
|
|
|
|
+ rConflicts = 0;
|
|
|
|
+ }
|
|
|
|
/* Resolve file conflicts to prefer Elf64 (if not forced). */
|
|
|
|
if (tscolor != 0 && FColor != 0 && FColor != oFColor)
|
|
|
|
{
|
|
|
|
@@ -972,6 +977,176 @@ rpmfi rpmtsiFi(const rpmtsi tsi)
|
|
|
|
/*@=compdef =refcounttrans =usereleased @*/
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int_32 *dupint32(int_32 *old, int cnt)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+ int_32 *new = xmalloc(cnt * sizeof(int_32));
|
|
|
|
+ for (i = 0; i < cnt; i++)
|
|
|
|
+ new[i] = old[i];
|
|
|
|
+ return new;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void patchUnpatchedFiles(Header oldh, Header h, int isRefresh)
|
|
|
|
+{
|
|
|
|
+ int fileCount, oldfileCount, i, j, oldidx, oldidxj;
|
|
|
|
+ const char ** baseNames, ** dirNames;
|
|
|
|
+ int_32 * dirIndexes;
|
|
|
|
+ int_32 * fileMtimes;
|
|
|
|
+ int_32 * fileSizes;
|
|
|
|
+ int_32 * fileFlags;
|
|
|
|
+ char ** fileMd5s;
|
|
|
|
+ const char ** oldbaseNames, ** olddirNames;
|
|
|
|
+ int_32 * olddirIndexes;
|
|
|
|
+ int_32 * oldfileMtimes;
|
|
|
|
+ int_32 * oldfileSizes;
|
|
|
|
+ int_32 * oldfileFlags;
|
|
|
|
+ char ** oldfileMd5s;
|
|
|
|
+ const char * name, * version, * release;
|
|
|
|
+ char * evr;
|
|
|
|
+ int_32 sense;
|
|
|
|
+ int_32 *epochp;
|
|
|
|
+ int save = 0;
|
|
|
|
+ char epoch[20];
|
|
|
|
+ const char ** oldpatches, **oldpatchesEVR = NULL;
|
|
|
|
+ int_32 * oldpatchesFlags;
|
|
|
|
+ int oldpatchesCount;
|
|
|
|
+
|
|
|
|
+ if (!oldh) {
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESNAME);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESFLAGS);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESVERSION);
|
|
|
|
+#if 1
|
|
|
|
+ name = "(none)";
|
|
|
|
+ sense = 0;
|
|
|
|
+ evr = "";
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESNAME, RPM_STRING_ARRAY_TYPE, &name, 1);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESFLAGS, RPM_INT32_TYPE, &sense, 1);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESVERSION, RPM_STRING_ARRAY_TYPE, &evr, 1);
|
|
|
|
+#endif
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (!headerGetEntry(h, RPMTAG_BASENAMES, NULL,
|
|
|
|
+ (void **) &baseNames, &fileCount))
|
|
|
|
+ return;
|
|
|
|
+ headerGetEntry(h, RPMTAG_DIRNAMES, NULL,
|
|
|
|
+ (void **) &dirNames, NULL);
|
|
|
|
+ headerGetEntry(h, RPMTAG_DIRINDEXES, NULL,
|
|
|
|
+ (void **) &dirIndexes, NULL);
|
|
|
|
+ headerGetEntry(h, RPMTAG_FILESIZES, NULL,
|
|
|
|
+ (void **) &fileSizes, NULL);
|
|
|
|
+ headerGetEntry(h, RPMTAG_FILEMD5S, NULL,
|
|
|
|
+ (void **) &fileMd5s, NULL);
|
|
|
|
+ headerGetEntry(h, RPMTAG_FILEMTIMES, NULL,
|
|
|
|
+ (void **) &fileMtimes, NULL);
|
|
|
|
+ headerGetEntry(h, RPMTAG_FILEFLAGS, NULL,
|
|
|
|
+ (void **) &fileFlags, NULL);
|
|
|
|
+
|
|
|
|
+ if (!headerGetEntry(oldh, RPMTAG_BASENAMES, NULL,
|
|
|
|
+ (void **) &oldbaseNames, &oldfileCount))
|
|
|
|
+ return;
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_DIRNAMES, NULL,
|
|
|
|
+ (void **) &olddirNames, NULL);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_DIRINDEXES, NULL,
|
|
|
|
+ (void **) &olddirIndexes, NULL);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_FILESIZES, NULL,
|
|
|
|
+ (void **) &oldfileSizes, NULL);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_FILEMD5S, NULL,
|
|
|
|
+ (void **) &oldfileMd5s, NULL);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_FILEMTIMES, NULL,
|
|
|
|
+ (void **) &oldfileMtimes, NULL);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_FILEFLAGS, NULL,
|
|
|
|
+ (void **) &oldfileFlags, NULL);
|
|
|
|
+
|
|
|
|
+ oldidx = -1;
|
|
|
|
+ oldidxj = 0;
|
|
|
|
+ for (i = 0; i < fileCount; i++) {
|
|
|
|
+ if (!(fileFlags[i] & RPMFILE_UNPATCHED))
|
|
|
|
+ continue;
|
|
|
|
+ if (dirIndexes[i] != oldidx) {
|
|
|
|
+ for (j = 0; j < oldfileCount; j++)
|
|
|
|
+ if (strcmp(dirNames[dirIndexes[i]], olddirNames[olddirIndexes[j]]) == 0)
|
|
|
|
+ break;
|
|
|
|
+ if (j == oldfileCount) {
|
|
|
|
+ while (i + 1 < fileCount && dirIndexes[i] == dirIndexes[i + 1])
|
|
|
|
+ i++;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ oldidx = olddirIndexes[j];
|
|
|
|
+ oldidxj = j;
|
|
|
|
+ }
|
|
|
|
+ for (j = oldidxj; j < oldfileCount; j++)
|
|
|
|
+ if (olddirIndexes[j] == oldidx && !strcmp(baseNames[i], oldbaseNames[j])) {
|
|
|
|
+ if (!save) {
|
|
|
|
+ /* duplicate fileSizes, fileMtimes, fileFlags
|
|
|
|
+ * so we can modify them */
|
|
|
|
+ fileSizes = dupint32(fileSizes, fileCount);
|
|
|
|
+ fileMtimes = dupint32(fileMtimes, fileCount);
|
|
|
|
+ fileFlags = dupint32(fileFlags, fileCount);
|
|
|
|
+ }
|
|
|
|
+ fileSizes[i] = oldfileSizes[j];
|
|
|
|
+ fileMtimes[i] = oldfileMtimes[j];
|
|
|
|
+ fileMd5s[i] = oldfileMd5s[j];
|
|
|
|
+ fileFlags[i] = oldfileFlags[j] | RPMFILE_UNPATCHED;
|
|
|
|
+ save = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (save) {
|
|
|
|
+ headerModifyEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
|
|
|
|
+ (void *) fileSizes, fileCount);
|
|
|
|
+ headerModifyEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
|
|
|
|
+ (void *) fileMd5s, fileCount);
|
|
|
|
+ headerModifyEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
|
|
|
|
+ (void *) fileMtimes, fileCount);
|
|
|
|
+ headerModifyEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
|
|
|
|
+ (void *) fileFlags, fileCount);
|
|
|
|
+ free(fileSizes);
|
|
|
|
+ free(fileMtimes);
|
|
|
|
+ free(fileFlags);
|
|
|
|
+ }
|
|
|
|
+ free(baseNames);
|
|
|
|
+ free(dirNames);
|
|
|
|
+ free(fileMd5s);
|
|
|
|
+ free(oldbaseNames);
|
|
|
|
+ free(olddirNames);
|
|
|
|
+ free(oldfileMd5s);
|
|
|
|
+
|
|
|
|
+ if (isRefresh) {
|
|
|
|
+ /* same patch installed, this is just a refresh operation */
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESNAME);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESFLAGS);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESVERSION);
|
|
|
|
+ if (headerGetEntry(oldh, RPMTAG_PATCHESNAME, NULL, (void **) &oldpatches, &oldpatchesCount) && oldpatchesCount) {
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_PATCHESFLAGS, NULL, (void **) &oldpatchesFlags, &oldpatchesCount);
|
|
|
|
+ headerGetEntry(oldh, RPMTAG_PATCHESVERSION, NULL, (void **) &oldpatchesEVR, &oldpatchesCount);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESNAME, RPM_STRING_ARRAY_TYPE, oldpatches, oldpatchesCount);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESFLAGS, RPM_INT32_TYPE, oldpatchesFlags, oldpatchesCount);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESVERSION, RPM_STRING_ARRAY_TYPE, oldpatchesEVR, oldpatchesCount);
|
|
|
|
+ free(oldpatches);
|
|
|
|
+ free(oldpatchesEVR);
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ headerNVR(oldh, &name, &version, &release);
|
|
|
|
+ *epoch = 0;
|
|
|
|
+ if (headerGetEntry(h, RPMTAG_EPOCH, NULL, (void **) &epochp, NULL))
|
|
|
|
+ sprintf(epoch, "%d:", *epochp);
|
|
|
|
+ evr = xmalloc(strlen(epoch) + strlen(version) + strlen(release) + 2);
|
|
|
|
+ strcpy(evr, epoch);
|
|
|
|
+ strcat(evr, version);
|
|
|
|
+ strcat(evr, "-");
|
|
|
|
+ strcat(evr, release);
|
|
|
|
+ sense = RPMSENSE_EQUAL;
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESNAME);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESFLAGS);
|
|
|
|
+ headerRemoveEntry(h, RPMTAG_PATCHESVERSION);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESNAME, RPM_STRING_ARRAY_TYPE, &name, 1);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESFLAGS, RPM_INT32_TYPE, &sense, 1);
|
|
|
|
+ headerAddEntry(h, RPMTAG_PATCHESVERSION, RPM_STRING_ARRAY_TYPE, &evr, 1);
|
|
|
|
+ free(evr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* This is not a generalized function to be called from outside
|
|
|
|
* librpm. It is called internally by rpmtsRun() to rollback
|
|
|
|
@@ -2137,6 +2312,8 @@ assert(psm != NULL);
|
|
|
|
}
|
|
|
|
psm->fi = rpmfiLink(p->fi, NULL);
|
|
|
|
|
|
|
|
+ if (p->hPatched || rpmteDS(p, RPMTAG_PATCHESNAME))
|
|
|
|
+ patchUnpatchedFiles(p->hPatched, p->fi->h, p->isPatchRefresh);
|
|
|
|
/*@-nullstate@*/ /* FIX: psm->fi may be NULL */
|
|
|
|
if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
|
|
|
|
ourrc++;
|
|
|
|
Index: doc/rpm.8
|
|
|
|
===================================================================
|
|
|
|
--- doc/rpm.8.orig
|
|
|
|
+++ doc/rpm.8
|
|
|
|
@@ -68,7 +68,8 @@ rpm \- RPM Package Manager
|
|
|
|
|
|
|
|
|
|
|
|
[\fB\fIPACKAGE_NAME\fB\fR] [\fB-a,--all\fR] [\fB-f,--file \fIFILE\fB\fR]
|
|
|
|
- [\fB-g,--group \fIGROUP\fB\fR] {\fB-p,--package \fIPACKAGE_FILE\fB\fR]
|
|
|
|
+ [\fB-g,--group \fIGROUP\fB\fR] [\fB-p,--package \fIPACKAGE_FILE\fB\fR]
|
|
|
|
+ [\fB-P,--patches\fR]
|
|
|
|
[\fB--fileid \fIMD5\fB\fR] [\fB--hdrid \fISHA1\fB\fR] [\fB--pkgid \fIMD5\fB\fR] [\fB--tid \fITID\fB\fR]
|
|
|
|
[\fB--querybynumber \fIHDRNUM\fB\fR] [\fB--triggeredby \fIPACKAGE_NAME\fB\fR]
|
|
|
|
[\fB--whatprovides \fICAPABILITY\fB\fR] [\fB--whatrequires \fICAPABILITY\fB\fR]
|
|
|
|
@@ -77,7 +78,8 @@ rpm \- RPM Package Manager
|
|
|
|
.PP
|
|
|
|
|
|
|
|
|
|
|
|
- [\fB--changelog\fR] [\fB-c,--configfiles\fR] [\fB-d,--docfiles\fR] [\fB--dump\fR]
|
|
|
|
+ [\fB--basedon\fR] [\fB--changelog\fR] [\fB-c,--configfiles\fR]
|
|
|
|
+ [\fB-d,--docfiles\fR] [\fB--dump\fR]
|
|
|
|
[\fB--filesbypkg\fR] [\fB-i,--info\fR] [\fB--last\fR] [\fB-l,--list\fR]
|
|
|
|
[\fB--provides\fR] [\fB--qf,--queryformat \fIQUERYFMT\fB\fR]
|
|
|
|
[\fB-R,--requires\fR] [\fB--scripts\fR] [\fB-s,--state\fR]
|
|
|
|
@@ -547,6 +549,10 @@ that will be expanded to paths that are
|
|
|
|
the package manifest as additional \fIPACKAGE_FILE\fR
|
|
|
|
arguments to the query.
|
|
|
|
.TP
|
|
|
|
+\fB-P, --patches\fP
|
|
|
|
+Limit the selected packages to patch-rpms. As a side effect, limit
|
|
|
|
+the file list to patched files.
|
|
|
|
+.TP
|
|
|
|
\fB--pkgid \fIMD5\fB\fR
|
|
|
|
Query package that contains a given package identifier, i.e. the
|
|
|
|
\fIMD5\fR digest of the combined header and
|
|
|
|
@@ -581,6 +587,10 @@ Query all packages that requires \fICAPA
|
|
|
|
.SS "PACKAGE QUERY OPTIONS:"
|
|
|
|
.PP
|
|
|
|
.TP
|
|
|
|
+\fB--basedon\fR
|
|
|
|
+Show what packages a patch-rpm is based on. A patch-rpm can only be
|
|
|
|
+installed if one of the packages it is based on is installed.
|
|
|
|
+.TP
|
|
|
|
\fB--changelog\fR
|
|
|
|
Display change information for the package.
|
|
|
|
.TP
|
|
|
|
@@ -618,7 +628,8 @@ Orders the package listing by install ti
|
|
|
|
packages are at the top.
|
|
|
|
.TP
|
|
|
|
\fB-l, --list\fR
|
|
|
|
-List files in package.
|
|
|
|
+List files in package. If the \fB\-P\fP option is also given, only
|
|
|
|
+patched files are shown.
|
|
|
|
.TP
|
|
|
|
\fB--provides\fR
|
|
|
|
List capabilities this package provides.
|
|
|
|
Index: rpmpopt.in
|
|
|
|
===================================================================
|
|
|
|
--- rpmpopt.in.orig
|
|
|
|
+++ rpmpopt.in
|
|
|
|
@@ -76,6 +76,10 @@ rpm alias --supplements --qf \
|
|
|
|
"[%|ENHANCESFLAGS:depflag_strong?{%{ENHANCESNAME} %{ENHANCESFLAGS:depflags} %{ENHANCESVERSION}\n}|]" \
|
|
|
|
--POPTdesc=$"list capabilities this package supplements"
|
|
|
|
|
|
|
|
+rpm alias --basedon --qf \
|
|
|
|
+ "[%{PATCHESNAME} %{PATCHESFLAGS:depflags} %{PATCHESVERSION}\n]" \
|
|
|
|
+ --POPTdesc=$"list packages this patch-rpm is based on"
|
|
|
|
+
|
|
|
|
rpm alias --info --qf 'Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n\
|
|
|
|
Version : %-27{VERSION} Vendor: %{VENDOR}\n\
|
|
|
|
Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\
|
|
|
|
@@ -373,6 +377,10 @@ rpmq alias --supplements --qf \
|
|
|
|
"[%|ENHANCESFLAGS:depflag_strong?{%{ENHANCESNAME} %{ENHANCESFLAGS:depflags} %{ENHANCESVERSION}\n}|]" \
|
|
|
|
--POPTdesc=$"list capabilities this package supplements"
|
|
|
|
|
|
|
|
+rpmq alias --basedon --qf \
|
|
|
|
+ "[%{PATCHESNAME} %{PATCHESFLAGS:depflags} %{PATCHESVERSION}\n]" \
|
|
|
|
+ --POPTdesc=$"list packages this patch-rpm is based on"
|
|
|
|
+
|
|
|
|
rpmq alias --info --qf 'Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n\
|
|
|
|
Version : %-27{VERSION} Vendor: %{VENDOR}\n\
|
|
|
|
Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\
|
|
|
|
@@ -488,6 +496,10 @@ rpmquery alias --supplements --qf \
|
|
|
|
"[%|ENHANCESFLAGS:depflag_strong?{%{ENHANCESNAME} %{ENHANCESFLAGS:depflags} %{ENHANCESVERSION}\n}|]" \
|
|
|
|
--POPTdesc=$"list capabilities this package supplements"
|
|
|
|
|
|
|
|
+rpmquery alias --basedon --qf \
|
|
|
|
+ "[%{PATCHESNAME} %{PATCHESFLAGS:depflags} %{PATCHESVERSION}\n]" \
|
|
|
|
+ --POPTdesc=$"list packages this patch-rpm is based on"
|
|
|
|
+
|
|
|
|
rpmquery alias --info --qf 'Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n\
|
|
|
|
Version : %-27{VERSION} Vendor: %{VENDOR}\n\
|
|
|
|
Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\
|