#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 "log.h"
#include "logs-show.h"
#include "macro.h"
+#include "main-func.h"
#include "mkdir.h"
#include "pager.h"
#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
+#include "pretty-print.h"
+#include "proc-cmdline.h"
#include "process-util.h"
#include "reboot-util.h"
#include "rlimit-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"
static bool arg_wait = false;
static bool arg_no_block = false;
static bool arg_no_legend = false;
-static bool arg_no_pager = false;
+static PagerFlags arg_pager_flags = 0;
static bool arg_no_wtmp = false;
static bool arg_no_sync = false;
static bool arg_no_wall = false;
return false;
}
-static int compare_unit_info(const void *a, const void *b) {
- const UnitInfo *u = a, *v = b;
+static int compare_unit_info(const UnitInfo *a, const UnitInfo *b) {
const char *d1, *d2;
int r;
/* First, order by machine */
- if (!u->machine && v->machine)
+ if (!a->machine && b->machine)
return -1;
- if (u->machine && !v->machine)
+ if (a->machine && !b->machine)
return 1;
- if (u->machine && v->machine) {
- r = strcasecmp(u->machine, v->machine);
+ if (a->machine && b->machine) {
+ r = strcasecmp(a->machine, b->machine);
if (r != 0)
return r;
}
/* Second, order by unit type */
- d1 = strrchr(u->id, '.');
- d2 = strrchr(v->id, '.');
+ d1 = strrchr(a->id, '.');
+ d2 = strrchr(b->id, '.');
if (d1 && d2) {
r = strcasecmp(d1, d2);
if (r != 0)
}
/* Third, order by name */
- return strcasecmp(u->id, v->id);
+ return strcasecmp(a->id, b->id);
}
static const char* unit_type_suffix(const char *name) {
const UnitInfo *u;
unsigned n_shown = 0;
int job_count = 0;
+ bool full = arg_full || FLAGS_SET(arg_pager_flags, PAGER_DISABLE);
max_id_len = STRLEN("UNIT");
load_len = STRLEN("LOAD");
printf("%-*.*s%s\n",
desc_len,
- !arg_full && arg_no_pager ? (int) desc_len : -1,
+ full ? -1 : (int) desc_len,
"DESCRIPTION",
ansi_normal());
}
printf("%-*.*s%s\n",
desc_len,
- !arg_full && arg_no_pager ? (int) desc_len : -1,
+ full ? -1 : (int) desc_len,
u->description,
off_underline);
}
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
- qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
+ typesafe_qsort(unit_infos, r, compare_unit_info);
return output_units_list(unit_infos, r);
}
};
static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
- int o;
+ int r;
assert(a);
assert(b);
if (a->machine && !b->machine)
return 1;
if (a->machine && b->machine) {
- o = strcasecmp(a->machine, b->machine);
- if (o != 0)
- return o;
+ r = strcasecmp(a->machine, b->machine);
+ if (r != 0)
+ return r;
}
- o = strcmp(a->path, b->path);
- if (o == 0)
- o = strcmp(a->type, b->type);
+ r = strcmp(a->path, b->path);
+ if (r == 0)
+ r = strcmp(a->type, b->type);
- return o;
+ return r;
}
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
listening = triggered = NULL; /* avoid cleanup */
}
- qsort_safe(socket_infos, cs, sizeof(struct socket_info),
- (__compar_fn_t) socket_info_compare);
+ typesafe_qsort(socket_infos, cs, socket_info_compare);
output_sockets_list(socket_infos, cs);
};
static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
- int o;
+ int r;
assert(a);
assert(b);
if (a->machine && !b->machine)
return 1;
if (a->machine && b->machine) {
- o = strcasecmp(a->machine, b->machine);
- if (o != 0)
- return o;
+ r = strcasecmp(a->machine, b->machine);
+ if (r != 0)
+ return r;
}
- if (a->next_elapse < b->next_elapse)
- return -1;
- if (a->next_elapse > b->next_elapse)
- return 1;
+ r = CMP(a->next_elapse, b->next_elapse);
+ if (r != 0)
+ return r;
return strcmp(a->id, b->id);
}
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
};
}
- qsort_safe(timer_infos, c, sizeof(struct timer_info),
- (__compar_fn_t) timer_info_compare);
+ typesafe_qsort(timer_infos, c, timer_info_compare);
output_timers_list(timer_infos, c);
return r;
}
-static int compare_unit_file_list(const void *a, const void *b) {
+static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
const char *d1, *d2;
- const UnitFileList *u = a, *v = b;
- d1 = strrchr(u->path, '.');
- d2 = strrchr(v->path, '.');
+ d1 = strrchr(a->path, '.');
+ d2 = strrchr(b->path, '.');
if (d1 && d2) {
int r;
return r;
}
- return strcasecmp(basename(u->path), basename(v->path));
+ return strcasecmp(basename(a->path), basename(b->path));
}
static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
return bus_log_parse_error(r);
}
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
- qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
+ typesafe_qsort(units, c, compare_unit_file_list);
output_unit_file_list(units, c);
if (install_client_side())
return 0;
}
-static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
+static int list_dependencies_print(const char *name, int level, unsigned branches, bool last) {
_cleanup_free_ char *n = NULL;
size_t max_len = MAX(columns(),20u);
size_t len = 0;
return 0;
}
-static int list_dependencies_compare(const void *_a, const void *_b) {
- const char **a = (const char**) _a, **b = (const char**) _b;
-
+static int list_dependencies_compare(char * const *a, char * const *b) {
if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
return 1;
if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
const char *name,
int level,
char ***units,
- unsigned int branches) {
+ unsigned branches) {
_cleanup_strv_free_ char **deps = NULL;
char **c;
if (r < 0)
return r;
- qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+ typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
STRV_FOREACH(c, deps) {
if (strv_contains(*units, *c)) {
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
puts(u);
free(machine_infos);
}
-static int compare_machine_info(const void *a, const void *b) {
- const struct machine_info *u = a, *v = b;
+static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
+ int r;
- if (u->is_host != v->is_host)
- return u->is_host > v->is_host ? -1 : 1;
+ r = CMP(b->is_host, a->is_host);
+ if (r != 0)
+ return r;
- return strcasecmp(u->name, v->name);
+ return strcasecmp(a->name, b->name);
}
static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
- qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
+ typesafe_qsort(machine_infos, r, compare_machine_info);
output_machines_list(machine_infos, r);
free_machines_list(machine_infos, r);
return;
}
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
id_len = STRLEN("JOB");
unit_len = STRLEN("UNIT");
if (r < 0)
return bus_log_parse_error(r);
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
output_jobs_list(bus, jobs, c, skipped);
return 0;
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 start_unit(int argc, char *argv[], void *userdata) {
_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_strv_free_ char **names = NULL;
+ int r, ret = EXIT_SUCCESS;
sd_bus *bus;
- _cleanup_(wait_context_free) WaitContext wait_context = {};
char **name;
- int r = 0;
if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
log_error("--wait may only be used with the 'start' or 'restart' commands.");
one_name = action_table[arg_action].target;
}
- if (one_name)
- names = strv_new(one_name, NULL);
- else {
+ if (one_name) {
+ names = strv_new(one_name);
+ if (!names)
+ return log_oom();
+ } else {
r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int q;
- q = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
- if (r >= 0 && q < 0)
- r = translate_bus_error_to_exit_status(q, &error);
+ 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 (!arg_no_block) {
- int q, arg_count = 0;
const char* extra_args[4] = {};
+ int arg_count = 0;
if (arg_scope != UNIT_FILE_SYSTEM)
extra_args[arg_count++] = "--user";
extra_args[arg_count++] = arg_host;
}
- q = bus_wait_for_jobs(w, arg_quiet, extra_args);
- if (q < 0)
- return q;
+ r = bus_wait_for_jobs(w, arg_quiet, extra_args);
+ if (r < 0)
+ return r;
/* When stopping units, warn if they can still be triggered by
* another active unit (socket, path, timer) */
(void) check_triggering_units(bus, *name);
}
- if (r >= 0 && arg_wait && !set_isempty(wait_context.unit_paths)) {
- int q;
- q = sd_event_loop(wait_context.event);
- if (q < 0)
- return log_error_errno(q, "Failed to run event loop: %m");
+ if (ret == EXIT_SUCCESS && arg_wait && !set_isempty(wait_context.unit_paths)) {
+ r = sd_event_loop(wait_context.event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
if (wait_context.any_failed)
- r = EXIT_FAILURE;
+ ret = EXIT_FAILURE;
}
- return r;
+ return ret;
}
#if ENABLE_LOGIND
if (access(KEXEC, X_OK) < 0)
return log_error_errno(errno, KEXEC" is not available: %m");
- r = find_esp_and_warn(arg_esp_path, false, &where, NULL, NULL, NULL, NULL);
- if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn about this case */
+ r = find_default_boot_entry(arg_esp_path, &where, &config, &e);
+ if (r == -ENOKEY) /* find_default_boot_entry() doesn't warn about this case */
return log_error_errno(r, "Cannot find the ESP partition mount point.");
- if (r < 0) /* But it logs about all these cases, hence don't log here again */
- return r;
-
- r = boot_entries_load_config(where, &config);
if (r < 0)
- return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", where);
-
- if (config.default_entry < 0) {
- log_error("No entry suitable as default, refusing to guess.");
- return -ENOENT;
- }
- e = &config.entries[config.default_entry];
+ /* But it logs about all these cases, hence don't log here again */
+ return r;
if (strv_length(e->initrd) > 1) {
log_error("Boot entry specifies multiple initrds, which is not supported currently.");
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();
static int start_system_special(int argc, char *argv[], void *userdata) {
/* Like start_special above, but raises an error when running in user mode */
- if (arg_scope != UNIT_FILE_SYSTEM) {
- log_error("Bad action for %s mode.",
- arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
- return -EINVAL;
- }
+ if (arg_scope != UNIT_FILE_SYSTEM)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Bad action for %s mode.",
+ arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
return start_special(argc, argv, userdata);
}
return 0;
}
-#define print_prop(name, fmt, ...) \
- do { \
- if (arg_value) \
- printf(fmt "\n", __VA_ARGS__); \
- else \
- printf("%s=" fmt "\n", name, __VA_ARGS__); \
- } while (0)
-
-static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
+static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
char bus_type;
const char *contents;
int r;
return bus_log_parse_error(r);
if (u > 0)
- print_prop(name, "%"PRIu32, u);
+ bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
else if (all)
- print_prop(name, "%s", "");
+ bus_print_property_value(name, expected_value, value, "%s", "");
return 1;
return bus_log_parse_error(r);
if (all || !isempty(s))
- print_prop(name, "%s", s);
+ bus_print_property_value(name, expected_value, value, "%s", s);
return 1;
return bus_log_parse_error(r);
if (all || !isempty(a) || !isempty(b))
- print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
+ bus_print_property_value(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
return 1;
} else if (streq_ptr(name, "SystemCallFilter")) {
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
- print_prop(name, "%s (ignore_errors=%s)", path, yes_no(ignore));
+ bus_print_property_value(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- print_prop(name, "%s (%s)", path, type);
+ bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- print_prop(name, "%s (%s)", path, type);
+ bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
- print_prop(name, "{ %s=%s ; next_elapse=%s }", base,
- format_timespan(timespan1, sizeof(timespan1), v, 0),
- format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
+ bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base,
+ format_timespan(timespan1, sizeof(timespan1), v, 0),
+ format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
}
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
char timestamp[FORMAT_TIMESTAMP_MAX];
- print_prop(name, "{ %s=%s ; next_elapse=%s }", base, spec,
- format_timestamp(timestamp, sizeof(timestamp), next_elapse));
+ bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base, spec,
+ format_timestamp(timestamp, sizeof(timestamp), next_elapse));
}
if (r < 0)
return bus_log_parse_error(r);
tt = strv_join(info.argv, " ");
- print_prop(name,
- "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
- strna(info.path),
- strna(tt),
- yes_no(info.ignore),
- strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
- strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
- info.pid,
- sigchld_code_to_string(info.code),
- info.status,
- info.code == CLD_EXITED ? "" : "/",
- strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+ bus_print_property_value(name, expected_value, value,
+ "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+ strna(info.path),
+ strna(tt),
+ yes_no(info.ignore),
+ strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+ strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+ info.pid,
+ sigchld_code_to_string(info.code),
+ info.status,
+ info.code == CLD_EXITED ? "" : "/",
+ strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
free(info.path);
strv_free(info.argv);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
- print_prop(name, "%s %s", strna(path), strna(rwm));
+ bus_print_property_value(name, expected_value, value, "%s %s", strna(path), strna(rwm));
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
- print_prop(name, "%s %"PRIu64, strna(path), weight);
+ bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
- print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
+ bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
- print_prop(name, "%s %s", strna(path),
- format_timespan(ts, sizeof(ts), target, 1));
+ bus_print_property_value(name, expected_value, value, "%s %s", strna(path),
+ format_timespan(ts, sizeof(ts), target, 1));
if (r < 0)
return bus_log_parse_error(r);
if (n < 0)
return log_oom();
- print_prop(name, "%s", h);
+ bus_print_property_value(name, expected_value, value, "%s", h);
return 1;
}
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
c = (unsigned) r;
- qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
+ typesafe_qsort(unit_infos, c, compare_unit_info);
for (u = unit_infos; u < unit_infos + c; u++) {
_cleanup_free_ char *p = NULL;
assert(argv);
show_mode = systemctl_show_mode_from_string(argv[0]);
- if (show_mode < 0) {
- log_error("Invalid argument.");
- return -EINVAL;
- }
+ if (show_mode < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Invalid argument.");
- if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1) {
- log_error("This command expects one or more unit names. Did you mean --help?");
- return -EINVAL;
- }
+ if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This command expects one or more unit names. Did you mean --help?");
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
-
- if (show_mode == SYSTEMCTL_SHOW_STATUS)
- /* Increase max number of open files to 16K if we can, we
- * might needs this when browsing journal files, which might
- * be split up into many files. */
- setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
+ (void) pager_open(arg_pager_flags);
/* If no argument is specified inspect the manager itself */
if (show_mode == SYSTEMCTL_SHOW_PROPERTIES && argc <= 1)
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
STRV_FOREACH(name, names) {
_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)
_cleanup_free_ char *esc = NULL;
sep = strchr(s, '=');
- if (!sep) {
- log_error("Invalid environment block");
- return -EUCLEAN;
- }
+ if (!sep)
+ return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
+ "Invalid environment block");
esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
if (!esc)
if (r < 0)
return r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = sd_bus_get_property(
bus,
if (argc >= 3)
init = argv[2];
else {
- r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE,
- "init", &cmdline_init,
- NULL);
+ r = proc_cmdline_get_key("init", 0, &cmdline_init);
if (r < 0)
log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
if (!path_is_absolute(*u)) {
char* normalized_path;
- if (!isempty(arg_root)) {
- log_error("Non-absolute paths are not allowed when --root is used: %s", *u);
- return -EINVAL;
- }
+ if (!isempty(arg_root))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Non-absolute paths are not allowed when --root is used: %s",
+ *u);
- if (!strchr(*u,'/')) {
- log_error("Link argument does contain at least one directory separator: %s", *u);
- return -EINVAL;
- }
+ if (!strchr(*u,'/'))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Link argument does contain at least one directory separator: %s",
+ *u);
r = path_make_absolute_cwd(*u, &normalized_path);
if (r < 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;
}
if (arg_runtime) {
- if (access(path, F_OK) >= 0) {
- log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
- return -EEXIST;
- }
+ if (access(path, F_OK) >= 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+ "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
+ run, path);
*ret_path = TAKE_PTR(run);
} else
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;
}
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;
_cleanup_free_ char *link = NULL;
int r;
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = terminal_urlify_man("systemctl", "1", &link);
if (r < 0)
return version();
case 't': {
- if (isempty(optarg)) {
- log_error("--type= requires arguments.");
- return -EINVAL;
- }
+ if (isempty(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--type= requires arguments.");
for (p = optarg;;) {
_cleanup_free_ char *type = NULL;
}
log_error("Unknown unit type or load state '%s'.", type);
- log_info("Use -t help to see a list of allowed values.");
- return -EINVAL;
+ return log_info_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Use -t help to see a list of allowed values.");
}
break;
break;
case ARG_NO_PAGER:
- arg_no_pager = true;
+ arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_WALL:
}
arg_signal = signal_from_string(optarg);
- if (arg_signal < 0) {
- log_error("Failed to parse signal string %s.", optarg);
- return -EINVAL;
- }
+ if (arg_signal < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse signal string %s.",
+ optarg);
break;
case ARG_NO_ASK_PASSWORD:
break;
case 'n':
- if (safe_atou(optarg, &arg_lines) < 0) {
- log_error("Failed to parse lines '%s'", optarg);
- return -EINVAL;
- }
+ if (safe_atou(optarg, &arg_lines) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse lines '%s'",
+ optarg);
break;
case 'o':
}
arg_output = output_mode_from_string(optarg);
- if (arg_output < 0) {
- log_error("Unknown output '%s'.", optarg);
- return -EINVAL;
- }
+ if (arg_output < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown output '%s'.",
+ optarg);
break;
case 'i':
break;
case ARG_STATE: {
- if (isempty(optarg)) {
- log_error("--state= requires arguments.");
- return -EINVAL;
- }
+ if (isempty(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--state= requires arguments.");
for (p = optarg;;) {
_cleanup_free_ char *s = NULL;
}
case 'r':
- if (geteuid() != 0) {
- log_error("--recursive requires root privileges.");
- return -EPERM;
- }
+ if (geteuid() != 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+ "--recursive requires root privileges.");
arg_recursive = true;
break;
}
arg_preset_mode = unit_file_preset_mode_from_string(optarg);
- if (arg_preset_mode < 0) {
- log_error("Failed to parse preset mode: %s.", optarg);
- return -EINVAL;
- }
+ if (arg_preset_mode < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse preset mode: %s.", optarg);
break;
assert_not_reached("Unhandled option");
}
- if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
- log_error("Cannot access user instance remotely.");
- return -EINVAL;
- }
+ if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Cannot access user instance remotely.");
- if (arg_wait && arg_no_block) {
- log_error("--wait may not be combined with --no-block.");
- return -EINVAL;
- }
+ if (arg_wait && arg_no_block)
+ 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")) {
- log_error("--runtime cannot be used with %s", argv[optind]);
- return -EINVAL;
- }
+ 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;
}
r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
if (r < 0)
return r;
- } else if (optind < argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
+ } else if (optind < argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Too many arguments.");
return 1;
}
assert_not_reached("Unhandled option");
}
- if (optind >= argc) {
- log_error("%s: required argument missing.", program_invocation_short_name);
- return -EINVAL;
- }
+ if (optind >= argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: required argument missing.",
+ program_invocation_short_name);
- if (optind + 1 < argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
+ if (optind + 1 < argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Too many arguments.");
- if (strlen(argv[optind]) != 1) {
- log_error("Expected single character argument.");
- return -EINVAL;
- }
+ if (strlen(argv[optind]) != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Expected single character argument.");
for (i = 0; i < ELEMENTSOF(table); i++)
if (table[i].from == argv[optind][0])
break;
- if (i >= ELEMENTSOF(table)) {
- log_error("Unknown command '%s'.", argv[optind]);
- return -EINVAL;
- }
+ if (i >= ELEMENTSOF(table))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown command '%s'.", argv[optind]);
arg_action = table[i].to;
assert_not_reached("Unhandled option");
}
- if (optind < argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
+ if (optind < argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Too many arguments.");
return 1;
}
execv(TELINIT, argv);
- log_error("Couldn't find an alternative telinit implementation to spawn.");
- return -EIO;
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Couldn't find an alternative telinit implementation to spawn.");
}
} else if (strstr(program_invocation_short_name, "runlevel")) {
if (talk_initctl() > 0)
return 0;
- log_error("Failed to talk to init daemon.");
- return -EIO;
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Failed to talk to init daemon.");
}
static int halt_now(enum action a) {
/* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
- * synce'd explicitly in advance. */
+ * synced explicitly in advance. */
if (!arg_no_sync && !arg_dry_run)
(void) sync();
if (r < 0)
return r;
- if (arg_when > 0)
- return logind_schedule_shutdown();
+ /* Delayed shutdown requested, and was successful */
+ if (arg_when > 0 && logind_schedule_shutdown() == 0)
+ return 0;
+ /* no delay, or logind failed or is not at all available */
if (geteuid() != 0) {
if (arg_dry_run || arg_force > 0) {
#endif
}
-int main(int argc, char*argv[]) {
+static int run(int argc, char*argv[]) {
int r;
argv_cmdline = argv[0];
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
+
+ /* The journal merging logic potentially needs a lot of fds. */
+ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
+
sigbus_install();
/* Explicitly not on_tty() to avoid setting cached value.
goto finish;
if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) {
-
if (!arg_quiet)
log_info("Running in chroot, ignoring request.");
r = 0;
finish:
release_busses();
- pager_close();
- ask_password_agent_close();
- polkit_agent_close();
-
strv_free(arg_types);
strv_free(arg_states);
strv_free(arg_properties);
free(arg_root);
free(arg_esp_path);
- /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
- return r < 0 ? EXIT_FAILURE : r;
+ /* Note that we return r here, not 0, so that we can implement the LSB-like return codes */
+ return r;
}
+
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);