Suspend exclusive database lock when scriptlets get called, allowing read access in scriptlets. Only needed for DB_PRIVATE (aka global) locking. --- ./lib/backend/db3.c.orig 2019-10-02 09:56:46.416347458 +0000 +++ ./lib/backend/db3.c 2019-10-02 09:56:52.084335992 +0000 @@ -552,6 +552,46 @@ static void db3_dbSetFSync(rpmdb rdb, in static int db3_Ctrl(rpmdb rdb, dbCtrlOp ctrl) { + struct flock l; + int tries; + int fdno = -1; + dbiIndex dbi; + DB * db; + + switch (ctrl) { + case DB_CTRL_SUSPEND_DBLOCK: + case DB_CTRL_RESUME_DBLOCK: + dbi = rdb->db_pkgs; /* packages db only */ + if (!dbi) + return 1; + if (!dbi->cfg.dbi_lockdbfd || (dbi->dbi_flags & DBI_VERIFYONLY) != 0) + return 0; + if (!(dbi->dbi_rpmdb->db_mode & (O_RDWR|O_WRONLY))) + return 0; + if (_lockdbfd == 0) + return 0; + db = dbi->dbi_db; + if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) + return 1; + for (tries = 0; tries < 2; tries++) { + memset(&l, 0, sizeof(l)); + l.l_whence = 0; + l.l_start = 0; + l.l_len = 0; + l.l_type = ctrl == DB_CTRL_SUSPEND_DBLOCK ? F_RDLCK : F_WRLCK; + if (!fcntl(fdno, tries ? F_SETLKW : F_SETLK, (void *)&l)) + return 0; + if (ctrl == DB_CTRL_SUSPEND_DBLOCK) { + rpmlog(RPMLOG_WARNING, _("could not suspend database lock\n")); + return 1; + } + if (tries == 0) + rpmlog(RPMLOG_WARNING, _("waiting to reestablish exclusive database lock\n")); + } + return 1; + default: + break; + } return 0; } --- ./lib/backend/dbi.h.orig 2019-10-02 09:56:46.416347458 +0000 +++ ./lib/backend/dbi.h 2019-10-02 09:56:52.084335992 +0000 @@ -17,7 +17,9 @@ typedef enum dbCtrlOp_e { DB_CTRL_UNLOCK_RO = 2, DB_CTRL_LOCK_RW = 3, DB_CTRL_UNLOCK_RW = 4, - DB_CTRL_INDEXSYNC = 5 + DB_CTRL_INDEXSYNC = 5, + DB_CTRL_SUSPEND_DBLOCK = 100, + DB_CTRL_RESUME_DBLOCK = 101 } dbCtrlOp; typedef struct dbiIndex_s * dbiIndex; --- ./lib/rpmdb.c.orig 2019-10-02 09:56:46.416347458 +0000 +++ ./lib/rpmdb.c 2019-10-02 09:56:52.084335992 +0000 @@ -2644,6 +2644,12 @@ int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl case RPMDB_CTRL_INDEXSYNC: dbctrl = DB_CTRL_INDEXSYNC; break; + case RPMDB_CTRL_SUSPEND_DBLOCK: + dbctrl = DB_CTRL_SUSPEND_DBLOCK; + break; + case RPMDB_CTRL_RESUME_DBLOCK: + dbctrl = DB_CTRL_RESUME_DBLOCK; + break; } return dbctrl ? dbCtrl(db, dbctrl) : 1; } --- ./lib/rpmdb.h.orig 2019-06-26 14:17:31.412985694 +0000 +++ ./lib/rpmdb.h 2019-10-02 09:56:52.088335984 +0000 @@ -35,7 +35,9 @@ typedef enum rpmdbCtrlOp_e { RPMDB_CTRL_UNLOCK_RO = 2, RPMDB_CTRL_LOCK_RW = 3, RPMDB_CTRL_UNLOCK_RW = 4, - RPMDB_CTRL_INDEXSYNC = 5 + RPMDB_CTRL_INDEXSYNC = 5, + RPMDB_CTRL_SUSPEND_DBLOCK = 100, + RPMDB_CTRL_RESUME_DBLOCK = 101 } rpmdbCtrlOp; /** \ingroup rpmdb --- ./lib/transaction.c.orig 2019-10-02 09:56:52.088335984 +0000 +++ ./lib/transaction.c 2019-10-02 09:58:36.956123870 +0000 @@ -1601,6 +1601,7 @@ rpmRC runScript(rpmts ts, rpmte te, Head rpmTagVal stag = rpmScriptTag(script); FD_t sfd = NULL; int warn_only = !(rpmScriptFlags(script) & RPMSCRIPT_FLAG_CRITICAL); + rpmdb rdb = rpmtsGetRdb(ts); /* Create a temporary transaction element for triggers from rpmdb */ if (te == NULL) { @@ -1612,10 +1613,12 @@ rpmRC runScript(rpmts ts, rpmte te, Head if (sfd == NULL) sfd = rpmtsScriptFd(ts); + rpmdbCtrl(rdb, RPMDB_CTRL_SUSPEND_DBLOCK); rpmswEnter(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0); rc = rpmScriptRun(script, arg1, arg2, sfd, prefixes, rpmtsPlugins(ts)); rpmswExit(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0); + rpmdbCtrl(rdb, RPMDB_CTRL_RESUME_DBLOCK); /* Map warn-only errors to "notfound" for script stop callback */ stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;