X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=d16c673dcd4a772e2b460269b80db1421f3aa426;hp=d356686f78e482c23e3717c47d040e8212a4d0dd;hb=33f6c497f3f2da15b94da9140f77aefac92e2866;hpb=8b5e2af10830d55b2032e6c79d0cd1f959bb5b7f diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d356686f7..d16c673dc 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -72,7 +72,7 @@ #include "bus-util.h" #include "bus-message.h" #include "bus-error.h" -#include "bus-errors.h" +#include "bus-common-errors.h" #include "mkdir.h" static char **arg_types = NULL; @@ -752,7 +752,7 @@ struct socket_info { /* Note: triggered is a list here, although it almost certainly * will always be one unit. Nevertheless, dbus API allows for multiple - * values, so let's follow that.*/ + * values, so let's follow that. */ char** triggered; /* The strv above is shared. free is set only in the first one. */ @@ -2270,6 +2270,92 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) { return b; } +static void warn_unit_file_changed(const char *name) { + log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.", + ansi_highlight_red(), + ansi_highlight_off(), + name, + arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); +} + +static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) { + char **p; + + assert(lp); + assert(unit_name); + assert(unit_path); + + STRV_FOREACH(p, lp->unit_path) { + char *path; + + path = path_join(arg_root, *p, unit_name); + if (!path) + return log_oom(); + + if (access(path, F_OK) == 0) { + *unit_path = path; + return 1; + } + + free(path); + } + + return 0; +} + +static int unit_find_path(sd_bus *bus, const char *unit_name, const char *template, bool avoid_bus_cache, LookupPaths *lp, char **path) { + int r; + + assert(unit_name); + assert(path); + assert(lp); + + if (!avoid_bus_cache && !unit_name_is_template(unit_name)) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *tmp_path = NULL; + + unit = unit_dbus_path_from_name(unit_name); + if (!unit) + return log_oom(); + + if (need_daemon_reload(bus, unit_name) > 0) { + warn_unit_file_changed(unit_name); + return 0; + } + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "FragmentPath", + &error, + &tmp_path); + if (r < 0) { + log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r)); + return 0; + } + + if (isempty(tmp_path)) { + log_warning("%s ignored: not found", template); + return 0; + } + + *path = tmp_path; + tmp_path = NULL; + + return 1; + } else { + r = unit_file_find_path(lp, template, path); + if (r == 0) + log_warning("%s ignored: not found", template); + return r; + } + + return 0; +} + typedef struct WaitData { Set *set; @@ -2380,12 +2466,18 @@ static int check_wait_response(WaitData *d) { assert(d->result); if (!arg_quiet) { - if (streq(d->result, "timeout")) - log_error("Job for %s timed out.", strna(d->name)); - else if (streq(d->result, "canceled")) + if (streq(d->result, "canceled")) log_error("Job for %s canceled.", strna(d->name)); + else if (streq(d->result, "timeout")) + log_error("Job for %s timed out.", strna(d->name)); else if (streq(d->result, "dependency")) log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name)); + else if (streq(d->result, "invalid")) + log_error("Job for %s invalid.", strna(d->name)); + else if (streq(d->result, "assert")) + log_error("Assertion failed on job for %s.", strna(d->name)); + else if (streq(d->result, "unsupported")) + log_error("Operation on or unit type of %s not supported on this system.", strna(d->name)); else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { if (d->name) { bool quotes; @@ -2400,12 +2492,18 @@ static int check_wait_response(WaitData *d) { } } - if (streq(d->result, "timeout")) - r = -ETIME; - else if (streq(d->result, "canceled")) + if (streq(d->result, "canceled")) r = -ECANCELED; + else if (streq(d->result, "timeout")) + r = -ETIME; else if (streq(d->result, "dependency")) r = -EIO; + else if (streq(d->result, "invalid")) + r = -ENOEXEC; + else if (streq(d->result, "assert")) + r = -EPROTO; + else if (streq(d->result, "unsupported")) + r = -ENOTSUP; else if (!streq(d->result, "done") && !streq(d->result, "skipped")) r = -EIO; @@ -2664,8 +2762,7 @@ static int start_unit_one( return bus_log_parse_error(r); if (need_daemon_reload(bus, name) > 0) - log_warning("Warning: Unit file of %s changed on disk, 'systemctl%s daemon-reload' recommended.", - name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + warn_unit_file_changed(name); if (s) { char *p; @@ -3594,10 +3691,7 @@ static void print_status_info( } if (i->need_daemon_reload) - printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n", - ansi_highlight_red(), - ansi_highlight_off(), - arg_scope == UNIT_FILE_SYSTEM ? "" : "--user "); + warn_unit_file_changed(i->id); } static void show_unit_help(UnitStatusInfo *i) { @@ -4600,8 +4694,7 @@ static int cat(sd_bus *bus, char **args) { return log_oom(); if (need_daemon_reload(bus, *name) > 0) - log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.", - *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + warn_unit_file_changed(*name); r = sd_bus_get_property_string( bus, @@ -4641,7 +4734,7 @@ static int cat(sd_bus *bus, char **args) { ansi_highlight_off()); fflush(stdout); - r = copy_file_fd(fragment_path, STDOUT_FILENO); + r = copy_file_fd(fragment_path, STDOUT_FILENO, false); if (r < 0) { log_warning_errno(r, "Failed to cat %s: %m", fragment_path); continue; @@ -4656,7 +4749,7 @@ static int cat(sd_bus *bus, char **args) { ansi_highlight_off()); fflush(stdout); - r = copy_file_fd(*path, STDOUT_FILENO); + r = copy_file_fd(*path, STDOUT_FILENO, false); if (r < 0) { log_warning_errno(r, "Failed to cat %s: %m", *path); continue; @@ -5143,7 +5236,7 @@ static int enable_sysv_units(const char *verb, char **args) { int r = 0; #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG) - unsigned f = 1, t = 1; + unsigned f = 0; _cleanup_lookup_paths_free_ LookupPaths paths = {}; if (arg_scope != UNIT_FILE_SYSTEM) @@ -5162,7 +5255,7 @@ static int enable_sysv_units(const char *verb, char **args) { return r; r = 0; - for (f = 0; args[f]; f++) { + while (args[f]) { const char *name; _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL; bool found_native = false, found_sysv; @@ -5173,7 +5266,7 @@ static int enable_sysv_units(const char *verb, char **args) { pid_t pid; siginfo_t status; - name = args[f]; + name = args[f++]; if (!endswith(name, ".service")) continue; @@ -5205,9 +5298,6 @@ static int enable_sysv_units(const char *verb, char **args) { if (!found_sysv) continue; - /* Mark this entry, so that we don't try enabling it as native unit */ - args[f] = (char*) ""; - log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name); if (!isempty(arg_root)) @@ -5256,19 +5346,12 @@ static int enable_sysv_units(const char *verb, char **args) { return -EINVAL; } else return -EPROTO; - } - /* Drop all SysV units */ - for (f = 0, t = 0; args[f]; f++) { - - if (isempty(args[f])) - continue; - - args[t++] = args[f]; + /* Remove this entry, so that we don't try enabling it as native unit */ + assert(f > 0 && streq(args[f-1], name)); + assert_se(strv_remove(args + f - 1, name)); } - args[t] = NULL; - #endif return r; } @@ -5714,42 +5797,17 @@ static int is_system_running(sd_bus *bus, char **args) { return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE; } -static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) { - char **p; - - assert(lp); - assert(unit_name); - assert(unit_path); - - STRV_FOREACH(p, lp->unit_path) { - char *path; - - path = path_join(arg_root, *p, unit_name); - if (!path) - return log_oom(); - - if (access(path, F_OK) == 0) { - *unit_path = path; - return 1; - } - - free(path); - } - - return 0; -} - static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) { - int r; char *t; + int r; assert(new_path); assert(original_path); assert(ret_tmp_fn); - t = tempfn_random(new_path); - if (!t) - return log_oom(); + r = tempfn_random(new_path, &t); + if (r < 0) + return log_error_errno(r, "Failed to determine temporary filename for %s: %m", new_path); r = mkdir_parents(new_path, 0755); if (r < 0) { @@ -6039,6 +6097,8 @@ static int run_editor(char **paths) { static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { _cleanup_free_ char *user_home = NULL; _cleanup_free_ char *user_runtime = NULL; + _cleanup_lookup_paths_free_ LookupPaths lp = {}; + bool avoid_bus_cache; char **name; int r; @@ -6048,115 +6108,54 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { if (arg_scope == UNIT_FILE_USER) { r = user_config_home(&user_home); if (r < 0) - return log_oom(); - else if (r == 0) { - log_error("Cannot edit units for the user instance: home directory unknown"); - return -1; - } + return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m"); + else if (r == 0) + return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_CONFIG_HOME and $HOME are not set."); r = user_runtime_dir(&user_runtime); if (r < 0) - return log_oom(); - else if (r == 0) { - log_error("Cannot edit units for the user instance: runtime directory unknown"); - return -1; - } + return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m"); + else if (r == 0) + return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_RUNTIME_DIR is not set."); } - if (!bus || avoid_bus()) { - _cleanup_lookup_paths_free_ LookupPaths lp = {}; - - /* If there is no bus, we try to find the units by testing each available directory - * according to the scope. - */ - r = lookup_paths_init(&lp, - arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER, - arg_scope == UNIT_FILE_USER, - arg_root, - NULL, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Failed get lookup paths: %m"); - return r; - } - - STRV_FOREACH(name, names) { - _cleanup_free_ char *path = NULL; - char *new_path, *tmp_path; - - r = unit_file_find_path(&lp, *name, &path); - if (r < 0) - return r; - if (r == 0) { - log_warning("%s ignored: not found", *name); - continue; - } + r = lookup_paths_init(&lp, + arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER, + arg_scope == UNIT_FILE_USER, + arg_root, + NULL, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed get lookup paths: %m"); - if (arg_full) - r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path); - else - r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path); + avoid_bus_cache = !bus || avoid_bus(); - if (r < 0) - continue; + STRV_FOREACH(name, names) { + _cleanup_free_ char *path = NULL; + _cleanup_free_ char *template = NULL; + char *new_path, *tmp_path; - r = strv_push(paths, new_path); - if (r < 0) - return log_oom(); + template = unit_name_template(*name); + if (!template) + return log_oom(); - r = strv_push(paths, tmp_path); - if (r < 0) - return log_oom(); + r = unit_find_path(bus, *name, template, avoid_bus_cache, &lp, &path); + if (r < 0) + return r; + else if (r == 0) { + continue; } - } else { - STRV_FOREACH(name, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *fragment_path = NULL; - _cleanup_free_ char *unit = NULL; - char *new_path, *tmp_path; - - unit = unit_dbus_path_from_name(*name); - if (!unit) - return log_oom(); - if (need_daemon_reload(bus, *name) > 0) { - log_warning("%s ignored: unit file changed on disk. Run 'systemctl%s daemon-reload'.", - *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); - continue; - } - - r = sd_bus_get_property_string( - bus, - "org.freedesktop.systemd1", - unit, - "org.freedesktop.systemd1.Unit", - "FragmentPath", - &error, - &fragment_path); - if (r < 0) { - log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r)); - continue; - } - - if (isempty(fragment_path)) { - log_warning("%s ignored: not found", *name); - continue; - } - - if (arg_full) - r = unit_file_create_copy(*name, fragment_path, user_home, user_runtime, &new_path, &tmp_path); - else - r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path); - if (r < 0) - continue; + if (arg_full) + r = unit_file_create_copy(template, path, user_home, user_runtime, &new_path, &tmp_path); + else + r = unit_file_create_drop_in(template, user_home, user_runtime, &new_path, &tmp_path); - r = strv_push(paths, new_path); - if (r < 0) - return log_oom(); + if (r < 0) + continue; - r = strv_push(paths, tmp_path); - if (r < 0) - return log_oom(); - } + r = strv_push_pair(paths, new_path, tmp_path); + if (r < 0) + return log_oom(); } return 0; @@ -7246,12 +7245,9 @@ static int talk_initctl(void) { return -errno; } - errno = 0; - r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); - if (r) { - log_error_errno(errno, "Failed to write to "INIT_FIFO": %m"); - return errno > 0 ? -errno : -EIO; - } + r = loop_write(fd, &request, sizeof(request), false); + if (r < 0) + return log_error_errno(r, "Failed to write to "INIT_FIFO": %m"); return 1; }