]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/machine/machinectl.c
util: split out sorting related calls to new sort-util.[ch]
[thirdparty/systemd.git] / src / machine / machinectl.c
index 898be80a2276705ad96a4d256c42964ec5ca5271..78f5f2ff3238ae4b719c828dfed3aceefcea5130 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <locale.h>
+#include <math.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <string.h>
 #include "rlimit-util.h"
 #include "sigbus.h"
 #include "signal-util.h"
+#include "sort-util.h"
 #include "spawn-polkit-agent.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
-#include "util.h"
 #include "verbs.h"
 #include "web-util.h"
 
@@ -236,7 +237,7 @@ static int call_get_addresses(sd_bus *bus, const char *name, int ifi, const char
 
         if (truncate) {
 
-                if (!strextend(&addresses, special_glyph(ELLIPSIS), NULL))
+                if (!strextend(&addresses, special_glyph(SPECIAL_GLYPH_ELLIPSIS), NULL))
                         return -ENOMEM;
 
         }
@@ -258,7 +259,10 @@ static int show_table(Table *table, const char *word) {
 
                 table_set_header(table, arg_legend);
 
-                r = table_print(table, NULL);
+                if (OUTPUT_MODE_IS_JSON(arg_output))
+                        r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
+                else
+                        r = table_print(table, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to show table: %m");
         }
@@ -296,7 +300,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
 
-        table = table_new("MACHINE", "CLASS", "SERVICE", "OS", "VERSION", "ADDRESSES");
+        table = table_new("machine", "class", "service", "os", "version", "addresses");
         if (!table)
                 return log_oom();
 
@@ -331,7 +335,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
                                 name,
                                 0,
                                 "",
-                                "",
+                                " ",
                                 arg_addrs,
                                 &addresses);
 
@@ -376,7 +380,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
 
-        table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED");
+        table = table_new("name", "type", "ro", "usage", "created", "modified");
         if (!table)
                 return log_oom();
 
@@ -1305,7 +1309,7 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r
 static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
         char last_char = 0;
         bool machine_died;
-        int ret = 0, r;
+        int r;
 
         assert(event);
         assert(master >= 0);
@@ -1351,8 +1355,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
                         log_info("Connection to machine %s terminated.", name);
         }
 
-        sd_event_get_exit_code(event, &ret);
-        return ret;
+        return 0;
 }
 
 static int parse_machine_uid(const char *spec, const char **machine, char **uid) {
@@ -1736,7 +1739,7 @@ static int start_machine(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
                 if (r == 0) {
-                        log_error("Machine image '%s' does not exist.", argv[1]);
+                        log_error("Machine image '%s' does not exist.", argv[i]);
                         return -ENXIO;
                 }
 
@@ -1808,7 +1811,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
                 if (r == 0) {
-                        log_error("Machine image '%s' does not exist.", argv[1]);
+                        log_error("Machine image '%s' does not exist.", argv[i]);
                         return -ENXIO;
                 }
 
@@ -1987,28 +1990,38 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
         return -r;
 }
 
+static const char *nullify_dash(const char *p) {
+        if (isempty(p))
+                return NULL;
+
+        if (streq(p, "-"))
+                return NULL;
+
+        return p;
+}
+
 static int import_tar(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_free_ char *ll = NULL;
-        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
+        _cleanup_close_ int fd = -1;
         sd_bus *bus = userdata;
         int r;
 
         assert(bus);
 
         if (argc >= 2)
-                path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+                path = nullify_dash(argv[1]);
 
         if (argc >= 3)
-                local = argv[2];
-        else if (path)
-                local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
 
+                local = fn;
+        }
         if (!local) {
                 log_error("Need either path or local name.");
                 return -EINVAL;
@@ -2056,26 +2069,26 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
 static int import_raw(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        _cleanup_free_ char *ll = NULL;
-        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
+        _cleanup_close_ int fd = -1;
         sd_bus *bus = userdata;
         int r;
 
         assert(bus);
 
         if (argc >= 2)
-                path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+                path = nullify_dash(argv[1]);
 
         if (argc >= 3)
-                local = argv[2];
-        else if (path)
-                local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
 
+                local = fn;
+        }
         if (!local) {
                 log_error("Need either path or local name.");
                 return -EINVAL;
@@ -2121,6 +2134,67 @@ static int import_raw(int argc, char *argv[], void *userdata) {
         return transfer_image_common(bus, m);
 }
 
+static int import_fs(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        const char *local = NULL, *path = NULL;
+        _cleanup_free_ char *fn = NULL;
+        _cleanup_close_ int fd = -1;
+        sd_bus *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        if (argc >= 2)
+                path = nullify_dash(argv[1]);
+
+        if (argc >= 3)
+                local = nullify_dash(argv[2]);
+        else if (path) {
+                r = path_extract_filename(path, &fn);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot extract container name from filename: %m");
+
+                local = fn;
+        }
+        if (!local) {
+                log_error("Need either path or local name.");
+                return -EINVAL;
+        }
+
+        if (!machine_name_is_valid(local)) {
+                log_error("Local name %s is not a suitable machine name.", local);
+                return -EINVAL;
+        }
+
+        if (path) {
+                fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open directory '%s': %m", path);
+        }
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        &m,
+                        "org.freedesktop.import1",
+                        "/org/freedesktop/import1",
+                        "org.freedesktop.import1.Manager",
+                        "ImportFileSystem");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(
+                        m,
+                        "hsbb",
+                        fd >= 0 ? fd : STDIN_FILENO,
+                        local,
+                        arg_force,
+                        arg_read_only);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return transfer_image_common(bus, m);
+}
+
 static void determine_compression_from_filename(const char *p) {
         if (arg_format)
                 return;
@@ -2452,12 +2526,21 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
                        (int) max_remote, "REMOTE");
 
         for (j = 0; j < n_transfers; j++)
-                printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
-                       (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
-                       (int) 6, (unsigned) (transfers[j].progress * 100),
-                       (int) max_type, transfers[j].type,
-                       (int) max_local, transfers[j].local,
-                       (int) max_remote, transfers[j].remote);
+
+                if (transfers[j].progress < 0)
+                        printf("%*" PRIu32 " %*s %-*s %-*s %-*s\n",
+                               (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
+                               (int) 7, "n/a",
+                               (int) max_type, transfers[j].type,
+                               (int) max_local, transfers[j].local,
+                               (int) max_remote, transfers[j].remote);
+                else
+                        printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
+                               (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
+                               (int) 6, (unsigned) (transfers[j].progress * 100),
+                               (int) max_type, transfers[j].type,
+                               (int) max_local, transfers[j].local,
+                               (int) max_remote, transfers[j].remote);
 
         if (arg_legend) {
                 if (n_transfers > 0)
@@ -2583,10 +2666,15 @@ static int clean_images(int argc, char *argv[], void *userdata) {
                 return bus_log_parse_error(r);
 
         while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
-                log_info("Removed image '%s'. Freed exclusive disk space: %s",
-                         name, format_bytes(fb, sizeof(fb), usage));
-
-                total += usage;
+                if (usage == UINT64_MAX) {
+                        log_info("Removed image '%s'", name);
+                        total = UINT64_MAX;
+                } else {
+                        log_info("Removed image '%s'. Freed exclusive disk space: %s",
+                                 name, format_bytes(fb, sizeof(fb), usage));
+                        if (total != UINT64_MAX)
+                                total += usage;
+                }
                 c++;
         }
 
@@ -2594,8 +2682,11 @@ static int clean_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        log_info("Removed %u images in total. Total freed exclusive disk space %s.",
-                 c, format_bytes(fb, sizeof(fb), total));
+        if (total == UINT64_MAX)
+                log_info("Removed %u images in total.", c);
+        else
+                log_info("Removed %u images in total. Total freed exclusive disk space: %s.",
+                         c, format_bytes(fb, sizeof(fb), total));
 
         return 0;
 }
@@ -2675,6 +2766,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"
                "  import-tar FILE [NAME]      Import a local TAR container image\n"
                "  import-raw FILE [NAME]      Import a local RAW container or VM image\n"
+               "  import-fs DIRECTORY [NAME]  Import a local directory container image\n"
                "  export-tar NAME [FILE]      Export a TAR container image locally\n"
                "  export-raw NAME [FILE]      Export a RAW container or VM image locally\n"
                "  list-transfers              Show list of downloads in progress\n"
@@ -2839,6 +2931,9 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_output < 0)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Unknown output '%s'.", optarg);
+
+                        if (OUTPUT_MODE_IS_JSON(arg_output))
+                                arg_legend = false;
                         break;
 
                 case ARG_NO_PAGER:
@@ -2996,6 +3091,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
                 { "disable",         2,        VERB_ANY, 0,            enable_machine    },
                 { "import-tar",      2,        3,        0,            import_tar        },
                 { "import-raw",      2,        3,        0,            import_raw        },
+                { "import-fs",       2,        3,        0,            import_fs         },
                 { "export-tar",      2,        3,        0,            export_tar        },
                 { "export-raw",      2,        3,        0,            export_raw        },
                 { "pull-tar",        2,        3,        0,            pull_tar          },
@@ -3010,7 +3106,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
         return dispatch_verb(argc, argv, verbs, bus);
 }
 
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;