]> err.no Git - systemd/commitdiff
tmpfiles: never delete AF_UNIX sockets that are alive
authorLennart Poettering <lennart@poettering.net>
Mon, 14 Feb 2011 20:55:06 +0000 (21:55 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 14 Feb 2011 20:55:06 +0000 (21:55 +0100)
src/tmpfiles.c

index 9b697e47e8c532dd3dba466f324530dd41a0a385..01668da87e142c8a3711424e1c05e47c55080425 100644 (file)
@@ -80,6 +80,7 @@ typedef struct Item {
 } Item;
 
 static Hashmap *items = NULL, *globs = NULL;
+static Set *unix_sockets = NULL;
 
 static bool arg_create = false;
 static bool arg_clean = false;
@@ -104,6 +105,78 @@ static struct Item* find_glob(Hashmap *h, const char *match) {
         return NULL;
 }
 
+static void load_unix_sockets(void) {
+        FILE *f = NULL;
+        char line[LINE_MAX];
+
+        if (unix_sockets)
+                return;
+
+        /* We maintain a cache of the sockets we found in
+         * /proc/net/unix to speed things up a little. */
+
+        if (!(unix_sockets = set_new(string_hash_func, string_compare_func)))
+                return;
+
+        if (!(f = fopen("/proc/net/unix", "re")))
+                return;
+
+        if (!(fgets(line, sizeof(line), f)))
+                goto fail;
+
+        for (;;) {
+                char *p, *s;
+                int k;
+
+                if (!(fgets(line, sizeof(line), f)))
+                        break;
+
+                truncate_nl(line);
+
+                if (strlen(line) < 53)
+                        continue;
+
+                p = line + 53;
+                p += strspn(p, WHITESPACE);
+                p += strcspn(p, WHITESPACE);
+                p += strspn(p, WHITESPACE);
+
+                if (*p != '/')
+                        continue;
+
+                if (!(s = strdup(p)))
+                        goto fail;
+
+                if ((k = set_put(unix_sockets, s)) < 0) {
+                        free(s);
+
+                        if (k != -EEXIST)
+                                goto fail;
+                }
+        }
+
+        return;
+
+fail:
+        set_free_free(unix_sockets);
+        unix_sockets = NULL;
+
+        if (f)
+                fclose(f);
+}
+
+static bool unix_socket_alive(const char *fn) {
+        assert(fn);
+
+        load_unix_sockets();
+
+        if (unix_sockets)
+                return !!set_get(unix_sockets, (char*) fn);
+
+        /* We don't know, so assume yes */
+        return true;
+}
+
 static int dir_cleanup(
                 const char *p,
                 DIR *d,
@@ -214,7 +287,7 @@ static int dir_cleanup(
                         if (s.st_mode & S_ISVTX)
                                 continue;
 
-                        if (mountpoint) {
+                        if (mountpoint && S_ISREG(s.st_mode)) {
                                 if (streq(dent->d_name, ".journal") &&
                                     s.st_uid == 0)
                                         continue;
@@ -224,6 +297,10 @@ static int dir_cleanup(
                                         continue;
                         }
 
+                        /* Ignore sockets that are listed in /proc/net/unix */
+                        if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
+                                continue;
+
                         age = MAX3(timespec_load(&s.st_mtim),
                                    timespec_load(&s.st_atim),
                                    timespec_load(&s.st_ctim));
@@ -901,9 +978,14 @@ finish:
         while ((i = hashmap_steal_first(items)))
                 item_free(i);
 
+        while ((i = hashmap_steal_first(globs)))
+                item_free(i);
+
         hashmap_free(items);
         hashmap_free(globs);
 
+        set_free_free(unix_sockets);
+
         label_finish();
 
         return r;