[systemd-commits] 6 commits - Makefile.am TODO src/import src/machine src/shared units/systemd-machined.service.in

Lennart Poettering lennart at kemper.freedesktop.org
Fri Dec 19 10:22:59 PST 2014


 Makefile.am                               |    4 
 TODO                                      |    4 
 src/import/import.c                       |    4 
 src/machine/image.c                       |  239 +++++++++++++++++++++
 src/machine/image.h                       |   57 +++++
 src/machine/machine-dbus.c                |   23 ++
 src/machine/machinectl.c                  |  340 +++++++++++++++++-------------
 src/machine/machined-dbus.c               |   53 ++++
 src/machine/org.freedesktop.machine1.conf |    4 
 src/shared/btrfs-util.c                   |   21 +
 src/shared/btrfs-util.h                   |    1 
 src/shared/util.c                         |   18 -
 src/shared/util.h                         |    9 
 src/shared/verbs.c                        |   23 +-
 units/systemd-machined.service.in         |    2 
 15 files changed, 632 insertions(+), 170 deletions(-)

New commits:
commit 358ba19e5e18304258f053e30e6120a3b6adf322
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 19:19:20 2014 +0100

    update TODO

diff --git a/TODO b/TODO
index c49d179..c58f503 100644
--- a/TODO
+++ b/TODO
@@ -49,6 +49,10 @@ Features:
 
 * "machinectl diff"
 
+* "machinectl status" should show 10 most recent log lines of both the host logs of the unit of the machine, plus the logs generated in the machine
+
+* add transparent btrfs pool in a loopback file in /var if btrfs operations (such as systemd-import pull-dck) are used and /var is not a btrfs file system
+
 * machined: open up certain commands to unprivileged clients via polkit
 
 * hostnamectl: show root image uuid

commit 56159e0d918e9a9be07988133bb2847779325de0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 19:19:05 2014 +0100

    machinectl: port machinectl to new verbs logic

diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index d2d3d16..cde0c6a 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -50,6 +50,7 @@
 #include "path-util.h"
 #include "mkdir.h"
 #include "copy.h"
+#include "verbs.h"
 
 static char **arg_property = NULL;
 static bool arg_all = false;
@@ -72,13 +73,17 @@ static void pager_open_if_enabled(void) {
         pager_open(false);
 }
 
-static int list_machines(sd_bus *bus, char **args, unsigned n) {
+static int list_machines(int argc, char *argv[], void *userdata) {
+
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         const char *name, *class, *service, *object;
+        sd_bus *bus = userdata;
         unsigned k = 0;
         int r;
 
+        assert(bus);
+
         pager_open_if_enabled();
 
         r = sd_bus_call_method(
@@ -132,7 +137,7 @@ static int compare_image_info(const void *a, const void *b) {
         return strcmp(x->name, y->name);
 }
 
-static int list_images(sd_bus *bus, char **args, unsigned n) {
+static int list_images(int argc, char *argv[], void *userdata) {
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         size_t max_name = strlen("NAME"), max_type = strlen("TYPE");
@@ -140,9 +145,12 @@ static int list_images(sd_bus *bus, char **args, unsigned n) {
         _cleanup_free_ ImageInfo *images = NULL;
         size_t n_images = 0, n_allocated = 0, j;
         const char *name, *type, *object;
+        sd_bus *bus = userdata;
         int read_only;
         int r;
 
+        assert(bus);
+
         pager_open_if_enabled();
 
         r = sd_bus_call_method(
@@ -389,6 +397,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
         char since2[FORMAT_TIMESTAMP_MAX], *s2;
         int ifi = -1;
 
+        assert(bus);
         assert(i);
 
         fputs(strna(i->name), stdout);
@@ -505,6 +514,8 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
         MachineStatusInfo info = {};
         int r;
 
+        assert(verb);
+        assert(bus);
         assert(path);
         assert(new_line);
 
@@ -535,6 +546,10 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
         int r;
 
+        assert(bus);
+        assert(path);
+        assert(new_line);
+
         if (*new_line)
                 printf("\n");
 
@@ -547,21 +562,21 @@ static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
         return r;
 }
 
-static int show(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+static int show(int argc, char *argv[], void *userdata) {
+
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r = 0;
-        unsigned i;
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         bool properties, new_line = false;
+        sd_bus *bus = userdata;
+        int r = 0, i;
 
         assert(bus);
-        assert(args);
 
-        properties = !strstr(args[0], "status");
+        properties = !strstr(argv[0], "status");
 
         pager_open_if_enabled();
 
-        if (properties && n <= 1) {
+        if (properties && argc <= 1) {
 
                 /* If no argument is specified, inspect the manager
                  * itself */
@@ -570,7 +585,7 @@ static int show(sd_bus *bus, char **args, unsigned n) {
                         return r;
         }
 
-        for (i = 1; i < n; i++) {
+        for (i = 1; i < argc; i++) {
                 const char *path = NULL;
 
                 r = sd_bus_call_method(
@@ -581,7 +596,7 @@ static int show(sd_bus *bus, char **args, unsigned n) {
                                         "GetMachine",
                                         &error,
                                         &reply,
-                                        "s", args[i]);
+                                        "s", argv[i]);
                 if (r < 0) {
                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
                         return r;
@@ -594,33 +609,34 @@ static int show(sd_bus *bus, char **args, unsigned n) {
                 if (properties)
                         r = show_properties(bus, path, &new_line);
                 else
-                        r = show_info(args[0], bus, path, &new_line);
+                        r = show_info(argv[0], bus, path, &new_line);
         }
 
         return r;
 }
 
-static int kill_machine(sd_bus *bus, char **args, unsigned n) {
+static int kill_machine(int argc, char *argv[], void *userdata) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned i;
+        sd_bus *bus = userdata;
+        int i;
 
-        assert(args);
+        assert(bus);
 
         if (!arg_kill_who)
                 arg_kill_who = "all";
 
-        for (i = 1; i < n; i++) {
+        for (i = 1; i < argc; i++) {
                 int r;
 
                 r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.machine1",
-                                        "/org/freedesktop/machine1",
-                                        "org.freedesktop.machine1.Manager",
-                                        "KillMachine",
-                                        &error,
-                                        NULL,
-                                        "ssi", args[i], arg_kill_who, arg_signal);
+                                bus,
+                                "org.freedesktop.machine1",
+                                "/org/freedesktop/machine1",
+                                "org.freedesktop.machine1.Manager",
+                                "KillMachine",
+                                &error,
+                                NULL,
+                                "ssi", argv[i], arg_kill_who, arg_signal);
                 if (r < 0) {
                         log_error("Could not kill machine: %s", bus_error_message(&error, -r));
                         return r;
@@ -630,27 +646,28 @@ static int kill_machine(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int reboot_machine(sd_bus *bus, char **args, unsigned n) {
+static int reboot_machine(int argc, char *argv[], void *userdata) {
         arg_kill_who = "leader";
         arg_signal = SIGINT; /* sysvinit + systemd */
 
-        return kill_machine(bus, args, n);
+        return kill_machine(argc, argv, userdata);
 }
 
-static int poweroff_machine(sd_bus *bus, char **args, unsigned n) {
+static int poweroff_machine(int argc, char *argv[], void *userdata) {
         arg_kill_who = "leader";
         arg_signal = SIGRTMIN+4; /* only systemd */
 
-        return kill_machine(bus, args, n);
+        return kill_machine(argc, argv, userdata);
 }
 
-static int terminate_machine(sd_bus *bus, char **args, unsigned n) {
+static int terminate_machine(int argc, char *argv[], void *userdata) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned i;
+        sd_bus *bus = userdata;
+        int i;
 
-        assert(args);
+        assert(bus);
 
-        for (i = 1; i < n; i++) {
+        for (i = 1; i < argc; i++) {
                 int r;
 
                 r = sd_bus_call_method(
@@ -661,7 +678,7 @@ static int terminate_machine(sd_bus *bus, char **args, unsigned n) {
                                 "TerminateMachine",
                                 &error,
                                 NULL,
-                                "s", args[i]);
+                                "s", argv[i]);
                 if (r < 0) {
                         log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
                         return r;
@@ -720,23 +737,21 @@ static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
         return 0;
 }
 
-static int copy_files(sd_bus *bus, char **args, unsigned n) {
+static int copy_files(int argc, char *argv[], void *userdata) {
         char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
         _cleanup_close_ int hostfd = -1;
+        sd_bus *bus = userdata;
         pid_t child, leader;
         bool copy_from;
         siginfo_t si;
         int r;
 
-        if (n > 4) {
-                log_error("Too many arguments.");
-                return -EINVAL;
-        }
+        assert(bus);
 
-        copy_from = streq(args[0], "copy-from");
-        dest = args[3] ?: args[2];
-        host_path = strdupa(copy_from ? dest : args[2]);
-        container_path = strdupa(copy_from ? args[2] : dest);
+        copy_from = streq(argv[0], "copy-from");
+        dest = argv[3] ?: argv[2];
+        host_path = strdupa(copy_from ? dest : argv[2]);
+        container_path = strdupa(copy_from ? argv[2] : dest);
 
         if (!path_is_absolute(container_path)) {
                 log_error("Container path not absolute.");
@@ -751,7 +766,7 @@ static int copy_files(sd_bus *bus, char **args, unsigned n) {
         container_basename = basename(t);
         container_dirname = dirname(container_path);
 
-        r = machine_get_leader(bus, args[1], &leader);
+        r = machine_get_leader(bus, argv[1], &leader);
         if (r < 0)
                 return r;
 
@@ -811,8 +826,9 @@ static int copy_files(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int bind_mount(sd_bus *bus, char **args, unsigned n) {
+static int bind_mount(int argc, char *argv[], void *userdata) {
         char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
+        sd_bus *bus = userdata;
         pid_t child, leader;
         const char *dest;
         siginfo_t si;
@@ -821,28 +837,25 @@ static int bind_mount(sd_bus *bus, char **args, unsigned n) {
                 mount_outside_created = false, mount_outside_mounted = false;
         int r;
 
+        assert(bus);
+
         /* One day, when bind mounting /proc/self/fd/n works across
          * namespace boundaries we should rework this logic to make
          * use of it... */
 
-        if (n > 4) {
-                log_error("Too many arguments.");
-                return -EINVAL;
-        }
-
-        dest = args[3] ?: args[2];
+        dest = argv[3] ?: argv[2];
         if (!path_is_absolute(dest)) {
                 log_error("Destination path not absolute.");
                 return -EINVAL;
         }
 
-        p = strappenda("/run/systemd/nspawn/propagate/", args[1], "/");
+        p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/");
         if (access(p, F_OK) < 0) {
                 log_error("Container does not allow propagation of mount points.");
                 return -ENOTSUP;
         }
 
-        r = machine_get_leader(bus, args[1], &leader);
+        r = machine_get_leader(bus, argv[1], &leader);
         if (r < 0)
                 return r;
 
@@ -882,7 +895,7 @@ static int bind_mount(sd_bus *bus, char **args, unsigned n) {
 
         mount_tmp_created = true;
 
-        if (mount(args[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
+        if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
                 r = log_error_errno(errno, "Failed to overmount: %m");
                 goto finish;
         }
@@ -900,7 +913,7 @@ static int bind_mount(sd_bus *bus, char **args, unsigned n) {
          * directory. This way it will appear there read-only
          * right-away. */
 
-        mount_outside = strappenda("/run/systemd/nspawn/propagate/", args[1], "/XXXXXX");
+        mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
         if (!mkdtemp(mount_outside)) {
                 r = log_error_errno(errno, "Cannot create propagation directory: %m");
                 goto finish;
@@ -1013,6 +1026,8 @@ static int openpt_in_namespace(pid_t pid, int flags) {
         pid_t child;
         siginfo_t si;
 
+        assert(pid > 0);
+
         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
         if (r < 0)
                 return r;
@@ -1082,7 +1097,7 @@ static int openpt_in_namespace(pid_t pid, int flags) {
         return master;
 }
 
-static int login_machine(sd_bus *bus, char **args, unsigned n) {
+static int login_machine(int argc, char *argv[], void *userdata) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
@@ -1090,13 +1105,13 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
         _cleanup_event_unref_ sd_event *event = NULL;
         _cleanup_close_ int master = -1;
         _cleanup_free_ char *getty = NULL;
+        sd_bus *bus = userdata;
         const char *pty, *p;
         pid_t leader;
         sigset_t mask;
         int r, ret = 0;
 
         assert(bus);
-        assert(args);
 
         if (arg_transport != BUS_TRANSPORT_LOCAL) {
                 log_error("Login only supported on local machines.");
@@ -1111,7 +1126,7 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
         if (r < 0)
                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
 
-        r = machine_get_leader(bus, args[1], &leader);
+        r = machine_get_leader(bus, argv[1], &leader);
         if (r < 0)
                 return r;
 
@@ -1129,7 +1144,7 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
                 return -EIO;
         }
 
-        r = sd_bus_open_system_container(&container_bus, args[1]);
+        r = sd_bus_open_system_container(&container_bus, argv[1]);
         if (r < 0)
                 return log_error_errno(r, "Failed to get container bus: %m");
 
@@ -1158,7 +1173,7 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
 
-        log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
+        log_info("Connected to container %s. Press ^] three times within 1s to exit session.", argv[1]);
 
         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
@@ -1175,13 +1190,14 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
 
         fputc('\n', stdout);
 
-        log_info("Connection to container %s terminated.", args[1]);
+        log_info("Connection to container %s terminated.", argv[1]);
 
         sd_event_get_exit_code(event, &ret);
         return ret;
 }
 
-static void help(void) {
+static int help(int argc, char *argv[], void *userdata) {
+
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the virtual machine and container\n"
                "registration manager.\n\n"
@@ -1213,6 +1229,8 @@ static void help(void) {
                "Image commands:\n"
                "  list-images                 Show available images\n",
                program_invocation_short_name);
+
+        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1253,8 +1271,7 @@ static int parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        help();
-                        return 0;
+                        return help(0, NULL, NULL);
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -1328,90 +1345,26 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
-
-        static const struct {
-                const char* verb;
-                const enum {
-                        MORE,
-                        LESS,
-                        EQUAL
-                } argc_cmp;
-                const int argc;
-                int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
-        } verbs[] = {
-                { "list",                  LESS,   1, list_machines     },
-                { "list-images",           LESS,   1, list_images       },
-                { "status",                MORE,   2, show              },
-                { "show",                  MORE,   1, show              },
-                { "terminate",             MORE,   2, terminate_machine },
-                { "reboot",                MORE,   2, reboot_machine    },
-                { "poweroff",              MORE,   2, poweroff_machine  },
-                { "kill",                  MORE,   2, kill_machine      },
-                { "login",                 MORE,   2, login_machine     },
-                { "bind",                  MORE,   3, bind_mount        },
-                { "copy-to",               MORE,   3, copy_files        },
-                { "copy-from",             MORE,   3, copy_files        },
+static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
+
+        static const Verb verbs[] = {
+                { "help",        VERB_ANY, VERB_ANY, 0,            help              },
+                { "list",        VERB_ANY, 1,        VERB_DEFAULT, list_machines     },
+                { "list-images", VERB_ANY, 1,        0,            list_images       },
+                { "status",      2,        VERB_ANY, 0,            show              },
+                { "show",        VERB_ANY, VERB_ANY, 0,            show              },
+                { "terminate",   2,        VERB_ANY, 0,            terminate_machine },
+                { "reboot",      2,        VERB_ANY, 0,            reboot_machine    },
+                { "poweroff",    2,        VERB_ANY, 0,            poweroff_machine  },
+                { "kill",        2,        VERB_ANY, 0,            kill_machine      },
+                { "login",       2,        2,        0,            login_machine     },
+                { "bind",        3,        4,        0,            bind_mount        },
+                { "copy-to",     3,        4,        0,            copy_files        },
+                { "copy-from",   3,        4,        0,            copy_files        },
+                {}
         };
 
-        int left;
-        unsigned i;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        left = argc - optind;
-
-        if (left <= 0)
-                /* Special rule: no arguments means "list" */
-                i = 0;
-        else {
-                if (streq(argv[optind], "help")) {
-                        help();
-                        return 0;
-                }
-
-                for (i = 0; i < ELEMENTSOF(verbs); i++)
-                        if (streq(argv[optind], verbs[i].verb))
-                                break;
-
-                if (i >= ELEMENTSOF(verbs)) {
-                        log_error("Unknown operation %s", argv[optind]);
-                        return -EINVAL;
-                }
-        }
-
-        switch (verbs[i].argc_cmp) {
-
-        case EQUAL:
-                if (left != verbs[i].argc) {
-                        log_error("Invalid number of arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        case MORE:
-                if (left < verbs[i].argc) {
-                        log_error("Too few arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        case LESS:
-                if (left > verbs[i].argc) {
-                        log_error("Too many arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Unknown comparison operator.");
-        }
-
-        return verbs[i].dispatch(bus, argv + optind, left);
+        return dispatch_verb(argc, argv, verbs, bus);
 }
 
 int main(int argc, char*argv[]) {
@@ -1432,7 +1385,7 @@ int main(int argc, char*argv[]) {
                 goto finish;
         }
 
-        r = machinectl_main(bus, argc, argv);
+        r = machinectl_main(argc, argv, bus);
 
 finish:
         pager_close();

commit 7eeeb28e45ae4d436bdccad1d519cfcb81c0762d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 19:18:48 2014 +0100

    import: Verb[] array can be static, too

diff --git a/src/import/import.c b/src/import/import.c
index 9bade38..6fd3eeb 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -163,7 +163,7 @@ static int parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        return help(argc, argv, NULL);
+                        return help(0, NULL, NULL);
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -186,7 +186,7 @@ static int parse_argv(int argc, char *argv[]) {
 
 static int import_main(int argc, char *argv[]) {
 
-        const Verb verbs[] = {
+        static const Verb verbs[] = {
                 { "help",     VERB_ANY, VERB_ANY, 0, help     },
                 { "pull-dck", 2,        3,        0, pull_dck },
                 {}

commit 43343ee7c298dad8db0698b4c181a42ecb7bb216
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 19:17:52 2014 +0100

    verbs: when invoking the default verb, pass a faked argv array, with just the verb in it
    
    That way the dispatcher calls know how they got called.

diff --git a/src/shared/verbs.c b/src/shared/verbs.c
index ead2ff6..bc1ae43 100644
--- a/src/shared/verbs.c
+++ b/src/shared/verbs.c
@@ -49,11 +49,10 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
                         return -EINVAL;
                 }
 
-
-                if (!name)
-                        found = !!(verbs[i].flags & VERB_DEFAULT);
-                else
+                if (name)
                         found = streq(name, verbs[i].verb);
+                else
+                        found = !!(verbs[i].flags & VERB_DEFAULT);
 
                 if (found) {
                         verb = &verbs[i];
@@ -61,6 +60,11 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
                 }
         }
 
+        assert(verb);
+
+        if (!name)
+                left = 1;
+
         if (verb->min_args != VERB_ANY &&
             (unsigned) left < verb->min_args) {
                 log_error("Too few arguments.");
@@ -73,5 +77,14 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
                 return -EINVAL;
         }
 
-        return verb->dispatch(left, argv + optind, userdata);
+        if (name)
+                return verb->dispatch(left, argv + optind, userdata);
+        else {
+                char* fake[2] = {
+                        (char*) verb->verb,
+                        NULL
+                };
+
+                return verb->dispatch(1, fake, userdata);
+        }
 }

commit cd61c3bfd718fb398cc53ced906266a9297782c9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 18:42:50 2014 +0100

    machined/machinectl: add logic to show list of available images
    
    This adds a new bus call to machined that enumerates /var/lib/container
    and returns all trees stored in it, distuingishing three types:
    
            - GPT disk images, which are files suffixed with ".gpt"
            - directory trees
            - btrfs subvolumes

diff --git a/Makefile.am b/Makefile.am
index a7a2b6d..840b871 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5034,9 +5034,11 @@ rootlibexec_PROGRAMS += \
 	systemd-machined
 
 libsystemd_machine_core_la_SOURCES = \
-	src/machine/machined-dbus.c \
 	src/machine/machine.c \
 	src/machine/machine.h \
+	src/machine/image.c \
+	src/machine/image.h \
+	src/machine/machined-dbus.c \
 	src/machine/machine-dbus.c
 
 libsystemd_machine_core_la_LIBADD = \
diff --git a/src/machine/image.c b/src/machine/image.c
new file mode 100644
index 0000000..0ba9652
--- /dev/null
+++ b/src/machine/image.c
@@ -0,0 +1,239 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/statfs.h>
+
+#include "strv.h"
+#include "utf8.h"
+#include "btrfs-util.h"
+#include "image.h"
+#include "bus-label.h"
+
+Image *image_unref(Image *i) {
+        if (!i)
+                return NULL;
+
+        free(i->name);
+        free(i->path);
+        free(i);
+        return NULL;
+}
+
+static int add_image(
+                Hashmap *h,
+                ImageType t,
+                const char *name,
+                const char *path,
+                bool read_only,
+                usec_t mtime,
+                usec_t btime) {
+
+        _cleanup_(image_unrefp) Image *i = NULL;
+        int r;
+
+        assert(h);
+        assert(t >= 0);
+        assert(t < _IMAGE_TYPE_MAX);
+        assert(name);
+
+        i = new(Image, 1);
+        if (!i)
+                return -ENOMEM;
+
+        i->type = t;
+        i->read_only = read_only;
+        i->mtime = mtime;
+        i->btime = btime;
+
+        i->name = strdup(name);
+        if (!i->name)
+                return -ENOMEM;
+
+        if (path) {
+                i->path = strdup(path);
+                if (!i->path)
+                        return -ENOMEM;
+        }
+
+        r = hashmap_put(h, i->name, i);
+        if (r < 0)
+                return r;
+
+        i = NULL;
+        return 0;
+}
+
+int image_discover(Hashmap *h) {
+        const char *path;
+        int r;
+
+        assert(h);
+
+        FOREACH_STRING(path, "/var/lib/container", "/var/lib/machine") {
+                _cleanup_closedir_ DIR *d = NULL;
+                struct dirent *de;
+
+                d = opendir(path);
+                if (!d) {
+                        if (errno == ENOENT)
+                                return 0;
+
+                        return -errno;
+                }
+
+                FOREACH_DIRENT_ALL(de, d, return -errno) {
+                        struct stat st;
+
+                        if (STR_IN_SET(de->d_name, ".", ".."))
+                                continue;
+
+                        /* Temporary files for atomically creating new files */
+                        if (startswith(de->d_name, ".#"))
+                                continue;
+
+                        if (string_has_cc(de->d_name, NULL))
+                                continue;
+
+                        if (!utf8_is_valid(de->d_name))
+                                continue;
+
+                        if (hashmap_contains(h, de->d_name))
+                                continue;
+
+                        /* We explicitly *do* follow symlinks here,
+                         * since we want to allow symlinking trees
+                         * into /var/lib/container/, and treat them
+                         * normally. */
+                        if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
+                                if (errno == ENOENT)
+                                        continue;
+
+                                return -errno;
+                        }
+
+                        if (S_ISDIR(st.st_mode)) {
+
+                                /* btrfs subvolumes have inode 256 */
+                                if (st.st_ino == 256) {
+                                        _cleanup_close_ int fd = -1;
+                                        struct statfs sfs;
+
+                                        fd = openat(dirfd(d), de->d_name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
+                                        if (fd < 0) {
+                                                if (errno == ENOENT)
+                                                        continue;
+
+                                                return -errno;
+                                        }
+
+                                        if (fstatfs(fd, &sfs) < 0)
+                                                return -errno;
+
+                                        if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
+                                                usec_t btime = 0;
+                                                int ro;
+
+                                                /* It's a btrfs subvolume */
+
+                                                ro = btrfs_subvol_is_read_only_fd(fd);
+                                                if (ro < 0)
+                                                        return ro;
+
+                                                /* r = btrfs_subvol_get_btime(fd, &btime); */
+                                                /* if (r < 0) */
+                                                /*         return r; */
+
+                                                r = add_image(h,
+                                                              IMAGE_SUBVOLUME,
+                                                              de->d_name,
+                                                              path,
+                                                              ro,
+                                                              0,
+                                                              btime);
+
+                                                if (r < 0)
+                                                        return r;
+
+                                                continue;
+                                        }
+                                }
+
+                                /* It's just a normal directory. */
+
+                                r = add_image(h,
+                                              IMAGE_DIRECTORY,
+                                              de->d_name,
+                                              path,
+                                              false,
+                                              0,
+                                              0);
+                                if (r < 0)
+                                        return r;
+
+                        } else if (S_ISREG(st.st_mode) &&
+                                   endswith(de->d_name, ".gpt")) {
+
+                                /* It's a GPT block device */
+
+                                r = add_image(h,
+                                              IMAGE_GPT,
+                                              de->d_name,
+                                              path,
+                                              !!(st.st_mode & 0111),
+                                              timespec_load(&st.st_mtim),
+                                              0);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        }
+
+        return 0;
+}
+
+void image_hashmap_free(Hashmap *map) {
+        Image *i;
+
+        while ((i = hashmap_steal_first(map)))
+                image_unref(i);
+
+        hashmap_free(map);
+}
+
+char *image_bus_path(const char *name) {
+        _cleanup_free_ char *e = NULL;
+
+        assert(name);
+
+        e = bus_label_escape(name);
+        if (!e)
+                return NULL;
+
+        return strappend("/org/freedesktop/machine1/image/", e);
+}
+
+static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
+        [IMAGE_DIRECTORY] = "directory",
+        [IMAGE_SUBVOLUME] = "subvolume",
+        [IMAGE_GPT] = "gpt",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);
diff --git a/src/machine/image.h b/src/machine/image.h
new file mode 100644
index 0000000..c77fd19
--- /dev/null
+++ b/src/machine/image.h
@@ -0,0 +1,57 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "time-util.h"
+#include "hashmap.h"
+
+typedef enum ImageType {
+        IMAGE_DIRECTORY,
+        IMAGE_SUBVOLUME,
+        IMAGE_GPT,
+        _IMAGE_TYPE_MAX,
+        _IMAGE_TYPE_INVALID = -1
+} ImageType;
+
+typedef struct Image {
+        ImageType type;
+        char *name;
+        char *path;
+        bool read_only;
+
+        usec_t mtime;
+        usec_t btime;
+} Image;
+
+Image *image_unref(Image *i);
+
+void image_hashmap_free(Hashmap *map);
+
+int image_discover(Hashmap *map);
+
+char *image_bus_path(const char *name);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, image_hashmap_free);
+
+const char* image_type_to_string(ImageType t) _const_;
+ImageType image_type_from_string(const char *s) _pure_;
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index f6fd9cf..163c73d 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -32,6 +32,7 @@
 #include "fileio.h"
 #include "in-addr-util.h"
 #include "local-addresses.h"
+#include "image.h"
 #include "machine.h"
 
 static int property_get_id(
@@ -475,9 +476,11 @@ char *machine_bus_path(Machine *m) {
 }
 
 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
         _cleanup_strv_free_ char **l = NULL;
         Machine *machine = NULL;
         Manager *m = userdata;
+        Image *image;
         Iterator i;
         int r;
 
@@ -497,6 +500,26 @@ int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char
                         return r;
         }
 
+        images = hashmap_new(&string_hash_ops);
+        if (!images)
+                return -ENOMEM;
+
+        r = image_discover(images);
+        if (r < 0)
+                return r;
+
+        HASHMAP_FOREACH(image, images, i) {
+                char *p;
+
+                p = image_bus_path(image->name);
+                if (!p)
+                        return -ENOMEM;
+
+                r = strv_consume(&l, p);
+                if (r < 0)
+                        return r;
+        }
+
         *nodes = l;
         l = NULL;
 
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index a62ffe3..d2d3d16 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -120,6 +120,98 @@ static int list_machines(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
+typedef struct ImageInfo {
+        const char *name;
+        const char *type;
+        bool read_only;
+} ImageInfo;
+
+static int compare_image_info(const void *a, const void *b) {
+        const ImageInfo *x = a, *y = b;
+
+        return strcmp(x->name, y->name);
+}
+
+static int list_images(sd_bus *bus, char **args, unsigned n) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        size_t max_name = strlen("NAME"), max_type = strlen("TYPE");
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_free_ ImageInfo *images = NULL;
+        size_t n_images = 0, n_allocated = 0, j;
+        const char *name, *type, *object;
+        int read_only;
+        int r;
+
+        pager_open_if_enabled();
+
+        r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.machine1",
+                                "/org/freedesktop/machine1",
+                                "org.freedesktop.machine1.Manager",
+                                "ListImages",
+                                &error,
+                                &reply,
+                                "");
+        if (r < 0) {
+                log_error("Could not get images: %s", bus_error_message(&error, -r));
+                return r;
+        }
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbo)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(ssbo)", &name, &type, &read_only, &object)) > 0) {
+
+                if (name[0] == '.' && !arg_all)
+                        continue;
+
+                if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
+                        return log_oom();
+
+                images[n_images].name = name;
+                images[n_images].type = type;
+                images[n_images].read_only = read_only;
+
+                if (strlen(name) > max_name)
+                        max_name = strlen(name);
+
+                if (strlen(type) > max_type)
+                        max_type = strlen(type);
+
+                n_images++;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
+
+        if (arg_legend)
+                printf("%-*s %-*s %-3s\n", (int) max_name, "NAME", (int) max_type, "TYPE", "RO");
+
+        for (j = 0; j < n_images; j++) {
+                printf("%-*s %-*s %-3s\n",
+                       (int) max_name, images[j].name,
+                       (int) max_type, images[j].type,
+                       yes_no(images[j].read_only));
+        }
+
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+
+        if (arg_legend)
+                printf("\n%zu images listed.\n", n_images);
+
+        return 0;
+}
+
 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1106,7 +1198,7 @@ static void help(void) {
                "  -s --signal=SIGNAL          Which signal to send\n"
                "     --read-only              Create read-only bind mount\n"
                "     --mkdir                  Create directory before bind mounting, if missing\n\n"
-               "Commands:\n"
+               "Machine Commands:\n"
                "  list                        List running VMs and containers\n"
                "  status NAME...              Show VM/container status\n"
                "  show NAME...                Show properties of one or more VMs/containers\n"
@@ -1117,7 +1209,9 @@ static void help(void) {
                "  terminate NAME...           Terminate one or more VMs/containers\n"
                "  bind NAME PATH [PATH]       Bind mount a path from the host into a container\n"
                "  copy-to NAME PATH [PATH]    Copy files from the host to a container\n"
-               "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n",
+               "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n\n"
+               "Image commands:\n"
+               "  list-images                 Show available images\n",
                program_invocation_short_name);
 }
 
@@ -1247,6 +1341,7 @@ static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
                 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
         } verbs[] = {
                 { "list",                  LESS,   1, list_machines     },
+                { "list-images",           LESS,   1, list_images       },
                 { "status",                MORE,   2, show              },
                 { "show",                  MORE,   1, show              },
                 { "terminate",             MORE,   2, terminate_machine },
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 0b57b36..949c7d6 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -39,6 +39,7 @@
 #include "bus-common-errors.h"
 #include "time-util.h"
 #include "cgroup-util.h"
+#include "image.h"
 #include "machined.h"
 
 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -436,11 +437,63 @@ static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, v
         return bus_machine_method_get_os_release(bus, message, machine, error);
 }
 
+static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        Manager *m = userdata;
+        Image *image;
+        Iterator i;
+        int r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        images = hashmap_new(&string_hash_ops);
+        if (!images)
+                return -ENOMEM;
+
+        r = image_discover(images);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(ssbo)");
+        if (r < 0)
+                return r;
+
+        HASHMAP_FOREACH(image, images, i) {
+                _cleanup_free_ char *p = NULL;
+
+                p = image_bus_path(image->name);
+                if (!p)
+                        return -ENOMEM;
+
+                r = sd_bus_message_append(reply, "(ssbo)",
+                                          image->name,
+                                          image_type_to_string(image->type),
+                                          image->read_only,
+                                          p);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(bus, reply, NULL);
+}
+
 const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf
index ac1aee8..3745c52 100644
--- a/src/machine/org.freedesktop.machine1.conf
+++ b/src/machine/org.freedesktop.machine1.conf
@@ -42,6 +42,10 @@
 
                 <allow send_destination="org.freedesktop.machine1"
                        send_interface="org.freedesktop.machine1.Manager"
+                       send_member="ListImages"/>
+
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
                        send_member="GetMachine"/>
 
                 <allow send_destination="org.freedesktop.machine1"
diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c
index 492d7fc..d685b3e 100644
--- a/src/shared/btrfs-util.c
+++ b/src/shared/btrfs-util.c
@@ -84,18 +84,18 @@ int btrfs_is_snapshot(int fd) {
         struct stat st;
         struct statfs sfs;
 
-        if (fstatfs(fd, &sfs) < 0)
+        /* On btrfs subvolumes always have the inode 256 */
+
+        if (fstat(fd, &st) < 0)
                 return -errno;
 
-        if (!F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
+        if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
                 return 0;
 
-        if (fstat(fd, &st) < 0)
+        if (fstatfs(fd, &sfs) < 0)
                 return -errno;
 
-        /* On btrfs subvolumes always have the inode 256 */
-
-        return S_ISDIR(st.st_mode) && st.st_ino == 256;
+        return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
 }
 
 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
@@ -232,6 +232,15 @@ int btrfs_subvol_read_only(const char *path, bool b) {
         return 0;
 }
 
+int btrfs_subvol_is_read_only_fd(int fd) {
+        uint64_t flags;
+
+        if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
+                return -errno;
+
+        return !!(flags & BTRFS_SUBVOL_RDONLY);
+}
+
 int btrfs_reflink(int infd, int outfd) {
         int r;
 
diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h
index 28dbeb4..c8f798b 100644
--- a/src/shared/btrfs-util.h
+++ b/src/shared/btrfs-util.h
@@ -28,6 +28,7 @@ int btrfs_subvol_make(const char *path);
 int btrfs_subvol_remove(const char *path);
 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy);
 int btrfs_subvol_read_only(const char *path, bool b);
+int btrfs_subvol_is_read_only_fd(int fd);
 
 int btrfs_reflink(int infd, int outfd);
 
diff --git a/src/shared/util.h b/src/shared/util.h
index 96b8c1b..e783ec6 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -775,6 +775,15 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
                         continue;                                       \
                 else
 
+#define FOREACH_DIRENT_ALL(de, d, on_error)                             \
+        for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d))   \
+                if (!de) {                                              \
+                        if (errno > 0) {                                \
+                                on_error;                               \
+                        }                                               \
+                        break;                                          \
+                } else
+
 static inline void *mempset(void *s, int c, size_t n) {
         memset(s, c, n);
         return (uint8_t*)s + n;
diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in
index bbb13de..15f34d9 100644
--- a/units/systemd-machined.service.in
+++ b/units/systemd-machined.service.in
@@ -15,7 +15,7 @@ After=machine.slice
 [Service]
 ExecStart=@rootlibexecdir@/systemd-machined
 BusName=org.freedesktop.machine1
-CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT
+CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH
 WatchdogSec=1min
 PrivateTmp=yes
 PrivateDevices=yes

commit 8eebf6ad553adb22d7ea5d291de0b0da38606f4d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Dec 19 18:40:23 2014 +0100

    util: when creating temporary filename for atomic creation of files, add an extra "#" to the name
    
    That way, we have a simple, somewhat reliable way to detect such
    temporary files, by simply checking if they start with ".#".

diff --git a/src/shared/util.c b/src/shared/util.c
index dbae55f..5f18d34 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -6992,18 +6992,18 @@ int tempfn_xxxxxx(const char *p, char **ret) {
          *         /foo/bar/waldo
          *
          * Into this:
-         *         /foo/bar/.waldoXXXXXX
+         *         /foo/bar/.#waldoXXXXXX
          */
 
         fn = basename(p);
         if (!filename_is_valid(fn))
                 return -EINVAL;
 
-        t = new(char, strlen(p) + 1 + 6 + 1);
+        t = new(char, strlen(p) + 2 + 6 + 1);
         if (!t)
                 return -ENOMEM;
 
-        strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), "."), fn), "XXXXXX");
+        strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX");
 
         *ret = path_kill_slashes(t);
         return 0;
@@ -7023,18 +7023,18 @@ int tempfn_random(const char *p, char **ret) {
          *         /foo/bar/waldo
          *
          * Into this:
-         *         /foo/bar/.waldobaa2a261115984a9
+         *         /foo/bar/.#waldobaa2a261115984a9
          */
 
         fn = basename(p);
         if (!filename_is_valid(fn))
                 return -EINVAL;
 
-        t = new(char, strlen(p) + 1 + 16 + 1);
+        t = new(char, strlen(p) + 2 + 16 + 1);
         if (!t)
                 return -ENOMEM;
 
-        x = stpcpy(stpcpy(mempcpy(t, p, fn - p), "."), fn);
+        x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn);
 
         u = random_u64();
         for (i = 0; i < 16; i++) {
@@ -7059,14 +7059,14 @@ int tempfn_random_child(const char *p, char **ret) {
         /* Turns this:
          *         /foo/bar/waldo
          * Into this:
-         *         /foo/bar/waldo/.3c2b6219aa75d7d0
+         *         /foo/bar/waldo/.#3c2b6219aa75d7d0
          */
 
-        t = new(char, strlen(p) + 2 + 16 + 1);
+        t = new(char, strlen(p) + 3 + 16 + 1);
         if (!t)
                 return -ENOMEM;
 
-        x = stpcpy(stpcpy(t, p), "/.");
+        x = stpcpy(stpcpy(t, p), "/.#");
 
         u = random_u64();
         for (i = 0; i < 16; i++) {



More information about the systemd-commits mailing list