+}
+
+/* Check if the slot has expired */
+static int is_expired(struct cache_slot *slot)
+{
+ if (slot->ttl < 0)
+ return 0;
+ else
+ return slot->cache_st.st_mtime + slot->ttl*60 < time(NULL);
+}
+
+/* Check if the slot has been modified since we opened it.
+ * NB: If stat() fails, we pretend the file is modified.
+ */
+static int is_modified(struct cache_slot *slot)
+{
+ struct stat st;
+
+ if (stat(slot->cache_name, &st))
+ return 1;
+ return (st.st_ino != slot->cache_st.st_ino ||
+ st.st_mtime != slot->cache_st.st_mtime ||
+ st.st_size != slot->cache_st.st_size);
+}
+
+/* Close an open lockfile */
+static int close_lock(struct cache_slot *slot)
+{
+ int err = 0;
+ if (slot->lock_fd > 0) {
+ if (close(slot->lock_fd))
+ err = errno;
+ else
+ slot->lock_fd = -1;
+ }
+ return err;
+}
+
+/* Create a lockfile used to store the generated content for a cache
+ * slot, and write the slot key + \0 into it.
+ * Returns 0 on success and errno otherwise.
+ */
+static int lock_slot(struct cache_slot *slot)
+{
+ slot->lock_fd = open(slot->lock_name, O_RDWR|O_CREAT|O_EXCL,
+ S_IRUSR|S_IWUSR);
+ if (slot->lock_fd == -1)
+ return errno;
+ if (write(slot->lock_fd, slot->key, slot->keylen + 1) < 0)
+ return errno;
+ return 0;
+}
+
+/* Release the current lockfile. If `replace_old_slot` is set the
+ * lockfile replaces the old cache slot, otherwise the lockfile is
+ * just deleted.
+ */
+static int unlock_slot(struct cache_slot *slot, int replace_old_slot)
+{
+ int err;
+
+ if (replace_old_slot)
+ err = rename(slot->lock_name, slot->cache_name);
+ else
+ err = unlink(slot->lock_name);
+
+ if (err)
+ return errno;
+
+ return 0;
+}
+
+/* Generate the content for the current cache slot by redirecting
+ * stdout to the lock-fd and invoking the callback function
+ */
+static int fill_slot(struct cache_slot *slot)
+{
+ int tmp;
+
+ /* Preserve stdout */
+ tmp = dup(STDOUT_FILENO);
+ if (tmp == -1)
+ return errno;
+
+ /* Redirect stdout to lockfile */
+ if (dup2(slot->lock_fd, STDOUT_FILENO) == -1)
+ return errno;
+
+ /* Generate cache content */
+ slot->fn(slot->cbdata);
+
+ /* Restore stdout */
+ if (dup2(tmp, STDOUT_FILENO) == -1)
+ return errno;
+
+ /* Close the temporary filedescriptor */
+ if (close(tmp))
+ return errno;
+
+ return 0;
+}
+
+/* Crude implementation of 32-bit FNV-1 hash algorithm,
+ * see http://www.isthe.com/chongo/tech/comp/fnv/ for details
+ * about the magic numbers.
+ */
+#define FNV_OFFSET 0x811c9dc5
+#define FNV_PRIME 0x01000193
+
+unsigned long hash_str(const char *str)
+{
+ unsigned long h = FNV_OFFSET;
+ unsigned char *s = (unsigned char *)str;
+
+ if (!s)
+ return h;
+
+ while(*s) {
+ h *= FNV_PRIME;
+ h ^= *s++;