]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/portable/portable.c
Merge pull request #10920 from yuwata/hashmap-destructor
[thirdparty/systemd.git] / src / portable / portable.c
index aaabe9fb363f9092caedf3e4fa2b5d8dec5602ac..5b62486ea9eb023409c11c0219ea717f1a2ddefe 100644 (file)
@@ -26,6 +26,7 @@
 #include "socket-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
 
 static const char profile_dirs[] = CONF_PATHS_NULSTR("systemd/portable/profile");
@@ -92,21 +93,6 @@ PortableMetadata *portable_metadata_unref(PortableMetadata *i) {
         return mfree(i);
 }
 
-Hashmap *portable_metadata_hashmap_unref(Hashmap *h) {
-
-        for (;;) {
-                PortableMetadata *i;
-
-                i = hashmap_steal_first(h);
-                if (!i)
-                        break;
-
-                portable_metadata_unref(i);
-        }
-
-        return hashmap_free(h);
-}
-
 static int compare_metadata(PortableMetadata *const *x, PortableMetadata *const *y) {
         return strcmp((*x)->name, (*y)->name);
 }
@@ -201,7 +187,7 @@ static int recv_item(
         assert(ret_name);
         assert(ret_fd);
 
-        n = recvmsg(socket_fd, &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+        n = recvmsg(socket_fd, &mh, MSG_CMSG_CLOEXEC);
         if (n < 0)
                 return -errno;
 
@@ -232,6 +218,9 @@ static int recv_item(
         return 0;
 }
 
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char, string_hash_func, string_compare_func,
+                                              PortableMetadata, portable_metadata_unref);
+
 static int extract_now(
                 const char *where,
                 char **matches,
@@ -239,7 +228,7 @@ static int extract_now(
                 PortableMetadata **ret_os_release,
                 Hashmap **ret_unit_files) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_close_ int os_release_fd = -1;
@@ -286,7 +275,7 @@ static int extract_now(
         if (r < 0)
                 return log_debug_errno(r, "Failed to acquire lookup paths: %m");
 
-        unit_files = hashmap_new(&string_hash_ops);
+        unit_files = hashmap_new(&portable_metadata_hash_ops);
         if (!unit_files)
                 return -ENOMEM;
 
@@ -362,7 +351,7 @@ static int portable_extract_by_path(
                 Hashmap **ret_unit_files,
                 sd_bus_error *error) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata* os_release = NULL;
         _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
         int r;
@@ -432,7 +421,7 @@ static int portable_extract_by_path(
 
                 seq[1] = safe_close(seq[1]);
 
-                unit_files = hashmap_new(&string_hash_ops);
+                unit_files = hashmap_new(&portable_metadata_hash_ops);
                 if (!unit_files)
                         return -ENOMEM;
 
@@ -630,14 +619,14 @@ static int portable_changes_add(
         if (!p)
                 return -ENOMEM;
 
-        path_kill_slashes(p);
+        path_simplify(p, false);
 
         if (source) {
                 s = strdup(source);
                 if (!s)
                         return -ENOMEM;
 
-                path_kill_slashes(s);
+                path_simplify(s, false);
         }
 
         c[(*n_changes)++] = (PortableChange) {
@@ -782,7 +771,7 @@ static int install_profile_dropin(
 
         r = find_profile(profile, m->name, &from);
         if (r < 0) {
-                if (r != ENOENT)
+                if (r != -ENOENT)
                         return log_debug_errno(errno, "Profile '%s' is not accessible: %m", profile);
 
                 log_debug_errno(errno, "Skipping link to profile '%s', as it does not exist: %m", profile);
@@ -815,15 +804,15 @@ static int install_profile_dropin(
         return 0;
 }
 
-static const char *config_path(const LookupPaths *paths, PortableFlags flags) {
+static const char *attached_path(const LookupPaths *paths, PortableFlags flags) {
         const char *where;
 
         assert(paths);
 
         if (flags & PORTABLE_RUNTIME)
-                where = paths->runtime_config;
+                where = paths->runtime_attached;
         else
-                where = paths->persistent_config;
+                where = paths->persistent_attached;
 
         assert(where);
         return where;
@@ -849,15 +838,25 @@ static int attach_unit_file(
         assert(m);
         assert(PORTABLE_METADATA_IS_UNIT(m));
 
-        where = config_path(paths, flags);
-        path = strjoina(where, "/", m->name);
+        where = attached_path(paths, flags);
 
+        (void) mkdir_parents(where, 0755);
+        if (mkdir(where, 0755) < 0) {
+                if (errno != EEXIST)
+                        return -errno;
+        } else
+                (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, where, NULL);
+
+        path = strjoina(where, "/", m->name);
         dropin_dir = strjoin(path, ".d");
         if (!dropin_dir)
                 return -ENOMEM;
 
-        (void) mkdir_p(dropin_dir, 0755);
-        (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, dropin_dir, NULL);
+        if (mkdir(dropin_dir, 0755) < 0) {
+                if (errno != EEXIST)
+                        return -errno;
+        } else
+                (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, dropin_dir, NULL);
 
         /* We install the drop-ins first, and the actual unit file last to achieve somewhat atomic behaviour if PID 1
          * is reloaded while we are creating things here: as long as only the drop-ins exist the unit doesn't exist at
@@ -976,7 +975,7 @@ int portable_attach(
                 size_t *n_changes,
                 sd_bus_error *error) {
 
-        _cleanup_(portable_metadata_hashmap_unrefp) Hashmap *unit_files = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(image_unrefp) Image *image = NULL;
         PortableMetadata *item;
@@ -1147,11 +1146,15 @@ int portable_detach(
         if (r < 0)
                 return r;
 
-        where = config_path(&paths, flags);
+        where = attached_path(&paths, flags);
 
         d = opendir(where);
-        if (!d)
+        if (!d) {
+                if (errno == ENOENT)
+                        goto not_found;
+
                 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
+        }
 
         unit_files = set_new(&string_hash_ops);
         if (!unit_files)
@@ -1213,10 +1216,8 @@ int portable_detach(
                 }
         }
 
-        if (set_isempty(unit_files)) {
-                log_debug("No unit files associated with '%s' found. Image not attached?", name_or_path);
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "No unit files associated with '%s' found. Image not attached?", name_or_path);
-        }
+        if (set_isempty(unit_files))
+                goto not_found;
 
         SET_FOREACH(item, unit_files, iterator) {
                 _cleanup_free_ char *md = NULL;
@@ -1289,7 +1290,15 @@ int portable_detach(
                         portable_changes_add(changes, n_changes, PORTABLE_UNLINK, sl, NULL);
         }
 
+        /* Try to remove the unit file directory, if we can */
+        if (rmdir(where) >= 0)
+                portable_changes_add(changes, n_changes, PORTABLE_UNLINK, where, NULL);
+
         return ret;
+
+not_found:
+        log_debug("No unit files associated with '%s' found. Image not attached?", name_or_path);
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "No unit files associated with '%s' found. Image not attached?", name_or_path);
 }
 
 static int portable_get_state_internal(
@@ -1314,11 +1323,18 @@ static int portable_get_state_internal(
         if (r < 0)
                 return r;
 
-        where = config_path(&paths, flags);
+        where = attached_path(&paths, flags);
 
         d = opendir(where);
-        if (!d)
+        if (!d) {
+                if (errno == ENOENT) {
+                        /* If the 'attached' directory doesn't exist at all, then we know for sure this image isn't attached. */
+                        *ret = PORTABLE_DETACHED;
+                        return 0;
+                }
+
                 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
+        }
 
         unit_files = set_new(&string_hash_ops);
         if (!unit_files)