--- include/rpm/rpmcli.h.orig 2023-09-19 10:10:10.000000000 +0000 +++ include/rpm/rpmcli.h 2023-10-12 11:43:59.662617302 +0000 @@ -306,6 +306,7 @@ enum rpmInstallFlags_e { INSTALL_ALLMATCHES = (1 << 9), /*!< from --allmatches */ INSTALL_REINSTALL = (1 << 10), /*!< from --reinstall */ INSTALL_RESTORE = (1 << 11), /*!< from --restore */ + INSTALL_RUNPOSTTRANS = (1 << 12), /*!< from --runposttrans */ }; typedef rpmFlags rpmInstallFlags; @@ -396,6 +397,15 @@ int rpmErase(rpmts ts, struct rpmInstall int rpmRestore(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t argv); /** \ingroup rpmcli + * Run posttrans scriptlets + * @param ts transaction set + * @param ia control args/bits + * @param argv array of trigger manifest file names (NULL terminated) + * @return 0 on success + */ +int rpmRunPostTrans(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t argv); + +/** \ingroup rpmcli */ extern struct rpmInstallArguments_s rpmIArgs; --- include/rpm/rpmts.h.orig 2023-10-12 11:43:35.870664176 +0000 +++ include/rpm/rpmts.h 2023-10-12 11:43:59.662617302 +0000 @@ -253,6 +253,15 @@ int rpmtsOrder(rpmts ts); int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet); /** \ingroup rpmts + * Run all posttrans scriptlets described in the manifest data. + * + * @param ts transaction set + * @param manifest the manifest data + * @return 0 on success, -1 on error + */ +int rpmtsRunPostTrans(rpmts ts, ARGV_const_t manifest); + +/** \ingroup rpmts * Reference a transaction set instance. * @param ts transaction set * @return new transaction set reference --- lib/poptI.c.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/poptI.c 2023-10-12 11:43:59.662617302 +0000 @@ -283,6 +283,10 @@ struct poptOption rpmInstallPoptTable[] &rpmIArgs.installInterfaceFlags, (INSTALL_RESTORE), N_("restore package(s)"), N_("+") }, + { "runposttrans", '\0', POPT_BIT_SET, + &rpmIArgs.installInterfaceFlags, INSTALL_RUNPOSTTRANS, + N_("run posttrans scriptlet"), + N_("") }, POPT_TABLEEND }; --- lib/psm.c.orig 2023-10-12 11:43:35.850664215 +0000 +++ lib/psm.c 2023-10-12 11:43:59.662617302 +0000 @@ -1001,7 +1001,7 @@ static rpmRC rpmPackageErase(rpmts ts, r } if (rc) break; - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) { + if (ts->dump_posttrans || !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) { /* Prepare post transaction uninstall triggers */ rpmtriggersPrepPostUnTransFileTrigs(psm->ts, psm->te); } --- lib/rpminstall.c.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/rpminstall.c 2023-10-12 11:43:59.662617302 +0000 @@ -6,6 +6,8 @@ #include +#include + #include #include #include /* rpmReadPackageFile, vercmp etc */ @@ -830,3 +832,32 @@ int rpmInstallSource(rpmts ts, const cha return rc; } +int rpmRunPostTrans(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t fileArgv) +{ + ARGV_t manifest = NULL; + FILE *f; + char line[BUFSIZ], *s, *p; + int rc = 1; + + if (fileArgv == NULL) return 0; + if (!fileArgv[0] || fileArgv[1] != NULL) { + rpmlog(RPMLOG_ERR, _("runposttrans needs exactly one manifest file\n")); + goto exit; + } + if (!(f = fopen(fileArgv[0], "r"))) { + rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), fileArgv[0], strerror(errno)); + goto exit; + } + while ((s = fgets(line, sizeof(line) - 1, f)) != 0) { + if (p = strrchr(s, '\n')) + *p = 0; + argvAdd(&manifest, s); + } + fclose(f); + rpmlog(RPMLOG_DEBUG, "running posttrans scriptlets\n"); + rpmtsClean(ts); + rc = rpmtsRunPostTrans(ts, manifest); +exit: + argvFree(manifest); + return rc; +} --- lib/rpmtriggers.c.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/rpmtriggers.c 2023-10-12 11:43:59.662617302 +0000 @@ -1,5 +1,6 @@ #include "system.h" +#include #include #include #include @@ -34,7 +35,7 @@ rpmtriggers rpmtriggersFree(rpmtriggers return NULL; } -static void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum, +void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum, unsigned int tix, unsigned int priority) { if (trigs->count == trigs->alloced) { @@ -178,6 +179,14 @@ int runPostUnTransFileTrigs(rpmts ts) if (trigH == NULL) continue; + if (ts->dump_posttrans) { + char *trigNEVRA = headerGetAsString(trigH, RPMTAG_NEVRA); + rpmlog(RPMLOG_NOTICE, "dump_posttrans: transfiletriggerpostun %u %u %s\n", trigs->triggerInfo[i].tix, trigs->triggerInfo[i].hdrNum, trigNEVRA); + free(trigNEVRA); + headerFree(trigH); + continue; + } + /* Prepare and run script */ script = rpmScriptFromTriggerTag(trigH, triggertag(RPMSENSE_TRIGGERPOSTUN), @@ -587,6 +596,16 @@ rpmRC runImmedFileTriggers(rpmts ts, rpm rpmTagVal priorityTag; rpmtriggers triggers; + if (sense == RPMSENSE_TRIGGERIN && tm == RPMSCRIPT_TRANSFILETRIGGER && ts->dump_posttrans) { + unsigned int hdrNum = headerGetInstance(trigH); + if (hdrNum) { + char *trigNEVRA = headerGetAsString(trigH, RPMTAG_NEVRA); + rpmlog(RPMLOG_NOTICE, "dump_posttrans: install %u %s\n", hdrNum, trigNEVRA); + free(trigNEVRA); + } + headerFree(trigH); + return RPMRC_OK; + } if (tm == RPMSCRIPT_FILETRIGGER) { priorityTag = RPMTAG_FILETRIGGERPRIORITIES; } else { --- lib/rpmtriggers.h.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/rpmtriggers.h 2023-10-12 11:43:59.662617302 +0000 @@ -27,6 +27,10 @@ rpmtriggers rpmtriggersCreate(unsigned i RPM_GNUC_INTERNAL rpmtriggers rpmtriggersFree(rpmtriggers triggers); +RPM_GNUC_INTERNAL +void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum, + unsigned int tix, unsigned int priority); + /* * Prepare post trans uninstall file triggers. After transcation uninstalled * files are not saved anywhere. So we need during uninstalation of every --- lib/rpmts_internal.h.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/rpmts_internal.h 2023-10-12 11:43:59.662617302 +0000 @@ -94,6 +94,8 @@ struct rpmts_s { int min_writes; /*!< macro minimize_writes used */ time_t overrideTime; /*!< Time value used when overriding system clock. */ + + int dump_posttrans; /*!< macro dump_posttrans used */ }; #ifdef __cplusplus --- lib/transaction.c.orig 2023-09-19 10:10:10.000000000 +0000 +++ lib/transaction.c 2023-10-12 11:44:28.398560689 +0000 @@ -1475,6 +1475,8 @@ static int rpmtsSetup(rpmts ts, rpmprobF /* Get available space on mounted file systems. */ (void) rpmtsInitDSI(ts); + /* Initialize the dump_posttrans flag */ + ts->dump_posttrans = (rpmExpandNumeric("%{?_dump_posttrans}") > 0); return 0; } @@ -1858,27 +1860,31 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rp /* Actually install and remove packages */ nfailed = rpmtsProcess(ts); + if (ts->dump_posttrans) { + rpmlog(RPMLOG_NOTICE, "dump_posttrans: enabled\n"); + } + /* Run %posttrans scripts unless disabled */ - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) { + if (!ts->dump_posttrans && !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) { rpmlog(RPMLOG_DEBUG, "running %%posttrans scripts\n"); runTransScripts(ts, PKG_POSTTRANS); } /* Run %postuntrans scripts unless disabled */ - if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUNTRANS)) { + if (!ts->dump_posttrans && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUNTRANS)) { rpmlog(RPMLOG_DEBUG, "running %%postuntrans scripts\n"); runTransScripts(ts, PKG_POSTUNTRANS); } /* Run %transfiletriggerpostun scripts unless disabled */ - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { + if (!ts->dump_posttrans && !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { runFileTriggers(ts, NULL, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER, 0); } - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) { + if (ts->dump_posttrans || !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) { runPostUnTransFileTrigs(ts); } /* Run %transfiletriggerin scripts unless disabled */ - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { + if (ts->dump_posttrans || !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { runTransScripts(ts, PKG_TRANSFILETRIGGERIN); } /* Final exit code */ @@ -1901,3 +1907,117 @@ exit: sigaction(SIGPIPE, &oact, NULL); return rc; } + +static unsigned int runPostTransFindPkgNum(const char **lpp) +{ + const char *lp = *lpp; + unsigned int num = strtoul(lp, 0, 10); + while (*lp >= '0' && *lp <= '9') + lp++; + while (*lp == ' ') + lp++; + *lpp = lp; + return num; +} + +static Header runPostTransFindPkg(rpmts ts, const char *lp) +{ + rpmdbMatchIterator mi; + Header h = NULL; + unsigned int hdrnum = runPostTransFindPkgNum(&lp); + if (!*lp) + return NULL; + if (hdrnum) { + mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &hdrnum, sizeof(hdrnum)); + h = headerLink(rpmdbNextIterator(mi)); + rpmdbFreeIterator(mi); + } + if (h) { + char *NEVRA = headerGetAsString(h, RPMTAG_NEVRA); + if (!NEVRA || strcmp(NEVRA, lp) != 0) + h = headerFree(h); + _free(NEVRA); + } + if (!h) { + mi = rpmtsInitIterator(ts, RPMDBI_LABEL, lp, strlen(lp)); + h = headerLink(rpmdbNextIterator(mi)); + rpmdbFreeIterator(mi); + } + if (!h) + rpmlog(RPMLOG_WARNING, "package %s is not installed\n", lp); + return h; +} + +int rpmtsRunPostTrans(rpmts ts, ARGV_const_t manifest) +{ + int rc = -1; /* assume failure */ + /* setup */ + tsMembers tsmem = rpmtsMembers(ts); + rpmtxn txn = NULL; + /* Ignore SIGPIPE for the duration of transaction */ + struct sigaction act, oact; + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, &oact); + /* Force default 022 umask during transaction for consistent results */ + mode_t oldmask = umask(022); + + if (tsmem->orderCount) + goto exit; + char *line; + while ((line = *manifest++) != 0) { + if (!strncmp(line, "dump_posttrans: install ", 24)) { + const char *lp = line + 24; + Header h = runPostTransFindPkg(ts, lp); + if (!h) + continue; + rpmte p = rpmteNew(ts, h, TR_ADDED, line + 45, NULL, RPMTE_INSTALL); + if (tsmem->orderCount >= tsmem->orderAlloced) { + tsmem->orderAlloced += (tsmem->orderCount - tsmem->orderAlloced) + tsmem->delta; + tsmem->order = xrealloc(tsmem->order, tsmem->orderAlloced * sizeof(*tsmem->order)); + } + tsmem->order[tsmem->orderCount++] = p; + + if (tsmem->addedPackages == NULL) + tsmem->addedPackages = rpmalCreate(ts, 5); + rpmalAdd(tsmem->addedPackages, p); + packageHashAddEntry(tsmem->installedPackages, headerGetInstance(h), p); + } else if (!strncmp(line, "dump_posttrans: transfiletriggerpostun ", 39)) { + const char *lp = line + 39; + unsigned int tix = runPostTransFindPkgNum(&lp); + Header h = runPostTransFindPkg(ts, lp); + struct rpmtd_s priorities; + if (!h) + continue; + headerGet(h, RPMTAG_TRANSFILETRIGGERPRIORITIES, &priorities, HEADERGET_MINMEM); + if (rpmtdSetIndex(&priorities, tix) >= 0) + rpmtriggersAdd(ts->trigs2run, headerGetInstance(h), tix, *rpmtdGetUint32(&priorities)); + headerFree(h); + } + } + + if (!(txn = rpmtxnBegin(ts, RPMTXN_WRITE))) + goto exit; + + if (rpmChrootSet(rpmtsRootDir(ts))) + goto exit; + + /* run posttrans scripts */ + rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n"); + runTransScripts(ts, PKG_POSTTRANS); + runTransScripts(ts, PKG_POSTUNTRANS); + /* run %transfiletriggerin scripts */ + runFileTriggers(ts, NULL, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER, 0); + /* run %transfiletriggerpostun scrips */ + runPostUnTransFileTrigs(ts); + /* Run immed %transfiletriggerin scripts */ + runTransScripts(ts, PKG_TRANSFILETRIGGERIN); + rc = 0; + +exit: + (void) umask(oldmask); + rpmtxnEnd(txn); + sigaction(SIGPIPE, &oact, NULL); + rpmtsEmpty(ts); + return rc; +} --- tools/rpm.c.orig 2023-09-19 10:10:10.000000000 +0000 +++ tools/rpm.c 2023-10-12 11:43:59.662617302 +0000 @@ -21,6 +21,7 @@ enum modes { MODE_ERASE = (1 << 2), MODE_RESTORE = (1 << 4), #define MODES_IE (MODE_INSTALL | MODE_ERASE) + MODE_RUNPOSTTRANS = (1 << 5), MODE_UNKNOWN = 0 }; @@ -115,6 +116,11 @@ int main(int argc, char *argv[]) int eflags = (ia->installInterfaceFlags & INSTALL_ERASE); int rflags = (ia->installInterfaceFlags & INSTALL_RESTORE); + if (ia->installInterfaceFlags & INSTALL_RUNPOSTTRANS) { + if (iflags || eflags || rflags) + argerror(_("only one major mode may be specified")); + bigMode = MODE_RUNPOSTTRANS; + } if (iflags & eflags & rflags) argerror(_("only one major mode may be specified")); else if (iflags) @@ -293,6 +299,14 @@ int main(int argc, char *argv[]) ec = rpmcliVerify(ts, qva, (ARGV_const_t) poptGetArgs(optCon)); } break; + case MODE_RUNPOSTTRANS: + if (!poptPeekArg(optCon)) { + argerror(_("need posttrans manifest for --runposttrans")); + } else { + ec += rpmRunPostTrans(ts, ia, (ARGV_const_t) poptGetArgs(optCon)); + } + break; + case MODE_UNKNOWN: if (poptPeekArg(optCon) != NULL || argc <= 1) { printUsage(optCon, stderr, 0);