diff --git a/src/tools.c b/src/tools.c
index 1287d0b634529ff7226c5af5580cc0f9442e3605..2f1969d91d830d29d1de55160334fcb66104b1b7 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -24,12 +24,16 @@
 
 /* Some standard headers. */
 #include <ctype.h>
+#include <errno.h>
 #include <math.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/resource.h>
+#include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 /* This object's header. */
 #include "tools.h"
@@ -1058,3 +1062,48 @@ char *trim_both(char *s) {
   if (s == NULL || strlen(s) < 2) return s;
   return trim_trailing(trim_leading(s));
 }
+
+/**
+ * @brief safe check directory existence and creation.
+ *
+ * Doesn't try to re-create an existing directory and makes sure that it can
+ * have files created in it. If the directory doesn't exist and we want to
+ * create it then we try to do that with an appropriate mask that should
+ * honour the users umask. If the directory is something odd like a broken
+ * link then that is dereferenced so should also result in an error, since
+ * it doesn't exist and cannot be created. Finally we check that an existing
+ * file with this name is indeed a directory.
+ *
+ * @param dir the directory we need to exist.
+ * @param create create if not already exists, otherwise non-existence is an
+ *               error.
+ */
+void safe_checkdir(const char *dir, int create) {
+
+  if (access(dir, W_OK | X_OK) != 0) {
+
+    /* A file with this name and the minimally correct permissions does not
+     * exist. */
+    if (create) {
+      if (mkdir(dir, 0777) != 0)
+        error("Failed to create directory %s (%s)", dir, strerror(errno));
+    } else {
+      error("directory %s does not exist or cannot be used (%s)", dir,
+            strerror(errno));
+    }
+  } else {
+
+    /* Exists and has the minimally correct permissions, is this a
+     * directory? */
+    struct stat sb;
+    if (stat(dir, &sb) != 0) {
+      /* Weird error, can stat all existing files. */
+      error("Failed to stat directory %s (%s)", dir, strerror(errno));
+    } else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+      error("%s is not a directory, cannot use or create.", dir);
+    }
+  }
+
+  /* Success. */
+  return;
+}
diff --git a/src/tools.h b/src/tools.h
index a34904bcbb7af1ce15408a376f957f0f72cd327c..8f7a65b7aa9acd60fe3dc6d37fe2b1589e61b133 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -64,4 +64,6 @@ char *trim_leading(char *s);
 char *trim_trailing(char *s);
 char *trim_both(char *s);
 
+void safe_checkdir(const char *dir, int create);
+
 #endif /* SWIFT_TOOL_H */