Blame posttrans.diff

347c6d
--- include/rpm/rpmcli.h.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ include/rpm/rpmcli.h	2025-05-19 13:58:25.952973533 +0000
e0a517
@@ -306,6 +306,7 @@ enum rpmInstallFlags_e {
ef05fe
     INSTALL_ALLMATCHES	= (1 << 9),	/*!< from --allmatches */
ef05fe
     INSTALL_REINSTALL	= (1 << 10),	/*!< from --reinstall */
e0a517
     INSTALL_RESTORE	= (1 << 11),	/*!< from --restore */
e0a517
+    INSTALL_RUNPOSTTRANS = (1 << 12),	/*!< from --runposttrans */
ef05fe
 };
ef05fe
 
ef05fe
 typedef rpmFlags rpmInstallFlags;
e0a517
@@ -396,6 +397,15 @@ int rpmErase(rpmts ts, struct rpmInstall
e0a517
 int rpmRestore(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t argv);
ef05fe
 
ef05fe
 /** \ingroup rpmcli
ef05fe
+ * Run posttrans scriptlets
ef05fe
+ * @param ts		transaction set
ef05fe
+ * @param ia		control args/bits
ef05fe
+ * @param argv		array of trigger manifest file names (NULL terminated)
ef05fe
+ * @return		0 on success
ef05fe
+ */
ef05fe
+int rpmRunPostTrans(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t argv);
ef05fe
+
ef05fe
+/** \ingroup rpmcli
ef05fe
  */
ef05fe
 extern struct rpmInstallArguments_s rpmIArgs;
ef05fe
 
2799fd
--- include/rpm/rpmts.h.orig	2025-05-19 13:58:13.800993465 +0000
2799fd
+++ include/rpm/rpmts.h	2025-05-19 13:58:25.952973533 +0000
5b17a5
@@ -253,6 +253,15 @@ int rpmtsOrder(rpmts ts);
e0a517
 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet);
ef05fe
 
e0a517
 /** \ingroup rpmts
e0a517
+ * Run all posttrans scriptlets described in the manifest data.
e0a517
+ *       
e0a517
+ * @param ts		transaction set
e0a517
+ * @param manifest	the manifest data
e0a517
+ * @return		0 on success, -1 on error
e0a517
+ */
e0a517
+int rpmtsRunPostTrans(rpmts ts, ARGV_const_t manifest);
e0a517
+
e0a517
+/** \ingroup rpmts
e0a517
  * Reference a transaction set instance.
e0a517
  * @param ts		transaction set
e0a517
  * @return		new transaction set reference
347c6d
--- lib/poptI.c.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/poptI.c	2025-05-19 13:58:25.952973533 +0000
5b17a5
@@ -283,6 +283,10 @@ struct poptOption rpmInstallPoptTable[]
e0a517
 	&rpmIArgs.installInterfaceFlags, (INSTALL_RESTORE),
e0a517
 	N_("restore package(s)"),
e0a517
 	N_("<packagefile>+") },
e0a517
+ { "runposttrans", '\0', POPT_BIT_SET,
e0a517
+	&rpmIArgs.installInterfaceFlags, INSTALL_RUNPOSTTRANS,
e0a517
+	N_("run posttrans scriptlet"),
e0a517
+	N_("<posttransmanifest>") },
e0a517
 
e0a517
    POPT_TABLEEND
e0a517
 };
2799fd
--- lib/psm.c.orig	2025-05-19 13:58:13.780993499 +0000
2799fd
+++ lib/psm.c	2025-05-19 14:32:29.713648565 +0000
2799fd
@@ -612,6 +612,8 @@ static int isUpdate(rpmts ts, rpmte te)
2799fd
     rpmtsi pi = rpmtsiInit(ts);
2799fd
     rpmte p;
2799fd
     int update = 0;
2799fd
+    if (rpmteAddOp(te) == RPMTE_RUNPOSTTRANS_UPDATE)
2799fd
+	update = 1;
2799fd
     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
2799fd
 	if (rpmteDependsOn(p) == te) {
2799fd
 	    update = 1;
2799fd
@@ -1009,7 +1011,7 @@ static rpmRC rpmPackageErase(rpmts ts, r
e0a517
 	}
e0a517
 	if (rc) break;
e0a517
 
e0a517
-	if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) {
e0a517
+	if (ts->dump_posttrans || !(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) {
e0a517
 	    /* Prepare post transaction uninstall triggers */
e0a517
 	    rpmtriggersPrepPostUnTransFileTrigs(psm->ts, psm->te);
e0a517
 	}
347c6d
--- lib/rpminstall.c.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/rpminstall.c	2025-05-19 13:58:25.952973533 +0000
e0a517
@@ -6,6 +6,8 @@
e0a517
 
e0a517
 #include <string.h>
ef05fe
 
ef05fe
+#include <errno.h>
ef05fe
+
ef05fe
 #include <rpm/rpmcli.h>
ef05fe
 #include <rpm/rpmtag.h>
ef05fe
 #include <rpm/rpmlib.h>		/* rpmReadPackageFile, vercmp etc */
347c6d
@@ -90,6 +92,24 @@ static rpmVSFlags setvsFlags(struct rpmI
347c6d
     return vsflags;
347c6d
 }
347c6d
 
347c6d
+static const char *
347c6d
+posttranstag2str(rpmTagVal stag)
347c6d
+{
347c6d
+    switch (stag) {
347c6d
+    case RPMTAG_POSTTRANS:
347c6d
+	return "posttrans";
347c6d
+    case RPMTAG_POSTUNTRANS:
347c6d
+	return "postuntrans";
347c6d
+    case RPMTAG_TRIGGERIN:
347c6d
+	return "transfiletriggerin";
347c6d
+    case RPMTAG_TRIGGERUN:
347c6d
+	return "transfiletriggerun";
347c6d
+    case RPMTAG_TRIGGERPOSTUN:
347c6d
+	return "transfiletriggerpostun";
347c6d
+    }
347c6d
+    return rpmTagGetName(stag);
347c6d
+}
347c6d
+
347c6d
 void * rpmShowProgress(const void * arg,
347c6d
 			const rpmCallbackType what,
347c6d
 			const rpm_loff_t amount,
347c6d
@@ -213,8 +233,20 @@ void * rpmShowProgress(const void * arg,
347c6d
     case RPMCALLBACK_CPIO_ERROR:
347c6d
 	break;
347c6d
     case RPMCALLBACK_SCRIPT_ERROR:
347c6d
+	if (flags & INSTALL_RUNPOSTTRANS) {
347c6d
+	    rpmTagVal stag = (rpmTagVal)amount;
347c6d
+	    char *s = headerGetAsString(h, RPMTAG_NEVRA);
347c6d
+	    fprintf(stdout, "Error from %%%s(%s)\n", posttranstag2str(stag), s);
347c6d
+	    free(s);
347c6d
+	}
347c6d
 	break;
347c6d
     case RPMCALLBACK_SCRIPT_START:
347c6d
+	if (flags & INSTALL_RUNPOSTTRANS) {
347c6d
+	    rpmTagVal stag = (rpmTagVal)amount;
347c6d
+	    char *s = headerGetAsString(h, RPMTAG_NEVRA);
347c6d
+	    fprintf(stdout, "Running %%%s(%s)\n", posttranstag2str(stag), s);
347c6d
+	    free(s);
347c6d
+	}
347c6d
 	break;
347c6d
     case RPMCALLBACK_SCRIPT_STOP:
347c6d
 	break;
347c6d
@@ -831,3 +863,33 @@ int rpmInstallSource(rpmts ts, const cha
ef05fe
     return rc;
ef05fe
 }
ef05fe
 
ef05fe
+int rpmRunPostTrans(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_const_t fileArgv)
ef05fe
+{
ef05fe
+    ARGV_t manifest = NULL;
ef05fe
+    FILE *f;
ef05fe
+    char line[BUFSIZ], *s, *p;
ef05fe
+    int rc = 1;
ef05fe
+
ef05fe
+    if (fileArgv == NULL) return 0;
ef05fe
+    if (!fileArgv[0] || fileArgv[1] != NULL) {
ef05fe
+	rpmlog(RPMLOG_ERR, _("runposttrans needs exactly one manifest file\n"));
ef05fe
+	goto exit;
ef05fe
+    }
ef05fe
+    if (!(f = fopen(fileArgv[0], "r"))) {
ef05fe
+	rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), fileArgv[0], strerror(errno));
ef05fe
+	goto exit;
ef05fe
+    }
ef05fe
+    while ((s = fgets(line, sizeof(line) - 1, f)) != 0) {
01de3b
+	if ((p = strrchr(s, '\n')) != 0)
ef05fe
+	    *p = 0;
ef05fe
+	argvAdd(&manifest, s);
ef05fe
+    }
ef05fe
+    fclose(f);
ef05fe
+    rpmlog(RPMLOG_DEBUG, "running posttrans scriptlets\n");
ef05fe
+    rpmtsClean(ts);
347c6d
+    setNotifyFlag(ia, ts);
ef05fe
+    rc = rpmtsRunPostTrans(ts, manifest);
ef05fe
+exit:
ef05fe
+    argvFree(manifest);
ef05fe
+    return rc;
ef05fe
+}
2799fd
--- lib/rpmte_internal.h.orig	2025-05-19 14:17:38.131089552 +0000
2799fd
+++ lib/rpmte_internal.h	2025-05-19 14:18:06.503043382 +0000
2799fd
@@ -32,6 +32,7 @@ enum addOp_e {
2799fd
   RPMTE_UPGRADE       = 1,
2799fd
   RPMTE_REINSTALL     = 2,
2799fd
   RPMTE_RESTORE       = 3,
2799fd
+  RPMTE_RUNPOSTTRANS_UPDATE = 4,
2799fd
 };
2799fd
 
2799fd
 /** \ingroup rpmte
347c6d
--- lib/rpmtriggers.c.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/rpmtriggers.c	2025-05-19 14:36:21.781275493 +0000
ef05fe
@@ -1,5 +1,6 @@
ef05fe
 #include "system.h"
ef05fe
 
ef05fe
+#include <rpm/rpmlog.h>
ef05fe
 #include <rpm/rpmts.h>
ef05fe
 #include <rpm/rpmdb.h>
ef05fe
 #include <rpm/rpmds.h>
ef05fe
@@ -34,7 +35,7 @@ rpmtriggers rpmtriggersFree(rpmtriggers
ef05fe
     return NULL;
ef05fe
 }
ef05fe
 
ef05fe
-static void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum,
ef05fe
+void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum,
ef05fe
 			    unsigned int tix, unsigned int priority)
ef05fe
 {
ef05fe
     if (trigs->count == trigs->alloced) {
01de3b
@@ -190,6 +191,14 @@ int runPostUnTransFileTrigs(rpmts ts)
ef05fe
 	if (trigH == NULL)
ef05fe
 	    continue;
ef05fe
 
ef05fe
+	if (ts->dump_posttrans) {
ef05fe
+	    char *trigNEVRA = headerGetAsString(trigH, RPMTAG_NEVRA);
ef05fe
+	    rpmlog(RPMLOG_NOTICE, "dump_posttrans: transfiletriggerpostun %u %u %s\n", trigs->triggerInfo[i].tix, trigs->triggerInfo[i].hdrNum, trigNEVRA);
ef05fe
+	    free(trigNEVRA);
ef05fe
+	    headerFree(trigH);
ef05fe
+	    continue;
ef05fe
+	}
ef05fe
+
ef05fe
 	/* Prepare and run script */
ef05fe
 	script = rpmScriptFromTriggerTag(trigH,
ef05fe
 		triggertag(RPMSENSE_TRIGGERPOSTUN),
2799fd
@@ -603,6 +612,21 @@ rpmRC runFileTriggers(rpmts ts, rpmte te
2799fd
     return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
2799fd
 }
2799fd
 
2799fd
+static int isUpdate(rpmts ts, rpmte te)
2799fd
+{
2799fd
+    rpmtsi pi = rpmtsiInit(ts);
2799fd
+    rpmte p;
2799fd
+    int update = 0;
2799fd
+    while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
2799fd
+        if (rpmteDependsOn(p) == te) {
2799fd
+            update = 1;
2799fd
+            break;
2799fd
+        }
2799fd
+    }
2799fd
+    rpmtsiFree(pi);
2799fd
+    return update;
2799fd
+}
2799fd
+
2799fd
 rpmRC runImmedFileTriggers(rpmts ts, rpmte te, int arg1, rpmsenseFlags sense,
2799fd
 			    rpmscriptTriggerModes tm, int priorityClass)
2799fd
 {
2799fd
@@ -613,6 +637,19 @@ rpmRC runImmedFileTriggers(rpmts ts, rpm
ef05fe
     rpmTagVal priorityTag;
ef05fe
     rpmtriggers triggers;
ef05fe
 
ef05fe
+    if (sense == RPMSENSE_TRIGGERIN && tm == RPMSCRIPT_TRANSFILETRIGGER && ts->dump_posttrans) {
ef05fe
+	unsigned int hdrNum = headerGetInstance(trigH);
ef05fe
+	if (hdrNum) {
ef05fe
+	    char *trigNEVRA = headerGetAsString(trigH, RPMTAG_NEVRA);
2799fd
+	    if (isUpdate(ts, te))
2799fd
+		rpmlog(RPMLOG_NOTICE, "dump_posttrans: update %u %s\n", hdrNum, trigNEVRA);
2799fd
+	    else
2799fd
+		rpmlog(RPMLOG_NOTICE, "dump_posttrans: install %u %s\n", hdrNum, trigNEVRA);
ef05fe
+	    free(trigNEVRA);
ef05fe
+	}
ef05fe
+	headerFree(trigH);
ef05fe
+	return RPMRC_OK;
ef05fe
+    }
ef05fe
     if (tm == RPMSCRIPT_FILETRIGGER) {
ef05fe
 	priorityTag = RPMTAG_FILETRIGGERPRIORITIES;
ef05fe
     } else {
347c6d
--- lib/rpmtriggers.h.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/rpmtriggers.h	2025-05-19 13:58:25.956973525 +0000
01de3b
@@ -24,6 +24,10 @@ rpmtriggers rpmtriggersCreate(unsigned i
ef05fe
 RPM_GNUC_INTERNAL
ef05fe
 rpmtriggers rpmtriggersFree(rpmtriggers triggers);
ef05fe
 
ef05fe
+RPM_GNUC_INTERNAL
ef05fe
+void rpmtriggersAdd(rpmtriggers trigs, unsigned int hdrNum,
ef05fe
+			unsigned int tix, unsigned int priority);
ef05fe
+
ef05fe
 /*
ef05fe
  * Prepare post trans uninstall file triggers. After transcation uninstalled
ef05fe
  * files are not saved anywhere. So we need during uninstalation of every
347c6d
--- lib/rpmts_internal.h.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/rpmts_internal.h	2025-05-19 13:58:25.956973525 +0000
01de3b
@@ -83,6 +83,8 @@ struct rpmts_s {
e0a517
     int min_writes;             /*!< macro minimize_writes used */
ef05fe
 
e0a517
     time_t overrideTime;	/*!< Time value used when overriding system clock. */
ef05fe
+
ef05fe
+    int dump_posttrans;		/*!< macro dump_posttrans used */
ef05fe
 };
ef05fe
 
01de3b
 /** \ingroup rpmts
347c6d
--- lib/transaction.c.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ lib/transaction.c	2025-05-21 13:35:19.931704634 +0000
5b17a5
@@ -1475,6 +1475,8 @@ static int rpmtsSetup(rpmts ts, rpmprobF
ef05fe
     /* Get available space on mounted file systems. */
ef05fe
     (void) rpmtsInitDSI(ts);
ef05fe
 
ef05fe
+    /* Initialize the dump_posttrans flag */
ef05fe
+    ts->dump_posttrans = (rpmExpandNumeric("%{?_dump_posttrans}") > 0);
ef05fe
     return 0;
ef05fe
 }
ef05fe
 
2799fd
@@ -1858,6 +1860,16 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rp
ef05fe
     /* Actually install and remove packages */
ef05fe
     nfailed = rpmtsProcess(ts);
ef05fe
 
ef05fe
+    if (ts->dump_posttrans) {
ef05fe
+	rpmlog(RPMLOG_NOTICE, "dump_posttrans: enabled\n");
2799fd
+	runTransScripts(ts, PKG_POSTUNTRANS);	/* need to run them right away */
01de3b
+	runPostUnTransFileTrigs(ts);
01de3b
+	runTransScripts(ts, PKG_TRANSFILETRIGGERIN);
01de3b
+	/* Final exit code */
01de3b
+	rc = nfailed ? -1 : 0;
01de3b
+	goto exit;
ef05fe
+    }
ef05fe
+
ef05fe
     /* Run %posttrans scripts unless disabled */
01de3b
     if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) {
5b17a5
 	rpmlog(RPMLOG_DEBUG, "running %%posttrans scripts\n");
2799fd
@@ -1901,3 +1913,120 @@ exit:
e0a517
     sigaction(SIGPIPE, &oact, NULL);
ef05fe
     return rc;
ef05fe
 }
ef05fe
+
ef05fe
+static unsigned int runPostTransFindPkgNum(const char **lpp)
ef05fe
+{
ef05fe
+    const char *lp = *lpp;
ef05fe
+    unsigned int num = strtoul(lp, 0, 10);
ef05fe
+    while (*lp >= '0' && *lp <= '9')
ef05fe
+	lp++;
ef05fe
+    while (*lp == ' ')
ef05fe
+	lp++;
ef05fe
+    *lpp = lp;
ef05fe
+    return num;
ef05fe
+}
ef05fe
+
ef05fe
+static Header runPostTransFindPkg(rpmts ts, const char *lp)
ef05fe
+{
ef05fe
+    rpmdbMatchIterator mi;
ef05fe
+    Header h = NULL;
ef05fe
+    unsigned int hdrnum = runPostTransFindPkgNum(&lp);
ef05fe
+    if (!*lp)
ef05fe
+	return NULL;
ef05fe
+    if (hdrnum) {
ef05fe
+	mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &hdrnum, sizeof(hdrnum));
ef05fe
+	h = headerLink(rpmdbNextIterator(mi));
ef05fe
+	rpmdbFreeIterator(mi);
ef05fe
+    }
ef05fe
+    if (h) {
ef05fe
+	char *NEVRA = headerGetAsString(h, RPMTAG_NEVRA);
ef05fe
+	if (!NEVRA || strcmp(NEVRA, lp) != 0)
ef05fe
+	    h = headerFree(h);
ef05fe
+	_free(NEVRA);
ef05fe
+    }
ef05fe
+    if (!h) {
ef05fe
+	mi = rpmtsInitIterator(ts, RPMDBI_LABEL, lp, strlen(lp));
ef05fe
+	h = headerLink(rpmdbNextIterator(mi));
ef05fe
+	rpmdbFreeIterator(mi);
ef05fe
+    }
ef05fe
+    if (!h)
ef05fe
+	rpmlog(RPMLOG_WARNING, "package %s is not installed\n", lp);
ef05fe
+    return h;
ef05fe
+}
ef05fe
+
ef05fe
+int rpmtsRunPostTrans(rpmts ts, ARGV_const_t manifest)
ef05fe
+{
ef05fe
+    int rc = -1; /* assume failure */
ef05fe
+    /* setup */
ef05fe
+    tsMembers tsmem = rpmtsMembers(ts);
ef05fe
+    rpmtxn txn = NULL;
ef05fe
+    /* Ignore SIGPIPE for the duration of transaction */
5b17a5
+    struct sigaction act, oact;
5b17a5
+    memset(&act, 0, sizeof(act));
5b17a5
+    act.sa_handler = SIG_IGN;
5b17a5
+    sigaction(SIGPIPE, &act, &oact;;
ef05fe
+    /* Force default 022 umask during transaction for consistent results */
ef05fe
+    mode_t oldmask = umask(022);
ef05fe
+    
ef05fe
+    if (tsmem->orderCount)
ef05fe
+	goto exit;
ef05fe
+    char *line;
ef05fe
+    while ((line = *manifest++) != 0) {
2799fd
+	if (strncmp(line, "dump_posttrans: ", 16) != 0)
2799fd
+	    continue;
2799fd
+	line += 16;
2799fd
+	if (!strncmp(line, "install ", 8) || !strncmp(line, "update ", 7)) {
2799fd
+	    const char *lp = line + (*line == 'i' ? 8 : 7);
ef05fe
+	    Header h = runPostTransFindPkg(ts, lp);
ef05fe
+	    if (!h)
ef05fe
+		continue;
2799fd
+	    rpmte p = rpmteNew(ts, h, TR_ADDED, NULL, NULL, (*line == 'i' ? RPMTE_INSTALL: RPMTE_RUNPOSTTRANS_UPDATE));
ef05fe
+	    if (tsmem->orderCount >= tsmem->orderAlloced) {
ef05fe
+		tsmem->orderAlloced += (tsmem->orderCount - tsmem->orderAlloced) + tsmem->delta;
ef05fe
+		tsmem->order = xrealloc(tsmem->order, tsmem->orderAlloced * sizeof(*tsmem->order));
ef05fe
+	    }
ef05fe
+	    tsmem->order[tsmem->orderCount++] = p; 
ef05fe
+
ef05fe
+	    if (tsmem->addedPackages == NULL)
ef05fe
+		tsmem->addedPackages = rpmalCreate(ts, 5);
ef05fe
+	    rpmalAdd(tsmem->addedPackages, p);
ef05fe
+	    packageHashAddEntry(tsmem->installedPackages, headerGetInstance(h), p);
2799fd
+	} else if (!strncmp(line, "transfiletriggerpostun ", 23)) {
2799fd
+	    const char *lp = line + 23;
ef05fe
+	    unsigned int tix = runPostTransFindPkgNum(&lp);
ef05fe
+	    Header h = runPostTransFindPkg(ts, lp);
ef05fe
+	    struct rpmtd_s priorities;
ef05fe
+	    if (!h)
ef05fe
+		continue;
ef05fe
+	    headerGet(h, RPMTAG_TRANSFILETRIGGERPRIORITIES, &priorities, HEADERGET_MINMEM);
ef05fe
+	    if (rpmtdSetIndex(&priorities, tix) >= 0)
ef05fe
+		rpmtriggersAdd(ts->trigs2run, headerGetInstance(h), tix, *rpmtdGetUint32(&priorities));
ef05fe
+	    headerFree(h);
ef05fe
+	}
ef05fe
+    }
ef05fe
+
ef05fe
+    if (!(txn = rpmtxnBegin(ts, RPMTXN_WRITE)))
ef05fe
+	goto exit;
ef05fe
+
5b17a5
+    if (rpmChrootSet(rpmtsRootDir(ts)))
5b17a5
+	goto exit;
5b17a5
+
ef05fe
+    /* run posttrans scripts */
ef05fe
+    rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
ef05fe
+    runTransScripts(ts, PKG_POSTTRANS);
5b17a5
+    runTransScripts(ts, PKG_POSTUNTRANS);
ef05fe
+    /* run %transfiletriggerin scripts */
01de3b
+    runFileTriggers(ts, NULL, -1, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER, 0);
ef05fe
+    /* run %transfiletriggerpostun scrips */
ef05fe
+    runPostUnTransFileTrigs(ts);
ef05fe
+    /* Run immed %transfiletriggerin scripts */
ef05fe
+    runTransScripts(ts, PKG_TRANSFILETRIGGERIN);
ef05fe
+    rc = 0;
ef05fe
+
ef05fe
+exit:
ef05fe
+    (void) umask(oldmask);
ef05fe
+    rpmtxnEnd(txn);
5b17a5
+    sigaction(SIGPIPE, &oact, NULL);
ef05fe
+    rpmtsEmpty(ts);
ef05fe
+    return rc;
ef05fe
+}
347c6d
--- tools/rpm.c.orig	2025-02-19 15:29:33.000000000 +0000
2799fd
+++ tools/rpm.c	2025-05-19 13:58:25.956973525 +0000
e0a517
@@ -21,6 +21,7 @@ enum modes {
ef05fe
     MODE_ERASE		= (1 <<  2),
e0a517
     MODE_RESTORE	= (1 <<  4),
ef05fe
 #define	MODES_IE (MODE_INSTALL | MODE_ERASE)
e0a517
+    MODE_RUNPOSTTRANS	= (1 <<  5),
ef05fe
 
ef05fe
     MODE_UNKNOWN	= 0
ef05fe
 };
e0a517
@@ -115,6 +116,11 @@ int main(int argc, char *argv[])
ef05fe
 	int eflags = (ia->installInterfaceFlags & INSTALL_ERASE);
e0a517
 	int rflags = (ia->installInterfaceFlags & INSTALL_RESTORE);
ef05fe
 
ef05fe
+	if (ia->installInterfaceFlags & INSTALL_RUNPOSTTRANS) {
e0a517
+	    if (iflags || eflags || rflags)
ef05fe
+		argerror(_("only one major mode may be specified"));
ef05fe
+	    bigMode = MODE_RUNPOSTTRANS;
ef05fe
+	}
e0a517
 	if (iflags & eflags & rflags)
ef05fe
 	    argerror(_("only one major mode may be specified"));
ef05fe
 	else if (iflags)
e0a517
@@ -293,6 +299,14 @@ int main(int argc, char *argv[])
ef05fe
 	ec = rpmcliVerify(ts, qva, (ARGV_const_t) poptGetArgs(optCon));
ef05fe
     }	break;
ef05fe
 
ef05fe
+    case MODE_RUNPOSTTRANS:
ef05fe
+	if (!poptPeekArg(optCon)) {
ef05fe
+	    argerror(_("need posttrans manifest for --runposttrans"));
ef05fe
+	} else {
ef05fe
+	    ec += rpmRunPostTrans(ts, ia, (ARGV_const_t) poptGetArgs(optCon));
ef05fe
+	}
ef05fe
+	break;
ef05fe
+
ef05fe
     case MODE_UNKNOWN:
ef05fe
 	if (poptPeekArg(optCon) != NULL || argc <= 1) {
ef05fe
 	    printUsage(optCon, stderr, 0);