#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
-#include <locale.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
-#include <string.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/reboot.h>
-#include <sys/socket.h>
#include <unistd.h>
#include "sd-bus.h"
return c;
}
-static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
+static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
char **name;
int r, i;
char *t;
UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
- if (suffix)
- r = unit_name_mangle_with_suffix(*name, options, suffix, &t);
- else
- r = unit_name_mangle(*name, options, &t);
+ r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
if (r < 0)
return log_error_errno(r, "Failed to mangle name: %m");
/* Query the manager only if any of the names are a glob, since
* this is fairly expensive */
- if (!strv_isempty(globs)) {
+ bool expanded = !strv_isempty(globs);
+ if (expanded) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
size_t allocated, n;
}
}
+ if (ret_expanded)
+ *ret_expanded = expanded;
+
*ret = TAKE_PTR(mangled);
return 0;
}
-
static int list_units(int argc, char *argv[], void *userdata) {
_cleanup_free_ UnitInfo *unit_infos = NULL;
_cleanup_(message_set_freep) Set *replies = NULL;
(void) pager_open(arg_pager_flags);
- r = expand_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix);
+ r = expand_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix, NULL);
if (r < 0)
return r;
(void) pager_open(arg_pager_flags);
- r = expand_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix);
+ r = expand_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix, NULL);
if (r < 0)
return r;
assert(argc >= 2);
assert(argv);
- r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &unit);
+ r = unit_name_mangle_with_suffix(argv[1], "set-default",
+ arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+ ".target", &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
if (!path)
return log_oom();
- r = chase_symlinks(path, arg_root, 0, &lpath);
+ r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
if (r == -ENOENT)
continue;
if (r == -ENOMEM)
if (!names)
return log_oom();
} else {
- r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
+ bool expanded;
+
+ r = expand_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
+
+ if (!arg_all && expanded && streq(job_type, "start") && !arg_quiet) {
+ log_warning("Warning: %ssystemctl start called with a glob pattern.%s",
+ ansi_highlight_red(),
+ ansi_normal());
+ log_notice("Hint: unit globs expand to loaded units, so start will usually have no effect.\n"
+ " Passing --all will also load units which are pulled in by other units.\n"
+ " See systemctl(1) for more details.");
+ }
}
if (!arg_no_block) {
if (r < 0)
return r;
- r = expand_names(bus, args, NULL, &names);
+ r = expand_names(bus, args, NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
if (streq(arg_job_mode, "fail"))
kill_who = strjoina(arg_kill_who, "-fail");
- r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
return log_oom();
}
- r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
char **dropin_paths;
+ char **triggered_by;
+ char **triggers;
+
const char *load_error;
const char *result;
strv_free(info->documentation);
strv_free(info->dropin_paths);
+ strv_free(info->triggered_by);
+ strv_free(info->triggers);
strv_free(info->listen);
while ((c = info->conditions)) {
}
}
+static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
+ if (streq_ptr(active_state, "failed")) {
+ *active_on = ansi_highlight_red();
+ *active_off = ansi_normal();
+ } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
+ *active_on = ansi_highlight_green();
+ *active_off = ansi_normal();
+ } else
+ *active_on = *active_off = "";
+}
+
static void print_status_info(
sd_bus *bus,
UnitStatusInfo *i,
/* This shows pretty information about a unit. See
* print_property() for a low-level property printer */
- if (streq_ptr(i->active_state, "failed")) {
- active_on = ansi_highlight_red();
- active_off = ansi_normal();
- } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
- active_on = ansi_highlight_green();
- active_off = ansi_normal();
- } else
- active_on = active_off = "";
+ format_active_state(i->active_state, &active_on, &active_off);
printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id));
path = formatted_path;
if (!isempty(i->load_error))
- printf(" Loaded: %s%s%s (Reason: %s)\n",
+ printf(" Loaded: %s%s%s (Reason: %s)\n",
on, strna(i->load_state), off, i->load_error);
else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
!STR_IN_SET(i->unit_file_state, "generated", "transient"))
- printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
+ printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
else if (path && !isempty(i->unit_file_state))
- printf(" Loaded: %s%s%s (%s; %s)\n",
+ printf(" Loaded: %s%s%s (%s; %s)\n",
on, strna(i->load_state), off, path, i->unit_file_state);
else if (path)
- printf(" Loaded: %s%s%s (%s)\n",
+ printf(" Loaded: %s%s%s (%s)\n",
on, strna(i->load_state), off, path);
else
- printf(" Loaded: %s%s%s\n",
+ printf(" Loaded: %s%s%s\n",
on, strna(i->load_state), off);
if (i->transient)
- printf("Transient: yes\n");
+ printf(" Transient: yes\n");
if (!strv_isempty(i->dropin_paths)) {
_cleanup_free_ char *dir = NULL;
const char *df;
if (!dir || last) {
- printf(dir ? " " :
- " Drop-In: ");
+ printf(dir ? " " :
+ " Drop-In: ");
dir = mfree(dir);
}
printf("%s\n"
- " %s", dir,
+ " %s", dir,
special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
}
ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
if (ss)
- printf(" Active: %s%s (%s)%s",
+ printf(" Active: %s%s (%s)%s",
active_on, strna(i->active_state), ss, active_off);
else
- printf(" Active: %s%s%s",
+ printf(" Active: %s%s%s",
active_on, strna(i->active_state), active_off);
if (!isempty(i->result) && !streq(i->result, "success"))
else
printf("\n");
+ STRV_FOREACH(t, i->triggered_by) {
+ UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+ (void) get_state_one_unit(bus, *t, &state);
+ format_active_state(unit_active_state_to_string(state), &on, &off);
+
+ printf("%s %s%s%s %s\n",
+ t == i->triggered_by ? "TriggeredBy:" : " ",
+ on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+ *t);
+ }
+
if (endswith(i->id, ".timer")) {
char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
tstamp2[FORMAT_TIMESTAMP_MAX];
i->next_elapse_monotonic};
usec_t next_elapse;
- printf(" Trigger: ");
+ printf(" Trigger: ");
dual_timestamp_get(&nw);
next_elapse = calc_next_elapse(&nw, &next);
printf("n/a\n");
}
+ STRV_FOREACH(t, i->triggers) {
+ UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+ (void) get_state_one_unit(bus, *t, &state);
+ format_active_state(unit_active_state_to_string(state), &on, &off);
+
+ printf("%s %s%s%s %s\n",
+ t == i->triggers ? " Triggers:" : " ",
+ on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+ *t);
+ }
+
if (!i->condition_result && i->condition_timestamp > 0) {
UnitCondition *c;
int n = 0;
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
- printf("Condition: start %scondition failed%s at %s%s%s\n",
+ printf(" Condition: start %scondition failed%s at %s%s%s\n",
ansi_highlight_yellow(), ansi_normal(),
s2, s1 ? "; " : "", strempty(s1));
LIST_FOREACH(conditions, c, i->conditions)
if (c->tristate < 0)
- printf(" %s %s=%s%s%s was not met\n",
+ printf(" %s %s=%s%s%s was not met\n",
--n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
c->name,
c->trigger ? "|" : "",
s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
- printf(" Assert: start %sassertion failed%s at %s%s%s\n",
+ printf(" Assert: start %sassertion failed%s at %s%s%s\n",
ansi_highlight_red(), ansi_normal(),
s2, s1 ? "; " : "", strempty(s1));
if (i->failed_assert_trigger)
- printf(" none of the trigger assertions were met\n");
+ printf(" none of the trigger assertions were met\n");
else if (i->failed_assert)
- printf(" %s=%s%s was not met\n",
+ printf(" %s=%s%s was not met\n",
i->failed_assert,
i->failed_assert_negate ? "!" : "",
i->failed_assert_parameter);
}
if (i->sysfs_path)
- printf(" Device: %s\n", i->sysfs_path);
+ printf(" Device: %s\n", i->sysfs_path);
if (i->where)
- printf(" Where: %s\n", i->where);
+ printf(" Where: %s\n", i->where);
if (i->what)
- printf(" What: %s\n", i->what);
+ printf(" What: %s\n", i->what);
STRV_FOREACH(t, i->documentation) {
_cleanup_free_ char *formatted = NULL;
else
q = *t;
- printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
+ printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
}
STRV_FOREACH_PAIR(t, t2, i->listen)
- printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
+ printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
if (i->accept) {
- printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
+ printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
if (i->n_refused)
- printf(" Refused: %u", i->n_refused);
+ printf(" Refused: %u", i->n_refused);
printf("\n");
}
continue;
argv = strv_join(p->argv, " ");
- printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
+ printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
if (!good) {
if (i->main_pid > 0 || i->control_pid > 0) {
if (i->main_pid > 0) {
- printf(" Main PID: "PID_FMT, i->main_pid);
+ printf(" Main PID: "PID_FMT, i->main_pid);
if (i->running) {
}
if (i->status_text)
- printf(" Status: \"%s\"\n", i->status_text);
+ printf(" Status: \"%s\"\n", i->status_text);
if (i->status_errno > 0)
- printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
+ printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
- printf(" IP: %s in, %s out\n",
+ printf(" IP: %s in, %s out\n",
format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
}
if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
- printf(" IO: %s read, %s written\n",
+ printf(" IO: %s read, %s written\n",
format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
}
if (i->tasks_current != (uint64_t) -1) {
- printf(" Tasks: %" PRIu64, i->tasks_current);
+ printf(" Tasks: %" PRIu64, i->tasks_current);
if (i->tasks_max != (uint64_t) -1)
printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
if (i->memory_current != (uint64_t) -1) {
char buf[FORMAT_BYTES_MAX];
- printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
+ printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
if (i->memory_min > 0 || i->memory_low > 0 ||
i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
if (i->cpu_usage_nsec != (uint64_t) -1) {
char buf[FORMAT_TIMESPAN_MAX];
- printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
+ printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
}
if (i->control_group) {
static const char prefix[] = " ";
unsigned c;
- printf(" CGroup: %s\n", i->control_group);
+ printf(" CGroup: %s\n", i->control_group);
c = columns();
if (c > sizeof(prefix) - 1)
{ "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
{ "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
{ "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
+ { "TriggeredBy", "as", NULL, offsetof(UnitStatusInfo, triggered_by) },
+ { "Triggers", "as", NULL, offsetof(UnitStatusInfo, triggers) },
{ "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
{ "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
if (!strv_isempty(patterns)) {
_cleanup_strv_free_ char **names = NULL;
- r = expand_names(bus, patterns, NULL, &names);
+ r = expand_names(bus, patterns, NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
if (r < 0)
return r;
- r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
polkit_agent_open_maybe();
- r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
return r;
}
-static int mangle_names(char **original_names, char ***mangled_names) {
+static int mangle_names(const char *operation, char **original_names, char ***mangled_names) {
char **i, **l, **name;
int r;
return log_oom();
}
} else {
- r = unit_name_mangle(*name, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, i);
+ r = unit_name_mangle_with_suffix(*name, operation,
+ arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+ ".service", i);
if (r < 0) {
*i = NULL;
strv_free(l);
if (!argv[1])
return 0;
- r = mangle_names(strv_skip(argv, 1), &names);
+ r = mangle_names("to enable", strv_skip(argv, 1), &names);
if (r < 0)
return r;
if (!argv[1])
return 0;
- r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &target);
+ r = unit_name_mangle_with_suffix(argv[1], "as target",
+ arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+ ".target", &target);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- r = mangle_names(strv_skip(argv, 2), &names);
+ r = mangle_names("as dependency", strv_skip(argv, 2), &names);
if (r < 0)
return r;
char **name;
int r;
- r = mangle_names(strv_skip(argv, 1), &names);
+ r = mangle_names("to check", strv_skip(argv, 1), &names);
if (r < 0)
return r;
if (r < 0)
return r;
- r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
static int help_boot_loader_entry(void) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char **l = NULL;
+ _cleanup_strv_free_ char **l = NULL;
sd_bus *bus;
char **i;
int r;