if (r < 0)
return r;
- i = new0(UnitFileInstallInfo, 1);
+ i = new(UnitFileInstallInfo, 1);
if (!i)
return -ENOMEM;
- i->type = _UNIT_FILE_TYPE_INVALID;
- i->auxiliary = auxiliary;
+
+ *i = (UnitFileInstallInfo) {
+ .type = _UNIT_FILE_TYPE_INVALID,
+ .auxiliary = auxiliary,
+ };
i->name = strdup(name);
if (!i->name) {
STRV_FOREACH(p, paths->search_path) {
char *path;
- path = path_join(NULL, *p, dropin_dir_name);
+ path = path_join(*p, dropin_dir_name);
if (!path)
return -ENOMEM;
STRV_FOREACH(p, paths->search_path) {
char *path;
- path = path_join(NULL, *p, dropin_template_dir_name);
+ path = path_join(*p, dropin_template_dir_name);
if (!path)
return -ENOMEM;
if (strv_isempty(list))
return 0;
- if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) {
+ if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
UnitFileInstallInfo instance = {
.type = _UNIT_FILE_TYPE_INVALID,
};
_cleanup_free_ char *path = NULL;
+ /* If this is a template, and we have no instance, don't do anything */
+ if (!i->default_instance)
+ return 1;
+
r = unit_name_replace_instance(i->name, i->default_instance, &buf);
if (r < 0)
return r;
InstallContext *c,
const LookupPaths *paths,
Set **remove_symlinks_to,
+ const char *config_path,
UnitFileChange **changes,
size_t *n_changes) {
assert(c);
assert(paths);
+ assert(config_path);
/* Marks all items for removal */
size_t n_todo = 0, n_allocated = 0;
const char *config_path;
char **i;
- bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
+ bool dry_run;
int r, q;
assert(scope >= 0);
if (r < 0)
return r;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
+
+ dry_run = !!(flags & UNIT_FILE_DRY_RUN);
+
STRV_FOREACH(i, files) {
+ _cleanup_free_ char *path = NULL;
+
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
return -EINVAL;
- FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
- _cleanup_free_ char *path = NULL;
-
- path = path_make_absolute(*i, config_path);
- if (!path)
- return -ENOMEM;
+ path = path_make_absolute(*i, config_path);
+ if (!path)
+ return -ENOMEM;
- r = null_or_empty_path(path);
- if (r == -ENOENT)
- continue;
- if (r < 0)
- return r;
- if (r == 0)
- continue;
+ r = null_or_empty_path(path);
+ if (r == -ENOENT)
+ continue;
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
- if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
- return -ENOMEM;
+ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+ return -ENOMEM;
- todo[n_todo] = strdup(*i);
- if (!todo[n_todo])
- return -ENOMEM;
+ todo[n_todo] = strdup(*i);
+ if (!todo[n_todo])
+ return -ENOMEM;
- n_todo++;
- }
+ n_todo++;
}
strv_uniq(todo);
r = 0;
- FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
- STRV_FOREACH(i, todo) {
- _cleanup_free_ char *path = NULL;
- const char *rp;
-
- path = path_make_absolute(*i, config_path);
- if (!path)
- return -ENOMEM;
+ STRV_FOREACH(i, todo) {
+ _cleanup_free_ char *path = NULL;
+ const char *rp;
- if (!dry_run && unlink(path) < 0) {
- if (errno != ENOENT) {
- if (r >= 0)
- r = -errno;
- unit_file_changes_add(changes, n_changes, -errno, path, NULL);
- }
+ path = path_make_absolute(*i, config_path);
+ if (!path)
+ return -ENOMEM;
- continue;
+ if (!dry_run && unlink(path) < 0) {
+ if (errno != ENOENT) {
+ if (r >= 0)
+ r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, path, NULL);
}
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-
- rp = skip_root(&paths, path);
- q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
- if (q < 0)
- return q;
+ continue;
}
- q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
- if (r >= 0)
- r = q;
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+ rp = skip_root(&paths, path);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
+ if (q < 0)
+ return q;
}
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
+ if (r >= 0)
+ r = q;
+
return r;
}
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
const char *config_path;
char **i;
int r;
if (r < 0)
return r;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
+
STRV_FOREACH(i, files) {
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
return -EINVAL;
return r;
}
- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, changes, n_changes);
+ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
if (r < 0)
return r;
- FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
- r = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
- if (r < 0)
- return r;
- }
-
- return 0;
+ return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
}
int unit_file_reenable(
static int execute_preset(
UnitFileScope scope,
- UnitFileFlags flags,
InstallContext *plus,
InstallContext *minus,
const LookupPaths *paths,
+ const char *config_path,
char **files,
UnitFilePresetMode mode,
+ bool force,
UnitFileChange **changes,
size_t *n_changes) {
- const char *config_path;
- bool force = !!(flags & UNIT_FILE_FORCE);
- bool runtime = !!(flags & UNIT_FILE_RUNTIME);
- int r = 0, q;
+ int r;
assert(plus);
assert(minus);
assert(paths);
+ assert(config_path);
if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- q = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, changes, n_changes);
- if (q < 0)
- return q;
+ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
+ if (r < 0)
+ return r;
- FOREACH_STRING(config_path, paths->runtime_config, paths->persistent_config) {
- q = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
- if (r == 0)
- r = q;
- }
- }
+ r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
+ } else
+ r = 0;
if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
+ int q;
+
/* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(scope, plus, paths,
- runtime ? paths->runtime_config : paths->persistent_config,
- force, SEARCH_LOAD, changes, n_changes);
- if (r == 0)
- r = q;
+ q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
+ if (r >= 0) {
+ if (q < 0)
+ r = q;
+ else
+ r += q;
+ }
}
return r;
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_(presets_freep) Presets presets = {};
+ const char *config_path;
char **i;
int r;
if (r < 0)
return r;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
+
r = read_presets(scope, root_dir, &presets);
if (r < 0)
return r;
return r;
}
- return execute_preset(scope, flags, &plus, &minus, &paths, files, mode, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
}
int unit_file_preset_all(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_(presets_freep) Presets presets = {};
+ const char *config_path = NULL;
char **i;
int r;
if (r < 0)
return r;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
+
r = read_presets(scope, root_dir, &presets);
if (r < 0)
return r;
}
FOREACH_DIRENT(de, d, return -errno) {
+
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
}
}
- return execute_preset(scope, flags, &plus, &minus, &paths, NULL, mode, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
}
static void unit_file_list_free_one(UnitFileList *f) {
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2013 Marc-Antoine Perennou
-***/
#include <errno.h>
#include <fcntl.h>
#include "escape.h"
#include "exit-status.h"
#include "fd-util.h"
-#include "fileio.h"
#include "format-util.h"
#include "fs-util.h"
#include "glob-util.h"
#include "string-table.h"
#include "strv.h"
#include "terminal-util.h"
+#include "tmpfile-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "user-util.h"
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
}
-static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
+static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
char **p;
assert(lp);
_cleanup_free_ char *path = NULL, *lpath = NULL;
int r;
- path = path_join(NULL, *p, unit_name);
+ path = path_join(*p, unit_name);
if (!path)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to access path \"%s\": %m", path);
- if (unit_path)
- *unit_path = TAKE_PTR(lpath);
+ if (ret_unit_path)
+ *ret_unit_path = TAKE_PTR(lpath);
return 1;
}
+ if (ret_unit_path)
+ *ret_unit_path = NULL;
+
return 0;
}
static int unit_find_template_path(
const char *unit_name,
LookupPaths *lp,
- char **fragment_path,
- char **template) {
+ char **ret_fragment_path,
+ char **ret_template) {
- _cleanup_free_ char *_template = NULL;
+ _cleanup_free_ char *t = NULL, *f = NULL;
int r;
/* Returns 1 if a fragment was found, 0 if not found, negative on error. */
- r = unit_file_find_path(lp, unit_name, fragment_path);
- if (r != 0)
- return r; /* error or found a real unit */
+ r = unit_file_find_path(lp, unit_name, &f);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ if (ret_fragment_path)
+ *ret_fragment_path = TAKE_PTR(f);
+ if (ret_template)
+ *ret_template = NULL;
+ return r; /* found a real unit */
+ }
+
+ r = unit_name_template(unit_name, &t);
+ if (r == -EINVAL) {
+ if (ret_fragment_path)
+ *ret_fragment_path = NULL;
+ if (ret_template)
+ *ret_template = NULL;
- r = unit_name_template(unit_name, &_template);
- if (r == -EINVAL)
return 0; /* not a template, does not exist */
+ }
if (r < 0)
return log_error_errno(r, "Failed to determine template name: %m");
- r = unit_file_find_path(lp, _template, fragment_path);
+ r = unit_file_find_path(lp, t, ret_fragment_path);
if (r < 0)
return r;
- if (template)
- *template = TAKE_PTR(_template);
+ if (ret_template)
+ *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
return r;
}
sd_bus *bus,
const char *unit_name,
LookupPaths *lp,
- char **fragment_path,
- char ***dropin_paths) {
+ bool force_client_side,
+ char **ret_fragment_path,
+ char ***ret_dropin_paths) {
- _cleanup_free_ char *path = NULL;
_cleanup_strv_free_ char **dropins = NULL;
+ _cleanup_free_ char *path = NULL;
int r;
/**
- * Finds where the unit is defined on disk. Returns 0 if the unit
- * is not found. Returns 1 if it is found, and sets
- * - the path to the unit in *path, if it exists on disk,
- * - and a strv of existing drop-ins in *dropins,
- * if the arg is not NULL and any dropins were found.
+ * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is found, and
+ * sets:
+ * - the path to the unit in *ret_frament_path, if it exists on disk,
+ * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins were found.
+ *
+ * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for some
+ * reason (the latter only applies if we are going through the service manager)
*/
assert(unit_name);
- assert(fragment_path);
+ assert(ret_fragment_path);
assert(lp);
- if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+ /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
+ if (!force_client_side &&
+ !install_client_side() &&
+ !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *unit = NULL;
+ _cleanup_free_ char *load_state = NULL, *unit = NULL;
unit = unit_dbus_path_from_name(unit_name);
if (!unit)
return log_oom();
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ unit,
+ "org.freedesktop.systemd1.Unit",
+ "LoadState",
+ &error,
+ &load_state);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get LoadState: %s", bus_error_message(&error, r));
+
+ if (streq(load_state, "masked"))
+ return -ERFKILL;
+ if (streq(load_state, "not-found")) {
+ r = 0;
+ goto not_found;
+ }
+ if (!streq(load_state, "loaded"))
+ return -EKEYREJECTED;
+
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
if (r < 0)
return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
- if (dropin_paths) {
+ if (ret_dropin_paths) {
r = sd_bus_get_property_strv(
bus,
"org.freedesktop.systemd1",
r = unit_find_template_path(unit_name, lp, &path, &template);
if (r < 0)
return r;
-
if (r > 0) {
if (null_or_empty_path(path))
/* The template is masked. Let's cut the process short. */
if (r < 0)
return log_error_errno(r, "Failed to add unit name: %m");
- if (dropin_paths) {
- r = unit_file_find_dropin_conf_paths(arg_root, lp->search_path,
- NULL, names, &dropins);
+ if (ret_dropin_paths) {
+ r = unit_file_find_dropin_conf_paths(arg_root, lp->search_path, NULL, names, &dropins);
if (r < 0)
return r;
}
}
- r = 0;
+ r = 0;
if (!isempty(path)) {
- *fragment_path = TAKE_PTR(path);
+ *ret_fragment_path = TAKE_PTR(path);
r = 1;
- }
+ } else
+ *ret_fragment_path = NULL;
- if (dropin_paths && !strv_isempty(dropins)) {
- *dropin_paths = TAKE_PTR(dropins);
- r = 1;
+ if (ret_dropin_paths) {
+ if (!strv_isempty(dropins)) {
+ *ret_dropin_paths = TAKE_PTR(dropins);
+ r = 1;
+ } else
+ *ret_dropin_paths = NULL;
}
+
not_found:
if (r == 0 && !arg_force)
log_error("No files found for %s.", unit_name);
}
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ const char *path, *interface, *active_state = NULL, *job_path = NULL;
WaitContext *c = userdata;
- const char *path;
+ bool is_failed;
int r;
+ /* Called whenever we get a PropertiesChanged signal. Checks if ActiveState changed to inactive/failed.
+ *
+ * Signal parameters: (s interface, a{sv} changed_properties, as invalidated_properties) */
+
path = sd_bus_message_get_path(m);
if (!set_contains(c->unit_paths, path))
return 0;
- /* Check if ActiveState changed to inactive/failed */
- /* (s interface, a{sv} changed_properties, as invalidated_properties) */
- r = sd_bus_message_skip(m, "s");
+ r = sd_bus_message_read(m, "s", &interface);
if (r < 0)
return bus_log_parse_error(r);
+ if (!streq(interface, "org.freedesktop.systemd1.Unit")) /* ActiveState is on the Unit interface */
+ return 0;
+
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+ for (;;) {
const char *s;
- r = sd_bus_message_read(m, "s", &s);
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
+ if (r < 0)
+ return bus_log_parse_error(r);
+ if (r == 0) /* end of array */
+ break;
+
+ r = sd_bus_message_read(m, "s", &s); /* Property name */
if (r < 0)
return bus_log_parse_error(r);
if (streq(s, "ActiveState")) {
- bool is_failed;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s");
+ r = sd_bus_message_read(m, "v", "s", &active_state);
if (r < 0)
return bus_log_parse_error(r);
- r = sd_bus_message_read(m, "s", &s);
+ if (job_path) /* Found everything we need */
+ break;
+
+ } else if (streq(s, "Job")) {
+ uint32_t job_id;
+
+ r = sd_bus_message_read(m, "v", "(uo)", &job_id, &job_path);
if (r < 0)
return bus_log_parse_error(r);
- is_failed = streq(s, "failed");
- if (streq(s, "inactive") || is_failed) {
- log_debug("%s became %s, dropping from --wait tracking", path, s);
- free(set_remove(c->unit_paths, path));
- c->any_failed = c->any_failed || is_failed;
- } else
- log_debug("ActiveState on %s changed to %s", path, s);
+ /* There's still a job pending for this unit, let's ignore this for now, and return right-away. */
+ if (job_id != 0)
+ return 0;
+
+ if (active_state) /* Found everything we need */
+ break;
- break; /* no need to dissect the rest of the message */
} else {
- /* other property */
- r = sd_bus_message_skip(m, "v");
+ r = sd_bus_message_skip(m, "v"); /* Other property */
if (r < 0)
return bus_log_parse_error(r);
}
+
r = sd_bus_message_exit_container(m);
if (r < 0)
return bus_log_parse_error(r);
}
- if (r < 0)
- return bus_log_parse_error(r);
+
+ /* If this didn't contain the ActiveState property we can't do anything */
+ if (!active_state)
+ return 0;
+
+ is_failed = streq(active_state, "failed");
+ if (streq(active_state, "inactive") || is_failed) {
+ log_debug("%s became %s, dropping from --wait tracking", path, active_state);
+ free(set_remove(c->unit_paths, path));
+ c->any_failed = c->any_failed || is_failed;
+ } else
+ log_debug("ActiveState on %s changed to %s", path, active_state);
if (set_isempty(c->unit_paths))
sd_event_exit(c->event, EXIT_SUCCESS);
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_(wait_context_free) WaitContext wait_context = {};
const char *method, *mode, *one_name, *suffix = NULL;
+ _cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
_cleanup_strv_free_ char **names = NULL;
int r, ret = EXIT_SUCCESS;
sd_bus *bus;
r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
if (ret == EXIT_SUCCESS && r < 0)
ret = translate_bus_error_to_exit_status(r, &error);
+
+ if (r >= 0 && streq(method, "StopUnit")) {
+ r = strv_push(&stopped_units, *name);
+ if (r < 0)
+ return log_oom();
+ }
}
if (!arg_no_block) {
/* When stopping units, warn if they can still be triggered by
* another active unit (socket, path, timer) */
- if (!arg_quiet && streq(method, "StopUnit"))
- STRV_FOREACH(name, names)
+ if (!arg_quiet)
+ STRV_FOREACH(name, stopped_units)
(void) check_triggering_units(bus, *name);
}
return -EINVAL;
}
- kernel = path_join(NULL, where, e->kernel);
+ kernel = path_join(where, e->kernel);
if (!strv_isempty(e->initrd))
- initrd = path_join(NULL, where, *e->initrd);
+ initrd = path_join(where, *e->initrd);
options = strv_join(e->options, " ");
if (!options)
return log_oom();
if (arg_dry_run)
return 0;
- r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+ r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
if (r < 0)
return r;
if (r == 0) {
_cleanup_free_ char *fragment_path = NULL;
_cleanup_strv_free_ char **dropin_paths = NULL;
- r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
+ r = unit_find_paths(bus, *name, &lp, false, &fragment_path, &dropin_paths);
if (r == -ERFKILL) {
- printf("%s# unit %s is masked%s\n",
+ printf("%s# Unit %s is masked%s.\n",
+ ansi_highlight_magenta(),
+ *name,
+ ansi_normal());
+ continue;
+ }
+ if (r == -EKEYREJECTED) {
+ printf("%s# Unit %s could not be loaded.%s\n",
ansi_highlight_magenta(),
*name,
ansi_normal());
}
if (r < 0)
return r;
- else if (r == 0)
+ if (r == 0)
return -ENOENT;
if (first)
if (!arg_quiet)
log_info("Executing: %s", l);
- j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+ j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
if (j < 0)
return j;
if (j == 0) {
}
if (carries_install_info == 0 && !ignore_carries_install_info)
- log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
- "settings in the [Install] section, and DefaultInstance for template units).\n"
- "This means they are not meant to be enabled using systemctl.\n"
- "Possible reasons for having this kind of units are:\n"
- "1) A unit may be statically enabled by being symlinked from another unit's\n"
- " .wants/ or .requires/ directory.\n"
- "2) A unit's purpose may be to act as a helper for some other unit which has\n"
- " a requirement dependency on it.\n"
- "3) A unit may be started when needed via activation (socket, path, timer,\n"
- " D-Bus, udev, scripted systemctl call, ...).\n"
- "4) In case of template units, the unit is meant to be enabled with some\n"
- " instance name specified.");
+ log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
+ "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
+ "units). This means they are not meant to be enabled using systemctl.\n \n"
+ "Possible reasons for having this kind of units are:\n"
+ "%1$s A unit may be statically enabled by being symlinked from another unit's\n"
+ " .wants/ or .requires/ directory.\n"
+ "%1$s A unit's purpose may be to act as a helper for some other unit which has\n"
+ " a requirement dependency on it.\n"
+ "%1$s A unit may be started when needed via activation (socket, path, timer,\n"
+ " D-Bus, udev, scripted systemctl call, ...).\n"
+ "%1$s In case of template units, the unit is meant to be enabled with some\n"
+ " instance name specified.",
+ special_glyph(BULLET));
if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
sd_bus *bus;
char **ret_new_path,
char **ret_tmp_path) {
- char *tmp_new_path, *tmp_tmp_path, *ending;
+ _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
+ const char *ending;
int r;
assert(unit_name);
assert(ret_tmp_path);
ending = strjoina(unit_name, suffix);
- r = get_file_to_edit(paths, ending, &tmp_new_path);
+ r = get_file_to_edit(paths, ending, &new_path);
if (r < 0)
return r;
- r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
- if (r < 0) {
- free(tmp_new_path);
+ r = create_edit_temp_file(new_path, new_path, &tmp_path);
+ if (r < 0)
return r;
- }
- *ret_new_path = tmp_new_path;
- *ret_tmp_path = tmp_tmp_path;
+ *ret_new_path = TAKE_PTR(new_path);
+ *ret_tmp_path = TAKE_PTR(tmp_path);
return 0;
}
char **ret_new_path,
char **ret_tmp_path) {
- char *tmp_new_path, *tmp_tmp_path;
+ _cleanup_free_ char *new_path = NULL, *tmp_path = NULL;
int r;
assert(fragment_path);
assert(ret_new_path);
assert(ret_tmp_path);
- r = get_file_to_edit(paths, unit_name, &tmp_new_path);
+ r = get_file_to_edit(paths, unit_name, &new_path);
if (r < 0)
return r;
- if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
+ if (!path_equal(fragment_path, new_path) && access(new_path, F_OK) >= 0) {
char response;
- r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
- if (r < 0) {
- free(tmp_new_path);
+ r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", new_path, fragment_path);
+ if (r < 0)
return r;
- }
- if (response != 'y') {
- log_warning("%s ignored", unit_name);
- free(tmp_new_path);
- return -EKEYREJECTED;
- }
+ if (response != 'y')
+ return log_warning_errno(SYNTHETIC_ERRNO(EKEYREJECTED), "%s skipped.", unit_name);
}
- r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
- if (r < 0) {
- free(tmp_new_path);
+ r = create_edit_temp_file(new_path, fragment_path, &tmp_path);
+ if (r < 0)
return r;
- }
- *ret_new_path = tmp_new_path;
- *ret_tmp_path = tmp_tmp_path;
+ *ret_new_path = TAKE_PTR(new_path);
+ *ret_tmp_path = TAKE_PTR(tmp_path);
return 0;
}
assert(paths);
- r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
+ r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_WAIT, NULL);
if (r < 0)
return r;
if (r == 0) {
n_editor_args = strv_length(editor_args);
argc += n_editor_args - 1;
}
+
args = newa(const char*, argc + 1);
if (n_editor_args > 0) {
args[i] = editor_args[i];
}
- STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
- args[i] = *tmp_path;
- i++;
- }
+ STRV_FOREACH_PAIR(original_path, tmp_path, paths)
+ args[i++] = *tmp_path;
args[i] = NULL;
if (n_editor_args > 0)
_cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL, *tmp_name = NULL;
const char *unit_name;
- r = unit_find_paths(bus, *name, &lp, &path, NULL);
+ r = unit_find_paths(bus, *name, &lp, false, &path, NULL);
+ if (r == -EKEYREJECTED) {
+ /* If loading of the unit failed server side complete, then the server won't tell us the unit
+ * file path. In that case, find the file client side. */
+ log_debug_errno(r, "Unit '%s' was not loaded correctly, retrying client-side.", *name);
+ r = unit_find_paths(bus, *name, &lp, true, &path, NULL);
+ }
+ if (r == -ERFKILL)
+ return log_error_errno(r, "Unit '%s' masked, cannot edit.", *name);
if (r < 0)
return r;
assert(!path);
if (!arg_force) {
- log_error("Run 'systemctl edit%s --force %s' to create a new unit.",
- arg_scope == UNIT_FILE_GLOBAL ? " --global" :
- arg_scope == UNIT_FILE_USER ? " --user" : "",
- *name);
+ log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.",
+ arg_scope == UNIT_FILE_GLOBAL ? " --global" :
+ arg_scope == UNIT_FILE_USER ? " --user" : "",
+ *name);
return -ENOENT;
}
r = strv_push_pair(paths, new_path, tmp_path);
if (r < 0)
return log_oom();
+
new_path = tmp_path = NULL;
}
r = unit_is_masked(bus, &lp, *tmp);
if (r < 0)
return r;
-
if (r > 0) {
log_error("Cannot edit %s: unit is masked.", *tmp);
return -EINVAL;
/* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
arg_ask_password = true;
- while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir.::", options, NULL)) >= 0)
switch (c) {
return log_oom();
break;
+ case '.':
+ /* Output an error mimicking getopt, and print a hint afterwards */
+ log_error("%s: invalid option -- '.'", program_invocation_name);
+ log_notice("Hint: to specify units starting with a dash, use \"--\":\n"
+ " %s [OPTIONS...] {COMMAND} -- -.%s ...",
+ program_invocation_name, optarg ?: "mount");
+ _fallthrough_;
+
case '?':
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--wait may not be combined with --no-block.");
- if (arg_runtime && STRPTR_IN_SET(argv[optind], "disable", "unmask", "preset", "preset-all"))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "--runtime cannot be used with %s",
- argv[optind]);
-
return 1;
}
/* Hmm, so some other init system is running, we need to forward this request to
* it. For now we simply guess that it is Upstart. */
+ (void) rlimit_nofile_safe();
execv(TELINIT, argv);
return log_error_errno(SYNTHETIC_ERRNO(EIO),
#endif
}
-static int run(int argc, char*argv[]) {
+static int run(int argc, char *argv[]) {
int r;
argv_cmdline = argv[0];