]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/systemctl/systemctl.c
util-lib: move a number of fs operations into fs-util.[ch]
[thirdparty/systemd.git] / src / systemctl / systemctl.c
index 9718ef54df1885685bb70161b143767eb81683bd..2b1caa619920601aec6e3d2a3687f015c259d565 100644 (file)
 #include "efivars.h"
 #include "env-util.h"
 #include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "hostname-util.h"
 #include "initreq.h"
 #include "install.h"
+#include "io-util.h"
 #include "list.h"
 #include "log.h"
 #include "logs-show.h"
 #include "macro.h"
 #include "mkdir.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "set.h"
 #include "signal-util.h"
 #include "socket-util.h"
@@ -71,6 +76,7 @@
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
+#include "user-util.h"
 #include "util.h"
 #include "utmp-wtmp.h"
 #include "verbs.h"
@@ -107,7 +113,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
 static char **arg_wall = NULL;
 static const char *arg_kill_who = NULL;
 static int arg_signal = SIGTERM;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
 static usec_t arg_when = 0;
 static enum action {
         _ACTION_INVALID,
@@ -3110,7 +3116,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
                         return r;
 
         } else if (a == ACTION_EXIT && argc > 1) {
-                uint8_t code = 0;
+                uint8_t code;
 
                 /* If the exit code is not given on the command line,
                  * don't reset it to zero: just keep it as it might
@@ -3475,7 +3481,8 @@ static void print_status_info(
 
                                 dir = mfree(dir);
 
-                                if (path_get_parent(*dropin, &dir) < 0) {
+                                dir = dirname_malloc(*dropin);
+                                if (!dir) {
                                         log_oom();
                                         return;
                                 }
@@ -5907,7 +5914,7 @@ static int is_system_running(int argc, char *argv[], void *userdata) {
 }
 
 static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
-        char *t;
+        _cleanup_free_ char *t = NULL;
         int r;
 
         assert(new_path);
@@ -5919,26 +5926,21 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
                 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
 
         r = mkdir_parents(new_path, 0755);
-        if (r < 0) {
-                free(t);
+        if (r < 0)
                 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
-        }
 
         r = copy_file(original_path, t, 0, 0644, 0);
         if (r == -ENOENT) {
+
                 r = touch(t);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
-                        free(t);
-                        return r;
-                }
-        } else if (r < 0) {
-                log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
-                free(t);
-                return r;
-        }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+
+        } else if (r < 0)
+                return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
 
         *ret_tmp_fn = t;
+        t = NULL;
 
         return 0;
 }
@@ -5946,6 +5948,9 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
 static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
         _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
 
+        assert(name);
+        assert(ret_path);
+
         switch (arg_scope) {
                 case UNIT_FILE_SYSTEM:
                         path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
@@ -5997,8 +6002,7 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
 }
 
 static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
-        char *tmp_new_path, *ending;
-        char *tmp_tmp_path;
+        char *tmp_new_path, *tmp_tmp_path, *ending;
         int r;
 
         assert(unit_name);
@@ -6030,8 +6034,7 @@ static int unit_file_create_copy(
                 char **ret_new_path,
                 char **ret_tmp_path) {
 
-        char *tmp_new_path;
-        char *tmp_tmp_path;
+        char *tmp_new_path, *tmp_tmp_path;
         int r;
 
         assert(fragment_path);
@@ -6150,7 +6153,7 @@ static int run_editor(char **paths) {
         if (r < 0)
                 return log_error_errno(r, "Failed to wait for child: %m");
 
-        return r;
+        return 0;
 }
 
 static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
@@ -6234,13 +6237,14 @@ static int edit(int argc, char *argv[], void *userdata) {
                 goto end;
 
         STRV_FOREACH_PAIR(original, tmp, paths) {
-                /* If the temporary file is empty we ignore it.
-                 * It's useful if the user wants to cancel its modification
+                /* If the temporary file is empty we ignore it.  It's
+                 * useful if the user wants to cancel its modification
                  */
                 if (null_or_empty_path(*tmp)) {
-                        log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
+                        log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
                         continue;
                 }
+
                 r = rename(*tmp, *original);
                 if (r < 0) {
                         r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
@@ -6248,12 +6252,14 @@ static int edit(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        if (!arg_no_reload && bus && !install_client_side())
+        r = 0;
+
+        if (!arg_no_reload && !install_client_side())
                 r = daemon_reload(argc, argv, userdata);
 
 end:
         STRV_FOREACH_PAIR(original, tmp, paths)
-                unlink_noerrno(*tmp);
+                (void) unlink(*tmp);
 
         return r;
 }
@@ -6447,15 +6453,90 @@ static void runlevel_help(void) {
 
 static void help_types(void) {
         int i;
-        const char *t;
 
         if (!arg_no_legend)
                 puts("Available unit types:");
-        for (i = 0; i < _UNIT_TYPE_MAX; i++) {
-                t = unit_type_to_string(i);
-                if (t)
-                        puts(t);
-        }
+        for (i = 0; i < _UNIT_TYPE_MAX; i++)
+                puts(unit_type_to_string(i));
+}
+
+static void help_states(void) {
+        int i;
+
+        if (!arg_no_legend)
+                puts("Available unit load states:");
+        for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
+                puts(unit_load_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable unit active states:");
+        for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
+                puts(unit_active_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable automount unit substates:");
+        for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
+                puts(automount_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable busname unit substates:");
+        for (i = 0; i < _BUSNAME_STATE_MAX; i++)
+                puts(busname_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable device unit substates:");
+        for (i = 0; i < _DEVICE_STATE_MAX; i++)
+                puts(device_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable mount unit substates:");
+        for (i = 0; i < _MOUNT_STATE_MAX; i++)
+                puts(mount_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable path unit substates:");
+        for (i = 0; i < _PATH_STATE_MAX; i++)
+                puts(path_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable scope unit substates:");
+        for (i = 0; i < _SCOPE_STATE_MAX; i++)
+                puts(scope_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable service unit substates:");
+        for (i = 0; i < _SERVICE_STATE_MAX; i++)
+                puts(service_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable slice unit substates:");
+        for (i = 0; i < _SLICE_STATE_MAX; i++)
+                puts(slice_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable snapshot unit substates:");
+        for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
+                puts(snapshot_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable socket unit substates:");
+        for (i = 0; i < _SOCKET_STATE_MAX; i++)
+                puts(socket_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable swap unit substates:");
+        for (i = 0; i < _SWAP_STATE_MAX; i++)
+                puts(swap_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable target unit substates:");
+        for (i = 0; i < _TARGET_STATE_MAX; i++)
+                puts(target_state_to_string(i));
+
+        if (!arg_no_legend)
+                puts("\nAvailable timer unit substates:");
+        for (i = 0; i < _TIMER_STATE_MAX; i++)
+                puts(timer_state_to_string(i));
 }
 
 static int systemctl_parse_argv(int argc, char *argv[]) {
@@ -6538,7 +6619,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 {}
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
@@ -6574,7 +6655,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 }
 
                                 if (unit_type_from_string(type) >= 0) {
-                                        if (strv_push(&arg_types, type))
+                                        if (strv_push(&arg_types, type) < 0)
                                                 return log_oom();
                                         type = NULL;
                                         continue;
@@ -6584,7 +6665,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                  * load states, but let's support this
                                  * in --types= too for compatibility
                                  * with old versions */
-                                if (unit_load_state_from_string(optarg) >= 0) {
+                                if (unit_load_state_from_string(type) >= 0) {
                                         if (strv_push(&arg_states, type) < 0)
                                                 return log_oom();
                                         type = NULL;
@@ -6695,7 +6776,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case 'l':
@@ -6786,14 +6869,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         size_t size;
 
                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                char *s;
+                                _cleanup_free_ char *s = NULL;
 
                                 s = strndup(word, size);
                                 if (!s)
                                         return log_oom();
 
-                                if (strv_consume(&arg_states, s) < 0)
+                                if (streq(s, "help")) {
+                                        help_states();
+                                        return 0;
+                                }
+
+                                if (strv_push(&arg_states, s) < 0)
                                         return log_oom();
+
+                                s = NULL;
                         }
                         break;
                 }
@@ -7004,7 +7094,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
@@ -7318,12 +7408,12 @@ static int talk_initctl(void) {
 static int systemctl_main(int argc, char *argv[]) {
 
         static const Verb verbs[] = {
-                { "list-units",            VERB_ANY, 1,        VERB_DEFAULT, list_units        },
-                { "list-unit-files",       VERB_ANY, 1,        0,            list_unit_files   },
-                { "list-sockets",          VERB_ANY, 1,        0,            list_sockets      },
-                { "list-timers",           VERB_ANY, 1,        0,            list_timers       },
-                { "list-jobs",             VERB_ANY, 1,        0,            list_jobs         },
-                { "list-machines",         VERB_ANY, 1,        0,            list_machines     },
+                { "list-units",            VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units        },
+                { "list-unit-files",       VERB_ANY, VERB_ANY, 0,            list_unit_files   },
+                { "list-sockets",          VERB_ANY, VERB_ANY, 0,            list_sockets      },
+                { "list-timers",           VERB_ANY, VERB_ANY, 0,            list_timers       },
+                { "list-jobs",             VERB_ANY, VERB_ANY, 0,            list_jobs         },
+                { "list-machines",         VERB_ANY, VERB_ANY, 0,            list_machines     },
                 { "clear-jobs",            VERB_ANY, 1,        0,            daemon_reload     },
                 { "cancel",                2,        VERB_ANY, 0,            cancel_job        },
                 { "start",                 2,        VERB_ANY, 0,            start_unit        },
@@ -7487,6 +7577,10 @@ static int logind_schedule_shutdown(void) {
         case ACTION_KEXEC:
                 action = "kexec";
                 break;
+        case ACTION_EXIT:
+                action = "exit";
+                break;
+        case ACTION_REBOOT:
         default:
                 action = "reboot";
                 break;
@@ -7693,6 +7787,7 @@ finish:
         strv_free(arg_properties);
 
         strv_free(arg_wall);
+        free(arg_root);
 
         release_busses();