Creating transaction locking scheme based on fcntl file locking
authorniemeyer <devnull@localhost>
Wed, 25 Feb 2004 19:54:58 +0000 (19:54 +0000)
committerniemeyer <devnull@localhost>
Wed, 25 Feb 2004 19:54:58 +0000 (19:54 +0000)
during writing operations. For now, this system will wait forever
for the lock to be released. This will ensure that current
applications will get the necessary protection without breaking
unexpectedly.
Modified Files:
lib/Makefile.am lib/rpmts.c lib/transaction.c
Added Files:
lib/rpmlock.c lib/rpmlock.h

CVS patchset: 7130
CVS date: 2004/02/25 19:54:58

lib/Makefile.am
lib/rpmlock.c [new file with mode: 0644]
lib/rpmlock.h [new file with mode: 0644]
lib/rpmts.c
lib/transaction.c

index e5bd741..317659e 100644 (file)
@@ -20,7 +20,7 @@ pkginc_HEADERS = \
        misc.h rpmcli.h rpmlib.h \
        rpmal.h rpmds.h rpmfi.h rpmps.h rpmsx.h rpmte.h rpmts.h stringbuf.h
 noinst_HEADERS = \
-       cpio.h fsm.h manifest.h psm.h rpmlead.h signature.h
+       cpio.h fsm.h manifest.h psm.h rpmlead.h signature.h rpmlock.h
 
 mylibs = librpm.la
 LIBS =
@@ -36,7 +36,7 @@ librpm_la_SOURCES = \
        rpmal.c rpmchecksig.c rpmds.c rpmfi.c rpminstall.c \
        rpmlead.c rpmlibprov.c rpmps.c rpmrc.c rpmsx.c rpmte.c rpmts.c \
        rpmvercmp.c signature.c stringbuf.c transaction.c \
-       verify.c
+       verify.c rpmlock.c
 librpm_la_LDFLAGS = -release 4.3 $(LDFLAGS) \
        $(top_builddir)/rpmdb/librpmdb.la \
        $(top_builddir)/rpmio/librpmio.la \
diff --git a/lib/rpmlock.c b/lib/rpmlock.c
new file mode 100644 (file)
index 0000000..65fcf3d
--- /dev/null
@@ -0,0 +1,135 @@
+
+#include "system.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <rpmlib.h>
+
+#include "rpmts.h"
+
+#include "rpmlock.h"
+
+/* Internal interface */
+
+#define RPMLOCK_FILE "/var/lib/rpm/transaction.lock"
+
+enum {
+       RPMLOCK_READ   = 1 << 0,
+       RPMLOCK_WRITE  = 1 << 1,
+       RPMLOCK_WAIT   = 1 << 2,
+};
+
+typedef struct {
+       int fd;
+       int openmode;
+} rpmlock;
+
+static rpmlock *rpmlock_new(const char *rootdir)
+{
+       rpmlock *lock = (rpmlock *)malloc(sizeof(rpmlock));
+       if (lock) {
+               mode_t oldmask = umask(022);
+               char *path = (char *)malloc(strlen(rootdir)+
+                                           strlen(RPMLOCK_FILE));
+               if (!path) {
+                       free(lock);
+                       return NULL;
+               }
+               sprintf(path, "%s/%s", rootdir, RPMLOCK_FILE);
+               lock->fd = open(RPMLOCK_FILE, O_RDWR|O_CREAT, 0644);
+               umask(oldmask);
+               if (lock->fd == -1) {
+                       lock->fd = open(RPMLOCK_FILE, O_RDONLY);
+                       if (lock->fd == -1) {
+                               free(lock);
+                               lock = NULL;
+                       } else {
+                               lock->openmode = RPMLOCK_READ;
+                       }
+               } else {
+                       lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
+               }
+       }
+       return lock;
+}
+
+static void rpmlock_free(rpmlock *lock)
+{
+       if (lock) {
+               close(lock->fd);
+               free(lock);
+       }
+}
+
+static int rpmlock_acquire(rpmlock *lock, int mode)
+{
+       int res = 0;
+       if (lock && (mode & lock->openmode)) {
+               struct flock info;
+               int cmd;
+               if (mode & RPMLOCK_WAIT)
+                       cmd = F_SETLKW;
+               else
+                       cmd = F_SETLK;
+               if (mode & RPMLOCK_READ)
+                       info.l_type = F_RDLCK;
+               else
+                       info.l_type = F_WRLCK;
+               info.l_whence = SEEK_SET;
+               info.l_start = 0;
+               info.l_len = 0;
+               if (fcntl(lock->fd, cmd, &info) != -1)
+                       res = 1;
+       }
+       return res;
+}
+
+static void rpmlock_release(rpmlock *lock)
+{
+       if (lock) {
+               struct flock info;
+               info.l_type = F_UNLCK;
+               info.l_whence = SEEK_SET;
+               info.l_start = 0;
+               info.l_len = 0;
+               fcntl(lock->fd, F_SETLK, &info);
+       }
+}
+
+
+/* External interface */
+
+void *rpmtsAcquireLock(rpmts ts)
+{
+       const char *rootDir = rpmtsRootDir(ts);
+       rpmlock *lock;
+       if (!rootDir)
+               rootDir = "/";
+       lock = rpmlock_new(rootDir);
+       if (!lock) {
+               rpmMessage(RPMMESS_ERROR, _("can't create transaction lock\n"));
+       } else if (!rpmlock_acquire(lock, RPMLOCK_WRITE)) {
+               if (lock->openmode & RPMLOCK_WRITE)
+                       rpmMessage(RPMMESS_WARNING,
+                                  _("waiting for transaction lock\n"));
+               if (!rpmlock_acquire(lock, RPMLOCK_WRITE|RPMLOCK_WAIT)) {
+                       rpmMessage(RPMMESS_ERROR,
+                                  _("can't create transaction lock\n"));
+                       rpmlock_free(lock);
+                       lock = NULL;
+               }
+       }
+       return lock;
+}
+
+void rpmtsFreeLock(void *lock)
+{
+       rpmlock_release((rpmlock *)lock); /* Not really needed here. */
+       rpmlock_free((rpmlock *)lock);
+}
+
+
diff --git a/lib/rpmlock.h b/lib/rpmlock.h
new file mode 100644 (file)
index 0000000..cfd84f7
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef RPMLOCK_H
+#define RPMLOCK_H 
+
+void *rpmtsAcquireLock(rpmts ts);
+void rpmtsFreeLock(void *lock);
+
+#endif
index 1b54ac7..dc2bb8d 100644 (file)
@@ -13,6 +13,7 @@
 #include "rpmal.h"
 #include "rpmds.h"
 #include "rpmfi.h"
+#include "rpmlock.h"
 
 #define        _RPMTE_INTERNAL         /* XXX te->h */
 #include "rpmte.h"
@@ -168,16 +169,24 @@ int rpmtsOpenDB(rpmts ts, int dbmode)
 
 int rpmtsInitDB(rpmts ts, int dbmode)
 {
-    return rpmdbInit(ts->rootDir, dbmode);
+    void *lock = rpmtsAcquireLock(ts);
+    int rc = -1;
+    if (lock)
+           rc = rpmdbInit(ts->rootDir, dbmode);
+    rpmtsFreeLock(lock);
+    return rc;
 }
 
 int rpmtsRebuildDB(rpmts ts)
 {
     int rc;
+    void *lock = rpmtsAcquireLock(ts);
+    if (!lock) return -1;
     if (!(ts->vsflags & RPMVSF_NOHDRCHK))
        rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
     else
        rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
+    rpmtsFreeLock(lock);
     return rc;
 }
 
index 4fdeab5..4bf8486 100644 (file)
@@ -14,6 +14,8 @@
 
 #include "rpmds.h"
 
+#include "rpmlock.h"
+
 #define        _RPMFI_INTERNAL
 #include "rpmfi.h"
 
@@ -957,6 +959,10 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
     if (rpmtsNElements(ts) <= 0)
        return -1;
 
+    void *lock = rpmtsAcquireLock(ts);
+    if (!lock)
+       return -1;
+
     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
        (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
@@ -973,8 +979,10 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
                ? O_RDONLY : (O_RDWR|O_CREAT);
 
        /* Open database RDWR for installing packages. */
-       if (rpmtsOpenDB(ts, dbmode))
+       if (rpmtsOpenDB(ts, dbmode)) {
+           rpmtsFreeLock(lock);
            return -1;  /* XXX W2DO? */
+       }
     }
 
     ts->ignoreSet = ignoreSet;
@@ -1194,6 +1202,7 @@ rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
        matches = xcalloc(fc, sizeof(*matches));
        if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
            ps = rpmpsFree(ps);
+           rpmtsFreeLock(lock);
            return 1;   /* XXX WTFO? */
        }
 
@@ -1331,6 +1340,7 @@ rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
                (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
        )
     {
+       rpmtsFreeLock(lock);
        return ts->orderCount;
     }
 
@@ -1546,6 +1556,8 @@ assert(psm != NULL);
     /*@=branchstate@*/
     pi = rpmtsiFree(pi);
 
+    rpmtsFreeLock(lock);
+
     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
     if (ourrc)
        return -1;