]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/machine/machinectl.c
nulstr-util: Declare NULSTR_FOREACH() iterator inline
[thirdparty/systemd.git] / src / machine / machinectl.c
index 213879c8edf1011ff3c0ae0acbd342fb3e649bc2..93761a1da9bdff993b5a7a25f8c347025246d7c2 100644 (file)
@@ -14,6 +14,7 @@
 #include "sd-bus.h"
 
 #include "alloc-util.h"
+#include "build.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-locator.h"
@@ -24,8 +25,8 @@
 #include "bus-wait-for-jobs.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
+#include "constants.h"
 #include "copy.h"
-#include "def.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "format-table.h"
@@ -34,6 +35,7 @@
 #include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
+#include "machine-dbus.h"
 #include "macro.h"
 #include "main-func.h"
 #include "mkdir.h"
 #include "verbs.h"
 #include "web-util.h"
 
-#define ALL_ADDRESSES -1
-
 static char **arg_property = NULL;
 static bool arg_all = false;
 static BusPrintPropertyFlags arg_print_flags = 0;
 static bool arg_full = false;
 static PagerFlags arg_pager_flags = 0;
 static bool arg_legend = true;
-static const char *arg_kill_who = NULL;
+static const char *arg_kill_whom = NULL;
 static int arg_signal = SIGTERM;
 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
 static const char *arg_host = NULL;
@@ -82,7 +82,7 @@ static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
 static const char* arg_format = NULL;
 static const char *arg_uid = NULL;
 static char **arg_setenv = NULL;
-static int arg_max_addresses = 1;
+static unsigned arg_max_addresses = 1;
 
 STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_setenv, strv_freep);
@@ -98,7 +98,7 @@ static OutputFlags get_output_flags(void) {
 static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *k, *v, *iter, **query_res = NULL;
+        const char *k, *v, **query_res = NULL;
         size_t count = 0, awaited_args = 0;
         va_list ap;
         int r;
@@ -259,27 +259,25 @@ static int show_table(Table *table, const char *word) {
 }
 
 static int list_machines(int argc, char *argv[], void *userdata) {
-
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(table_unrefp) Table *table = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         pager_open(arg_pager_flags);
 
         r = bus_call_method(bus, bus_machine_mgr, "ListMachines", &error, &reply, NULL);
         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",
+                          arg_max_addresses > 0 ? "addresses" : NULL);
         if (!table)
                 return log_oom();
 
-        table_set_empty_string(table, "-");
-        if (!arg_full && arg_max_addresses != ALL_ADDRESSES)
+        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
+        if (!arg_full && arg_max_addresses > 0 && arg_max_addresses < UINT_MAX)
                 table_set_cell_height_max(table, arg_max_addresses);
 
         if (arg_full)
@@ -311,23 +309,23 @@ static int list_machines(int argc, char *argv[], void *userdata) {
                                 &os,
                                 &version_id);
 
-                (void) call_get_addresses(
-                                bus,
-                                name,
-                                0,
-                                "",
-                                "\n",
-                                &addresses);
-
                 r = table_add_many(table,
                                    TABLE_STRING, empty_to_null(name),
                                    TABLE_STRING, empty_to_null(class),
                                    TABLE_STRING, empty_to_null(service),
                                    TABLE_STRING, empty_to_null(os),
-                                   TABLE_STRING, empty_to_null(version_id),
-                                   TABLE_STRING, empty_to_null(addresses));
+                                   TABLE_STRING, empty_to_null(version_id));
                 if (r < 0)
                         return table_log_add_error(r);
+
+                if (arg_max_addresses > 0) {
+                        (void) call_get_addresses(bus, name, 0, "", "\n", &addresses);
+
+                        r = table_add_many(table,
+                                           TABLE_STRING, empty_to_null(addresses));
+                        if (r < 0)
+                                return table_log_add_error(r);
+                }
         }
 
         r = sd_bus_message_exit_container(reply);
@@ -342,11 +340,9 @@ static int list_images(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(table_unrefp) Table *table = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         pager_open(arg_pager_flags);
 
         r = bus_call_method(bus, bus_machine_mgr, "ListImages", &error, &reply, NULL);
@@ -693,11 +689,9 @@ static int show_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         bool properties, new_line = false;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r = 0;
 
-        assert(bus);
-
         properties = !strstr(argv[0], "status");
 
         pager_open(arg_pager_flags);
@@ -992,11 +986,9 @@ static int show_image(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         bool properties, new_line = false;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r = 0;
 
-        assert(bus);
-
         properties = !strstr(argv[0], "status");
 
         pager_open(arg_pager_flags);
@@ -1036,15 +1028,13 @@ static int show_image(int argc, char *argv[], void *userdata) {
 
 static int kill_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        if (!arg_kill_who)
-                arg_kill_who = "all";
+        if (!arg_kill_whom)
+                arg_kill_whom = "all";
 
         for (int i = 1; i < argc; i++) {
                 r = bus_call_method(
@@ -1053,7 +1043,7 @@ static int kill_machine(int argc, char *argv[], void *userdata) {
                                 "KillMachine",
                                 &error,
                                 NULL,
-                                "ssi", argv[i], arg_kill_who, arg_signal);
+                                "ssi", argv[i], arg_kill_whom, arg_signal);
                 if (r < 0)
                         return log_error_errno(r, "Could not kill machine: %s", bus_error_message(&error, r));
         }
@@ -1062,14 +1052,14 @@ static int kill_machine(int argc, char *argv[], void *userdata) {
 }
 
 static int reboot_machine(int argc, char *argv[], void *userdata) {
-        arg_kill_who = "leader";
+        arg_kill_whom = "leader";
         arg_signal = SIGINT; /* sysvinit + systemd */
 
         return kill_machine(argc, argv, userdata);
 }
 
 static int poweroff_machine(int argc, char *argv[], void *userdata) {
-        arg_kill_who = "leader";
+        arg_kill_whom = "leader";
         arg_signal = SIGRTMIN+4; /* only systemd */
 
         return kill_machine(argc, argv, userdata);
@@ -1077,11 +1067,9 @@ static int poweroff_machine(int argc, char *argv[], void *userdata) {
 
 static int terminate_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         for (int i = 1; i < argc; i++) {
@@ -1093,17 +1081,22 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static const char *select_copy_method(bool copy_from, bool force) {
+        if (force)
+                return copy_from ? "CopyFromMachineWithFlags" : "CopyToMachineWithFlags";
+        else
+                return copy_from ? "CopyFromMachine" : "CopyToMachine";
+}
+
 static int copy_files(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *abs_host_path = NULL;
         char *dest, *host_path, *container_path;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         bool copy_from;
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         copy_from = streq(argv[0], "copy-from");
@@ -1123,7 +1116,7 @@ static int copy_files(int argc, char *argv[], void *userdata) {
                         bus,
                         &m,
                         bus_machine_mgr,
-                        copy_from ? "CopyFromMachine" : "CopyToMachine");
+                        select_copy_method(copy_from, arg_force));
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1136,6 +1129,12 @@ static int copy_files(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        if (arg_force) {
+                r = sd_bus_message_append(m, "t", MACHINE_COPY_REPLACE);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
         /* This is a slow operation, hence turn off any method call timeouts */
         r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
         if (r < 0)
@@ -1146,11 +1145,9 @@ static int copy_files(int argc, char *argv[], void *userdata) {
 
 static int bind_mount(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         r = bus_call_method(
@@ -1289,11 +1286,9 @@ static int login_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
         int master = -1, r;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         const char *match, *machine;
 
-        assert(bus);
-
         if (!strv_isempty(arg_setenv) || arg_uid)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
@@ -1343,12 +1338,10 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
         int master = -1, r;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         const char *match, *machine, *path;
         _cleanup_free_ char *uid = NULL;
 
-        assert(bus);
-
         if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE))
                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
                                        "Shell only supported on local machines.");
@@ -1419,11 +1412,9 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
 }
 
 static int remove_image(int argc, char *argv[], void *userdata) {
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         for (int i = 1; i < argc; i++) {
@@ -1449,11 +1440,9 @@ static int remove_image(int argc, char *argv[], void *userdata) {
 
 static int rename_image(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         r = bus_call_method(
@@ -1472,11 +1461,9 @@ static int rename_image(int argc, char *argv[], void *userdata) {
 static int clone_image(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CloneImage");
@@ -1497,11 +1484,9 @@ static int clone_image(int argc, char *argv[], void *userdata) {
 
 static int read_only_image(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int b = true, r;
 
-        assert(bus);
-
         if (argc > 2) {
                 b = parse_boolean(argv[2]);
                 if (b < 0)
@@ -1557,11 +1542,9 @@ static int make_service_name(const char *name, char **ret) {
 static int start_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
         ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
 
@@ -1615,14 +1598,12 @@ static int start_machine(int argc, char *argv[], void *userdata) {
 static int enable_machine(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        UnitFileChange *changes = NULL;
+        InstallChange *changes = NULL;
         size_t n_changes = 0;
         const char *method = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
@@ -1689,7 +1670,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
         r = 0;
 
 finish:
-        unit_file_changes_free(changes, n_changes);
+        install_changes_free(changes, n_changes);
 
         return r;
 }
@@ -1820,11 +1801,9 @@ static int import_tar(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
         _cleanup_close_ int fd = -1;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         if (argc >= 2)
                 path = empty_or_dash_to_null(argv[1]);
 
@@ -1883,11 +1862,9 @@ static int import_raw(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *ll = NULL, *fn = NULL;
         const char *local = NULL, *path = NULL;
         _cleanup_close_ int fd = -1;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         if (argc >= 2)
                 path = empty_or_dash_to_null(argv[1]);
 
@@ -1946,11 +1923,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
         const char *local = NULL, *path = NULL;
         _cleanup_free_ char *fn = NULL;
         _cleanup_close_ int fd = -1;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         if (argc >= 2)
                 path = empty_or_dash_to_null(argv[1]);
 
@@ -2014,11 +1989,9 @@ static int export_tar(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_close_ int fd = -1;
         const char *local = NULL, *path = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         local = argv[1];
         if (!hostname_is_valid(local, 0))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -2056,11 +2029,9 @@ static int export_raw(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_close_ int fd = -1;
         const char *local = NULL, *path = NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         local = argv[1];
         if (!hostname_is_valid(local, 0))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -2098,11 +2069,9 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *l = NULL, *ll = NULL;
         const char *local, *remote;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         remote = argv[1];
         if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -2154,11 +2123,9 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *l = NULL, *ll = NULL;
         const char *local, *remote;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         remote = argv[1];
         if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -2315,11 +2282,9 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
 
 static int cancel_transfer(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        sd_bus *bus = userdata;
+        sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
-        assert(bus);
-
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         for (int i = 1; i < argc; i++) {
@@ -2486,7 +2451,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -a --all                    Show all properties, including empty ones\n"
                "     --value                  When showing properties, only print the value\n"
                "  -l --full                   Do not ellipsize output\n"
-               "     --kill-who=WHO           Who to send signal to\n"
+               "     --kill-whom=WHOM         Whom to send signal to\n"
                "  -s --signal=SIGNAL          Which signal to send\n"
                "     --uid=USER               Specify user ID to invoke shell as\n"
                "  -E --setenv=VAR[=VALUE]     Add an environment variable for shell\n"
@@ -2496,9 +2461,9 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --max-addresses=INTEGER  Number of internet addresses to show at most\n"
                "  -o --output=STRING          Change journal output mode (short, short-precise,\n"
                "                               short-iso, short-iso-precise, short-full,\n"
-               "                               short-monotonic, short-unix, verbose, export,\n"
+               "                               short-monotonic, short-unix, short-delta,\n"
                "                               json, json-pretty, json-sse, json-seq, cat,\n"
-               "                               with-unit)\n"
+               "                               verbose, export, with-unit)\n"
                "     --verify=MODE            Verification mode for downloaded images (no,\n"
                "                              checksum, signature)\n"
                "     --force                  Download image even if already exists\n"
@@ -2520,7 +2485,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_NO_PAGER,
                 ARG_NO_LEGEND,
                 ARG_VALUE,
-                ARG_KILL_WHO,
+                ARG_KILL_WHOM,
                 ARG_READ_ONLY,
                 ARG_MKDIR,
                 ARG_NO_ASK_PASSWORD,
@@ -2540,7 +2505,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "full",            no_argument,       NULL, 'l'                 },
                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
-                { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
+                { "kill-whom",       required_argument, NULL, ARG_KILL_WHOM       },
                 { "signal",          required_argument, NULL, 's'                 },
                 { "host",            required_argument, NULL, 'H'                 },
                 { "machine",         required_argument, NULL, 'M'                 },
@@ -2679,8 +2644,8 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_legend = false;
                         break;
 
-                case ARG_KILL_WHO:
-                        arg_kill_who = optarg;
+                case ARG_KILL_WHOM:
+                        arg_kill_whom = optarg;
                         break;
 
                 case 's':
@@ -2751,13 +2716,10 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_MAX_ADDRESSES:
                         if (streq(optarg, "all"))
-                                arg_max_addresses = ALL_ADDRESSES;
-                        else if (safe_atoi(optarg, &arg_max_addresses) < 0)
+                                arg_max_addresses = UINT_MAX;
+                        else if (safe_atou(optarg, &arg_max_addresses) < 0)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Invalid number of addresses: %s", optarg);
-                        else if (arg_max_addresses <= 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Number of IPs cannot be negative or zero: %s", optarg);
                         break;
 
                 case '?':