summaryrefslogtreecommitdiff
path: root/src/systemctl/systemctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemctl/systemctl.c')
-rw-r--r--src/systemctl/systemctl.c212
1 files changed, 154 insertions, 58 deletions
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d3f437411a..782824ff38 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -224,6 +224,21 @@ static void release_busses(void) {
busses[w] = sd_bus_flush_close_unref(busses[w]);
}
+static int map_string_no_copy(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+ char *s;
+ const char **p = userdata;
+ int r;
+
+ r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &s);
+ if (r < 0)
+ return r;
+
+ if (!isempty(s))
+ *p = s;
+
+ return 0;
+}
+
static void ask_password_agent_open_if_enabled(void) {
/* Open the password agent as a child process if necessary */
@@ -1820,12 +1835,12 @@ static const struct bus_properties_map machine_info_property_map[] = {
};
static void machine_info_clear(struct machine_info *info) {
- if (info) {
- free(info->name);
- free(info->state);
- free(info->control_group);
- zero(*info);
- }
+ assert(info);
+
+ free(info->name);
+ free(info->state);
+ free(info->control_group);
+ zero(*info);
}
static void free_machines_list(struct machine_info *machine_infos, int n) {
@@ -3033,6 +3048,9 @@ static int logind_check_inhibitors(enum action a) {
if (!on_tty())
return 0;
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ return 0;
+
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
@@ -3455,6 +3473,27 @@ static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
return 1;
}
+typedef struct UnitCondition {
+ char *name;
+ char *param;
+ bool trigger;
+ bool negate;
+ int tristate;
+
+ LIST_FIELDS(struct UnitCondition, conditions);
+} UnitCondition;
+
+static void unit_condition_free(UnitCondition *c) {
+ if (!c)
+ return;
+
+ free(c->name);
+ free(c->param);
+ free(c);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
+
typedef struct UnitStatusInfo {
const char *id;
const char *load_state;
@@ -3501,10 +3540,7 @@ typedef struct UnitStatusInfo {
usec_t condition_timestamp;
bool condition_result;
- bool failed_condition_trigger;
- bool failed_condition_negate;
- const char *failed_condition;
- const char *failed_condition_parameter;
+ LIST_HEAD(UnitCondition, conditions);
usec_t assert_timestamp;
bool assert_result;
@@ -3543,6 +3579,25 @@ typedef struct UnitStatusInfo {
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
+static void unit_status_info_free(UnitStatusInfo *info) {
+ ExecStatusInfo *p;
+ UnitCondition *c;
+
+ strv_free(info->documentation);
+ strv_free(info->dropin_paths);
+ strv_free(info->listen);
+
+ while ((c = info->conditions)) {
+ LIST_REMOVE(conditions, info->conditions, c);
+ unit_condition_free(c);
+ }
+
+ while ((p = info->exec)) {
+ LIST_REMOVE(exec, info->exec, p);
+ exec_status_info_free(p);
+ }
+}
+
static void print_status_info(
sd_bus *bus,
UnitStatusInfo *i,
@@ -3664,19 +3719,28 @@ static void print_status_info(
printf("\n");
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",
ansi_highlight_yellow(), ansi_normal(),
s2, s1 ? "; " : "", strempty(s1));
- if (i->failed_condition_trigger)
- printf(" none of the trigger conditions were met\n");
- else if (i->failed_condition)
- printf(" %s=%s%s was not met\n",
- i->failed_condition,
- i->failed_condition_negate ? "!" : "",
- i->failed_condition_parameter);
+
+ LIST_FOREACH(conditions, c, i->conditions)
+ if (c->tristate < 0)
+ n++;
+
+ LIST_FOREACH(conditions, c, i->conditions)
+ if (c->tristate < 0)
+ printf(" %s %s=%s%s%s was not met\n",
+ --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT),
+ c->name,
+ c->trigger ? "|" : "",
+ c->negate ? "!" : "",
+ c->param);
}
if (!i->assert_result && i->assert_timestamp > 0) {
@@ -3761,7 +3825,7 @@ static void print_status_info(
if (i->running) {
_cleanup_free_ char *comm = NULL;
- get_process_comm(i->main_pid, &comm);
+ (void) get_process_comm(i->main_pid, &comm);
if (comm)
printf(" (%s)", comm);
} else if (i->exit_code > 0) {
@@ -3780,17 +3844,19 @@ static void print_status_info(
printf("signal=%s", signal_to_string(i->exit_status));
printf(")");
}
-
- if (i->control_pid > 0)
- printf(";");
}
if (i->control_pid > 0) {
_cleanup_free_ char *c = NULL;
- printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
+ if (i->main_pid > 0)
+ fputs("; Control PID: ", stdout);
+ else
+ fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
+
+ printf(PID_FMT, i->control_pid);
- get_process_comm(i->control_pid, &c);
+ (void) get_process_comm(i->control_pid, &c);
if (c)
printf(" (%s)", c);
}
@@ -3807,7 +3873,7 @@ static void print_status_info(
printf(" Tasks: %" PRIu64, i->tasks_current);
if (i->tasks_max != (uint64_t) -1)
- printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
+ printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
else
printf("\n");
}
@@ -4169,13 +4235,25 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
- log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
- if (state < 0 && (!trigger || !i->failed_condition)) {
- i->failed_condition = cond;
- i->failed_condition_trigger = trigger;
- i->failed_condition_negate = negate;
- i->failed_condition_parameter = param;
- }
+ _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
+
+ log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state);
+
+ c = new0(UnitCondition, 1);
+ if (!c)
+ return log_oom();
+
+ c->name = strdup(cond);
+ c->param = strdup(param);
+ if (!c->name || !c->param)
+ return log_oom();
+
+ c->trigger = trigger;
+ c->negate = negate;
+ c->tristate = state;
+
+ LIST_PREPEND(conditions, i->conditions, c);
+ c = NULL;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -4565,15 +4643,15 @@ static int show_one(
bool *ellipsized) {
static const struct bus_properties_map property_map[] = {
- { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
- { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
+ { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) },
{}
};
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_set_free_ Set *found_properties = NULL;
- UnitStatusInfo info = {
+ _cleanup_(unit_status_info_free) UnitStatusInfo info = {
.memory_current = (uint64_t) -1,
.memory_high = CGROUP_LIMIT_MAX,
.memory_max = CGROUP_LIMIT_MAX,
@@ -4582,7 +4660,6 @@ static int show_one(
.tasks_current = (uint64_t) -1,
.tasks_max = (uint64_t) -1,
};
- ExecStatusInfo *p;
int r;
assert(path);
@@ -4676,16 +4753,15 @@ static int show_one(
return bus_log_parse_error(r);
r = 0;
-
if (show_properties) {
char **pp;
- STRV_FOREACH(pp, arg_properties) {
+ STRV_FOREACH(pp, arg_properties)
if (!set_contains(found_properties, *pp)) {
log_warning("Property %s does not exist.", *pp);
r = -ENXIO;
}
- }
+
} else if (streq(verb, "help"))
show_unit_help(&info);
else if (streq(verb, "status")) {
@@ -4697,15 +4773,6 @@ static int show_one(
r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
}
- strv_free(info.documentation);
- strv_free(info.dropin_paths);
- strv_free(info.listen);
-
- while ((p = info.exec)) {
- LIST_REMOVE(exec, info.exec, p);
- exec_status_info_free(p);
- }
-
return r;
}
@@ -5499,10 +5566,12 @@ static int enable_sysv_units(const char *verb, char **args) {
if (!found_sysv)
continue;
- if (found_native)
- log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
- else
- log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
+ if (!arg_quiet) {
+ if (found_native)
+ log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
+ else
+ log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
+ }
if (!isempty(arg_root))
argv[c++] = q = strappend("--root=", arg_root);
@@ -5532,10 +5601,8 @@ static int enable_sysv_units(const char *verb, char **args) {
}
j = wait_for_terminate(pid, &status);
- if (j < 0) {
- log_error_errno(j, "Failed to wait for child: %m");
- return j;
- }
+ if (j < 0)
+ return log_error_errno(j, "Failed to wait for child: %m");
if (status.si_code == CLD_EXITED) {
if (streq(verb, "is-enabled")) {
@@ -5605,13 +5672,36 @@ static int mangle_names(char **original_names, char ***mangled_names) {
return 0;
}
+static int normalize_names(char **names, bool warn_if_path) {
+ char **u;
+ bool was_path = false;
+
+ STRV_FOREACH(u, names) {
+ int r;
+
+ if (!is_path(*u))
+ continue;
+
+ r = free_and_strdup(u, basename(*u));
+ if (r < 0)
+ return log_error_errno(r, "Failed to normalize unit file path: %m");
+
+ was_path = true;
+ }
+
+ if (warn_if_path && was_path)
+ log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
+
+ return 0;
+}
+
static int unit_exists(const char *unit) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL;
static const struct bus_properties_map property_map[] = {
- { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
- { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state)},
+ { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)},
{},
};
UnitStatusInfo info = {};
@@ -5672,6 +5762,12 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
return daemon_reload(argc, argv, userdata);
}
+ if (streq(verb, "disable")) {
+ r = normalize_names(names, true);
+ if (r < 0)
+ return r;
+ }
+
if (install_client_side()) {
if (streq(verb, "enable")) {
r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
@@ -6530,7 +6626,7 @@ static void systemctl_help(void) {
" unit is required or wanted\n\n"
"Unit File Commands:\n"
" list-unit-files [PATTERN...] List installed unit files\n"
- " enable NAME... Enable one or more unit files\n"
+ " enable [NAME...|PATH...] Enable one or more unit files\n"
" disable NAME... Disable one or more unit files\n"
" reenable NAME... Reenable one or more unit files\n"
" preset NAME... Enable/disable one or more unit files\n"