Sophie

Sophie

distrib > Mandriva > 2008.0 > x86_64 > by-pkgid > a35732d620cfac4812adc8d6b2992f07 > files > 41

rpm-4.4.8-22.1mdv2008.0.src.rpm

--- rpm-4.4.8/rpmdb/rpmdb.c.lock	2007-01-21 16:30:14.000000000 +0100
+++ rpm-4.4.8/rpmdb/rpmdb.c	2007-09-27 10:37:52.000000000 +0200
@@ -972,6 +972,18 @@ int rpmdbClose(rpmdb db)
     	db->_dbi[dbix] = NULL;
 	/*@=unqualifiedtrans@*/
     }
+
+    /* unlock database */
+    if (db->db_perms >> 16) {
+      int ld = (db->db_perms >> 16) - 1;
+      char *env = getenv("RPMLOCK_NOWAIT");
+      rpmMessage(RPMMESS_DEBUG, "unlocking %s%s/RPMLOCK\n", db->db_root, db->db_home);
+      close(ld);
+      /* below is not fully correct when manipulating more than one DB in the same prog,
+	 but it still catches most issues... */
+      if (env && strcmp(env, "_set_by_rpm_") == 0) unsetenv("RPMLOCK_NOWAIT");
+    }
+
     db->db_errpfx = _free(db->db_errpfx);
     db->db_root = _free(db->db_root);
     db->db_home = _free(db->db_home);
@@ -1116,10 +1128,7 @@ fprintf(stderr, "==> %s(%s, %s, 0x%x, 0%
 
     if (!(db->db_home && db->db_home[0])) {
 	rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
-	db->db_root = _free(db->db_root);
-	db->db_home = _free(db->db_home);
-	db = _free(db);
-	/*@-globstate@*/ return NULL; /*@=globstate@*/
+	goto fail;
     }
 
     /* XXX if default "/var/lib/rpm" path, manage %{_hrmib_path} entries too. */
@@ -1143,9 +1152,52 @@ fprintf(stderr, "==> %s(%s, %s, 0x%x, 0%
     dbiTagsInit(&db->db_tagn, &db->db_ndbi);
     db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
     db->nrefs = 0;
+
+    { /* create the db_home (even in O_RDONLY mode) */
+      const char *dbhome = rpmGenPath(db->db_root, db->db_home, NULL);
+      (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
+      _free(dbhome);
+    }
+    {
+      /* lock database using exclusive lock on write, and shared lock on read */
+      const char *lockfilename = rpmGenPath(db->db_root, db->db_home, "RPMLOCK");
+      /* compute lockfilename and open it according to mode used */
+      int ld = open(lockfilename, O_WRONLY | O_CREAT, 0644);
+      /* don't care if we can't write to the db (eg: running as non-superuser and doing a simple query) */
+      if (ld >= 0) {
+	int ok = 1;
+	int lockmode = mode == O_RDONLY ? LOCK_SH : LOCK_EX;
+	rpmMessage(RPMMESS_DEBUG, "locking file %s in %s mode\n", lockfilename, (mode == O_RDONLY ? "shared" : "exclusive"));
+	if (flock(ld, lockmode | LOCK_NB) != 0) {
+	  if (getenv("RPMLOCK_NOWAIT") == NULL) {
+	    rpmMessage(RPMMESS_WARNING,
+		       _("waiting for transaction lock on %s\n"), lockfilename);
+	    if (flock(ld, lockmode) != 0) ok = 0;
+	  } else ok = 0;
+	}
+	if (ok) {
+	  /* HACK to keep ld without breaking compabilities (changing db size) */
+	  db->db_perms |= (ld + 1) << 16;
+	  setenv("RPMLOCK_NOWAIT", "_set_by_rpm_", 0);
+	} else {
+	  close(ld);
+	  rpmError( RPMERR_DBOPEN,
+		    _("cannot open lock file %s in %s mode\n"), lockfilename, (mode == O_RDONLY ? "shared" : "exclusive"));
+	  _free(lockfilename);
+	  goto fail;
+	}
+      }
+      _free(lockfilename);
+    }
     /*@-globstate@*/
     return rpmdbLink(db, "rpmdbCreate");
     /*@=globstate@*/
+
+ fail:
+    db->db_root = _free(db->db_root);
+    db->db_home = _free(db->db_home);
+    db = _free(db);
+    /*@-globstate@*/ return NULL; /*@=globstate@*/    
 }
 /*@=mods@*/
 /*@=exportheader@*/
@@ -3665,6 +3717,11 @@ static int rpmdbRemoveDatabase(const cha
 	break;
     }
 
+    sprintf(filename, "%s/%s/RPMLOCK", prefix, dbpath);
+    (void)rpmCleanPath(filename);
+    rpmMessage(RPMMESS_DEBUG, "removing %s\n", filename);
+    xx = unlink(filename);
+
     sprintf(filename, "%s/%s", prefix, dbpath);
     (void)rpmCleanPath(filename);
     xx = rmdir(filename);
@@ -3775,6 +3832,12 @@ static int rpmdbMoveDatabase(const char 
     case 0:
 	break;
     }
+
+    sprintf(ofilename, "%s/%s/RPMLOCK", prefix, olddbpath);
+    (void)rpmCleanPath(ofilename);
+    rpmMessage(RPMMESS_DEBUG, "removing %s\n", ofilename);
+    xx = unlink(ofilename);
+
 #ifdef	SQLITE_HACK_XXX
     if (rc || _olddbapi == _newdbapi)
 	return rc;