3a3ae67b51
As flock-style locks have no way to check whether another lock on the file is held by the current process and is safe for libdb to access the its environment (in read-mode only), a helper function that parses /proc/locks for this information has been added. Additionally, db-5.3.28-rpm-lock-check.patch has been modified to use the helper function in order for libdb to not have to leak file descriptors while checking for rpm's transaction lock when accessing rpm's environment.
112 lines
3.4 KiB
Diff
112 lines
3.4 KiB
Diff
diff -up db-5.3.28/src/env/env_region.c.pthreads db-5.3.28/src/env/env_region.c
|
|
--- db-5.3.28/src/env/env_region.c.pthreads 2017-06-19 08:48:19.362325045 +0200
|
|
+++ db-5.3.28/src/env/env_region.c 2017-06-19 08:49:38.910773653 +0200
|
|
@@ -305,15 +305,7 @@ user_map_functions:
|
|
goto creation;
|
|
}
|
|
|
|
- /* We have an old environment but cannot rebuild it safely. */
|
|
- if (ret == DB_OLD_VERSION) {
|
|
- __db_errx(env, DB_STR("1539",
|
|
- "Build signature doesn't match environment"));
|
|
- ret = DB_VERSION_MISMATCH;
|
|
- goto err;
|
|
- }
|
|
-
|
|
if (renv->majver != DB_VERSION_MAJOR ||
|
|
renv->minver != DB_VERSION_MINOR) {
|
|
/*
|
|
* Special case a region that's all nul bytes, just treat it
|
|
@@ -337,6 +329,20 @@ user_map_functions:
|
|
goto err;
|
|
}
|
|
|
|
+ /*
|
|
+ * We have an old environment but cannot rebuild it safely.
|
|
+ * The environment might still be readable by the current process
|
|
+ * (only the libpthread timestamp changed) if this process is the one
|
|
+ * that is holding the lock on the region file as we can be sure
|
|
+ * the environment did not get rebuilt under our feet.
|
|
+ */
|
|
+ if (ret == DB_OLD_VERSION && __check_lock_fn(env->lockfhp->name, getpid()) ) {
|
|
+ __db_errx(env, DB_STR("1539",
|
|
+ "Build signature doesn't match environment"));
|
|
+ ret = DB_VERSION_MISMATCH;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
/*
|
|
* Check if the environment has had a catastrophic failure.
|
|
*
|
|
diff -up db-5.3.28/src/os/os_flock.c.pthreads db-5.3.28/src/os/os_flock.c
|
|
--- db-5.3.28/src/os/os_flock.c.pthreads 2017-06-19 08:48:19.362325045 +0200
|
|
+++ db-5.3.28/src/os/os_flock.c 2017-06-19 08:48:19.364325006 +0200
|
|
@@ -15,6 +15,67 @@ static int __os_filelocking_notsup __P((
|
|
#endif
|
|
|
|
/*
|
|
+ * __check_lock_fn --
|
|
+ * Parse /proc/locks to see if the file described by 'fn' is locked.
|
|
+ * Additionally (if 'pid' is not 0) check if the process holding
|
|
+ * the lock has the same pid value as 'pid'.
|
|
+ *
|
|
+ * Returns 0 if a lock on fn is found, 1 if it is not found and -1 on error.
|
|
+ */
|
|
+
|
|
+int __check_lock_fn(fn, pid)
|
|
+ char *fn;
|
|
+ pid_t pid;
|
|
+{
|
|
+ FILE* fp;
|
|
+ char buffer[PATH_MAX];
|
|
+ char *token;
|
|
+ int i, fd, inode;
|
|
+ struct stat st;
|
|
+ pid_t lpid = 0;
|
|
+
|
|
+ if (!fn)
|
|
+ return -1;
|
|
+
|
|
+ fp = fopen("/proc/locks", "r");
|
|
+ if (!fp)
|
|
+ return -1;
|
|
+
|
|
+ /* Get the file's inode */
|
|
+ if (stat(fn, &st))
|
|
+ return -1;
|
|
+
|
|
+ while (fgets(buffer, sizeof(buffer), fp))
|
|
+ for (token = strtok(buffer, " "), i = 0; token; token = strtok(NULL, " "), i++) {
|
|
+ /* Do not parse any other fields */
|
|
+ if (i > 5)
|
|
+ break;
|
|
+ /* Save the PID */
|
|
+ if (i == 4)
|
|
+ lpid = atoi(token);
|
|
+ /* Check the inode */
|
|
+ else if (i == 5) {
|
|
+ inode = 0;
|
|
+ sscanf(token, "%*02x:%*02x:%d", &inode);
|
|
+ /* Not the inode we are looking for */
|
|
+ if (inode != st.st_ino)
|
|
+ continue;
|
|
+ /*
|
|
+ * We have the correct file.
|
|
+ * We are either looking for a specific process or we do not care at all.
|
|
+ */
|
|
+ if (!pid || lpid == pid) {
|
|
+ fclose(fp);
|
|
+ return 0;
|
|
+ }
|
|
+ /* Not the lock we are looking for */
|
|
+ }
|
|
+ }
|
|
+ fclose(fp);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
* __os_fdlock --
|
|
* Acquire/release a lock on a byte in a file.
|
|
*
|