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 2017-01-19 15:31:32.166569447 +0000 +++ ./lib/backend/db3.c 2017-01-19 15:32:29.239335811 +0000 @@ -541,6 +541,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 2017-01-19 15:31:32.166569447 +0000 +++ ./lib/backend/dbi.h 2017-01-19 15:31:34.816559478 +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 2017-01-19 15:31:32.162569461 +0000 +++ ./lib/rpmdb.c 2017-01-19 15:31:34.817559474 +0000 @@ -2706,6 +2706,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 2016-10-03 08:08:36.582686286 +0000 +++ ./lib/rpmdb.h 2017-01-19 15:31:34.818559471 +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 2016-10-21 09:44:00.309962086 +0000 +++ ./lib/transaction.c 2017-01-19 15:31:34.818559471 +0000 @@ -1425,15 +1425,18 @@ rpmRC runScript(rpmts ts, rpmte te, ARGV stag != RPMTAG_PREUN && stag != RPMTAG_PRETRANS && stag != RPMTAG_VERIFYSCRIPT); + rpmdb rdb = rpmtsGetRdb(ts); sfd = rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_START, stag, 0); 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, warn_only, 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;