+/* Lock a file to protect the DB. Return TRUE for success */
+
+static inline BOOL
+lockfile_take(open_db * dbblock, const uschar * filename, BOOL rdonly, BOOL panic)
+{
+flock_t lock_data;
+int rc;
+
+priv_drop_temp(exim_uid, exim_gid);
+if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
+ {
+ (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, panic);
+ dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
+ }
+priv_restore();
+
+if (dbblock->lockfd < 0)
+ {
+ log_write(0, LOG_MAIN, "%s",
+ string_open_failed("database lock file %s", filename));
+ errno = 0; /* Indicates locking failure */
+ return FALSE;
+ }
+
+/* Now we must get a lock on the opened lock file; do this with a blocking
+lock that times out. */
+
+lock_data.l_type = rdonly ? F_RDLCK : F_WRLCK;
+lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0;
+
+DEBUG(D_hints_lookup|D_retry|D_route|D_deliver)
+ debug_printf_indent("locking %s\n", filename);
+
+sigalrm_seen = FALSE;
+ALARM(EXIMDB_LOCK_TIMEOUT);
+rc = fcntl(dbblock->lockfd, F_SETLKW, &lock_data);
+ALARM_CLR(0);
+
+if (sigalrm_seen) errno = ETIMEDOUT;
+if (rc < 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Failed to get %s lock for %s: %s",
+ rdonly ? "read" : "write", filename,
+ errno == ETIMEDOUT ? "timed out" : strerror(errno));
+ (void)close(dbblock->lockfd);
+ errno = 0; /* Indicates locking failure */
+ return FALSE;
+ }
+
+DEBUG(D_hints_lookup) debug_printf_indent("locked %s\n", filename);
+return TRUE;
+}
+