chiark / gitweb /
Add initialization helper for file_handle_union
[elogind.git] / src / tmpfiles / tmpfiles.c
index 44ea51e26b61d9f2fa665742858638c9fc750740..332ddcea766c7a3b01ef4d178841c8d451c05478 100644 (file)
@@ -54,6 +54,8 @@
 #include "specifier.h"
 #include "build.h"
 #include "copy.h"
+#include "selinux-util.h"
+#include "btrfs-util.h"
 
 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
  * them in the file system. This is intended to be used to create
@@ -66,6 +68,7 @@ typedef enum ItemType {
         TRUNCATE_FILE = 'F',
         CREATE_DIRECTORY = 'd',
         TRUNCATE_DIRECTORY = 'D',
+        CREATE_SUBVOLUME = 'v',
         CREATE_FIFO = 'p',
         CREATE_SYMLINK = 'L',
         CREATE_CHAR_DEVICE = 'c',
@@ -227,10 +230,7 @@ static bool unix_socket_alive(const char *fn) {
 
 static int dir_is_mount_point(DIR *d, const char *subdir) {
 
-        union file_handle_union h = {
-                .handle.handle_bytes = MAX_HANDLE_SZ
-        };
-
+        union file_handle_union h = FILE_HANDLE_INIT;
         int mount_id_parent, mount_id;
         int r_p, r;
 
@@ -758,17 +758,27 @@ static int create_item(Item *i) {
 
                 break;
 
-        case TRUNCATE_DIRECTORY:
         case CREATE_DIRECTORY:
+        case TRUNCATE_DIRECTORY:
+        case CREATE_SUBVOLUME:
 
-                RUN_WITH_UMASK(0000) {
+                RUN_WITH_UMASK(0000)
                         mkdir_parents_label(i->path, 0755);
-                        r = mkdir_label(i->path, i->mode);
+
+                if (i->type == CREATE_SUBVOLUME) {
+                        RUN_WITH_UMASK((~i->mode) & 0777)
+                                r = btrfs_subvol_make(i->path);
+                } else
+                        r = 0;
+
+                if (i->type == CREATE_DIRECTORY || i->type == TRUNCATE_DIRECTORY || r == -ENOTTY) {
+                        RUN_WITH_UMASK(0000)
+                                r = mkdir_label(i->path, i->mode);
                 }
 
                 if (r < 0) {
                         if (r != -EEXIST)
-                                return log_error_errno(r, "Failed to create directory %s: %m", i->path);
+                                return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
 
                         if (stat(i->path, &st) < 0)
                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
@@ -970,6 +980,7 @@ static int remove_item_instance(Item *i, const char *instance) {
         case CREATE_FILE:
         case TRUNCATE_FILE:
         case CREATE_DIRECTORY:
+        case CREATE_SUBVOLUME:
         case CREATE_FIFO:
         case CREATE_SYMLINK:
         case CREATE_BLOCK_DEVICE:
@@ -1014,6 +1025,7 @@ static int remove_item(Item *i) {
         case CREATE_FILE:
         case TRUNCATE_FILE:
         case CREATE_DIRECTORY:
+        case CREATE_SUBVOLUME:
         case CREATE_FIFO:
         case CREATE_SYMLINK:
         case CREATE_CHAR_DEVICE:
@@ -1091,6 +1103,7 @@ static int clean_item(Item *i) {
 
         switch (i->type) {
         case CREATE_DIRECTORY:
+        case CREATE_SUBVOLUME:
         case TRUNCATE_DIRECTORY:
         case IGNORE_PATH:
         case COPY_FILES:
@@ -1107,7 +1120,7 @@ static int clean_item(Item *i) {
 }
 
 static int process_item(Item *i) {
-        int r, q, p;
+        int r, q, p, t = 0;
         _cleanup_free_ char *prefix = NULL;
 
         assert(i);
@@ -1125,21 +1138,23 @@ static int process_item(Item *i) {
                 Item *j;
 
                 j = hashmap_get(items, prefix);
-                if (j)
-                        process_item(j);
+                if (j) {
+                        int s;
+
+                        s = process_item(j);
+                        if (s < 0 && t == 0)
+                                t = s;
+                }
         }
 
         r = arg_create ? create_item(i) : 0;
         q = arg_remove ? remove_item(i) : 0;
         p = arg_clean ? clean_item(i) : 0;
 
-        if (r < 0)
-                return r;
-
-        if (q < 0)
-                return q;
-
-        return p;
+        return t < 0 ? t :
+                r < 0 ? r :
+                q < 0 ? q :
+                p;
 }
 
 static void item_free(Item *i) {
@@ -1289,6 +1304,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         case CREATE_FILE:
         case TRUNCATE_FILE:
         case CREATE_DIRECTORY:
+        case CREATE_SUBVOLUME:
         case TRUNCATE_DIRECTORY:
         case CREATE_FIFO:
         case IGNORE_PATH:
@@ -1429,6 +1445,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         } else
                 i->mode =
                         i->type == CREATE_DIRECTORY ||
+                        i->type == CREATE_SUBVOLUME ||
                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
 
         if (age && !streq(age, "-")) {
@@ -1636,7 +1653,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
                         continue;
 
                 HASHMAP_FOREACH(j, items, iter) {
-                        if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
+                        if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
                                 continue;
 
                         if (path_equal(j->path, i->path)) {
@@ -1717,11 +1734,17 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        HASHMAP_FOREACH(i, globs, iterator)
-                process_item(i);
+        HASHMAP_FOREACH(i, globs, iterator) {
+                k = process_item(i);
+                if (k < 0 && r == 0)
+                        r = k;
+        }
 
-        HASHMAP_FOREACH(i, items, iterator)
-                process_item(i);
+        HASHMAP_FOREACH(i, items, iterator) {
+                k = process_item(i);
+                if (k < 0 && r == 0)
+                        r = k;
+        }
 
 finish:
         while ((i = hashmap_steal_first(items)))