#include "install.h"
#include "logs-show.h"
#include "path-util.h"
+#include "socket-util.h"
static const char *arg_type = NULL;
static const char *arg_load_state = NULL;
static bool arg_no_legend = false;
static bool arg_no_pager = false;
static bool arg_no_wtmp = false;
-static bool arg_no_sync = false;
static bool arg_no_wall = false;
static bool arg_no_reload = false;
static bool arg_dry = false;
"JOB = Pending job for the unit.\n");
if (arg_all)
- printf("\n%u units listed.\n", n_shown);
+ printf("\n%u loaded units listed.\n"
+ "To show all installed unit files use 'systemctl list-unit-files'.\n", n_shown);
else
- printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
+ printf("\n%u loaded units listed. Pass --all to see loaded but inactive units, too.\n"
+ "To show all installed unit files use 'systemctl list-unit-files'.\n", n_shown);
}
}
if (u->state == UNIT_FILE_MASKED ||
u->state == UNIT_FILE_MASKED_RUNTIME ||
- u->state == UNIT_FILE_DISABLED) {
+ u->state == UNIT_FILE_DISABLED ||
+ u->state == UNIT_FILE_INVALID) {
on = ansi_highlight_red(true);
off = ansi_highlight_red(false);
} else if (u->state == UNIT_FILE_ENABLED) {
typedef struct WaitData {
Set *set;
+
+ char *name;
char *result;
} WaitData;
p = set_remove(d->set, (char*) path);
free(p);
- if (*result)
+ if (!isempty(result))
d->result = strdup(result);
+ if (!isempty(unit))
+ d->name = strdup(unit);
+
goto finish;
}
#ifndef LEGACY
}
static int wait_for_jobs(DBusConnection *bus, Set *s) {
- int r;
+ int r = 0;
WaitData d;
assert(bus);
zero(d);
d.set = s;
- if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
- log_error("Failed to add filter.");
- r = -ENOMEM;
- goto finish;
- }
+ if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
+ return log_oom();
- while (!set_isempty(s) &&
- dbus_connection_read_write_dispatch(bus, -1))
- ;
+ while (!set_isempty(s)) {
- if (!arg_quiet && d.result) {
- if (streq(d.result, "timeout"))
- log_error("Job timed out.");
- else if (streq(d.result, "canceled"))
- log_error("Job canceled.");
- else if (streq(d.result, "dependency"))
- log_error("A dependency job failed. See system journal for details.");
- else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
- log_error("Job failed. See system journal and 'systemctl status' for details.");
- }
+ if (!dbus_connection_read_write_dispatch(bus, -1)) {
+ log_error("Disconnected from bus.");
+ return -ECONNREFUSED;
+ }
- if (streq_ptr(d.result, "timeout"))
- r = -ETIME;
- else if (streq_ptr(d.result, "canceled"))
- r = -ECANCELED;
- else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
- r = -EIO;
- else
- r = 0;
+ if (!d.result)
+ goto free_name;
- free(d.result);
+ if (!arg_quiet) {
+ if (streq(d.result, "timeout"))
+ log_error("Job for %s timed out.", strna(d.name));
+ else if (streq(d.result, "canceled"))
+ log_error("Job for %s canceled.", strna(d.name));
+ else if (streq(d.result, "dependency"))
+ log_error("A dependency job for %s failed. See 'journalctl' for details.", strna(d.name));
+ else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
+ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl' for details.", strna(d.name), strna(d.name));
+ }
-finish:
- /* This is slightly dirty, since we don't undo the filter registration. */
+ if (streq_ptr(d.result, "timeout"))
+ r = -ETIME;
+ else if (streq_ptr(d.result, "canceled"))
+ r = -ECANCELED;
+ else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
+ r = -EIO;
+
+ free(d.result);
+ d.result = NULL;
+
+ free_name:
+ free(d.name);
+ d.name = NULL;
+ }
+ dbus_connection_remove_filter(bus, wait_filter, &d);
return r;
}
DBusConnection *bus,
const char *unit_name) {
- DBusMessage *reply = NULL;
+ DBusMessage _cleanup_dbus_msg_unref_ *reply = NULL;
DBusMessageIter iter, sub;
char *service_trigger = NULL;
const char *interface = "org.freedesktop.systemd1.Unit",
*triggered_by_property = "TriggeredBy";
- char *unit_path = NULL, *n = NULL;
+ char _cleanup_free_ *unit_path = NULL, *n = NULL;
bool print_warning_label = true;
int r;
n = unit_name_mangle(unit_name);
- unit_path = unit_dbus_path_from_name(n ? n : unit_name);
- free(n);
+ if (!n) {
+ log_oom();
+ return;
+ }
+
+ unit_path = unit_dbus_path_from_name(n);
if (!unit_path) {
- log_error("Could not allocate dbus path.");
- goto finish;
+ log_oom();
+ return;
}
r = bus_method_call_with_reply (
DBUS_TYPE_STRING, &triggered_by_property,
DBUS_TYPE_INVALID);
if (r)
- goto finish;
+ return;
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
- goto finish;
-
+ return;
}
dbus_message_iter_recurse(&iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
- goto finish;
+ return;
}
dbus_message_iter_get_basic(&sub, &service_trigger);
r = check_one_unit(bus, service_trigger, true);
if (r < 0)
- goto finish;
+ return;
if (r == 0) {
if (print_warning_label) {
log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
dbus_message_iter_next(&sub);
}
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- free(unit_path);
}
static int start_unit_one(
DBusError *error,
Set *s) {
- DBusMessage *reply = NULL;
+ DBusMessage _cleanup_dbus_msg_unref_ *reply = NULL;
const char *path;
int r;
- char *n;
+ _cleanup_free_ char *n, *p = NULL;
assert(method);
assert(name);
assert(mode);
assert(error);
- assert(arg_no_block || s);
n = unit_name_mangle(name);
- r = bus_method_call_with_reply (
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
method,
&reply,
error,
- DBUS_TYPE_STRING, n ? (const char **) &n : &name,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
- free(n);
if (r) {
- if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL ) {
+ if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
/* There's always a fallback possible for
* legacy actions. */
r = -EADDRNOTAVAIL;
- }
- goto finish;
+ else
+ log_error("Failed to issue method call: %s", bus_error_message(error));
+
+ return r;
}
if (!dbus_message_get_args(reply, error,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(error));
- r = -EIO;
- goto finish;
+ return -EIO;
}
- if (need_daemon_reload(bus, name))
- log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
- arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
+ if (need_daemon_reload(bus, n))
+ log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
+ n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
- if (!arg_no_block) {
- char *p;
-
- if (!(p = strdup(path))) {
- log_error("Failed to duplicate path.");
- r = -ENOMEM;
- goto finish;
- }
+ if (s) {
+ p = strdup(path);
+ if (!p)
+ return log_oom();
- if ((r = set_put(s, p)) < 0) {
- free(p);
+ r = set_put(s, p);
+ if (r < 0) {
log_error("Failed to add path to set.");
- goto finish;
+ return r;
}
- }
-
- /* When stopping a unit warn if it can still be triggered by
- * another active unit (socket, path, timer) */
- if (!arg_quiet && streq(method, "StopUnit"))
- check_triggering_units(bus, name);
- r = 0;
-
-finish:
- if (reply)
- dbus_message_unref(reply);
+ p = NULL;
+ }
- return r;
+ return 0;
}
static enum action verb_to_action(const char *verb) {
}
if (!arg_no_block) {
- if ((ret = enable_wait_for_jobs(bus)) < 0) {
+ ret = enable_wait_for_jobs(bus);
+ if (ret < 0) {
log_error("Could not watch jobs: %s", strerror(-ret));
goto finish;
}
- if (!(s = set_new(string_hash_func, string_compare_func))) {
- log_error("Failed to allocate set.");
- ret = -ENOMEM;
+ s = set_new(string_hash_func, string_compare_func);
+ if (!s) {
+ ret = log_oom();
goto finish;
}
}
if (one_name) {
- if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
- goto finish;
+ ret = start_unit_one(bus, method, one_name, mode, &error, s);
+ if (ret < 0)
+ ret = translate_bus_error_to_exit_status(ret, &error);
} else {
- STRV_FOREACH(name, args+1)
- if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
+ STRV_FOREACH(name, args+1) {
+ r = start_unit_one(bus, method, *name, mode, &error, s);
+ if (r < 0) {
ret = translate_bus_error_to_exit_status(r, &error);
dbus_error_free(&error);
}
+ }
}
- if (!arg_no_block)
- if ((r = wait_for_jobs(bus, s)) < 0) {
+ if (!arg_no_block) {
+ r = wait_for_jobs(bus, s);
+ if (r < 0) {
ret = r;
goto finish;
}
-finish:
- if (s)
- set_free_free(s);
+ /* When stopping units, warn if they can still be triggered by
+ * another active unit (socket, path, timer) */
+ if (!arg_quiet && streq(method, "StopUnit")) {
+ if (one_name)
+ check_triggering_units(bus, one_name);
+ else
+ STRV_FOREACH(name, args+1)
+ check_triggering_units(bus, *name);
+ }
+ }
+finish:
+ set_free_free(s);
dbus_error_free(&error);
return ret;
printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
free(t);
- good = is_clean_exit_lsb(p->code, p->status);
+ good = is_clean_exit_lsb(p->code, p->status, NULL);
if (!good) {
on = ansi_highlight_red(true);
off = ansi_highlight_red(false);
if (i->id && arg_transport != TRANSPORT_SSH) {
int flags =
- arg_lines * OUTPUT_SHOW_ALL |
+ arg_all * OUTPUT_SHOW_ALL |
arg_follow * OUTPUT_FOLLOW |
!arg_quiet * OUTPUT_WARN_CUTOFF |
on_tty() * OUTPUT_COLOR;
printf("\n");
- show_journal_by_unit(i->id, arg_output, 0,
+ show_journal_by_unit(stdout,
+ i->id,
+ arg_output,
+ 0,
i->inactive_exit_timestamp_monotonic,
- arg_lines, flags);
+ arg_lines,
+ flags);
}
if (i->need_daemon_reload)
static int daemon_reload(DBusConnection *bus, char **args) {
int r;
const char *method;
+ DBusError error;
if (arg_action == ACTION_RELOAD)
method = "Reload";
"org.freedesktop.systemd1.Manager",
method,
NULL,
- NULL,
+ &error,
DBUS_TYPE_INVALID);
if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
/* On reexecution, we expect a disconnect, not
* a reply */
r = 0;
+ else if (r)
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ dbus_error_free(&error);
return r;
}
* afterwards only the native units remain */
zero(paths);
- r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
+ r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
if (r < 0)
return r;
return r;
}
+static int mangle_names(char **original_names, char ***mangled_names) {
+ char **i, **l, **name;
+
+ l = new(char*, strv_length(original_names) + 1);
+ if (!l)
+ return log_oom();
+
+ i = l;
+ STRV_FOREACH(name, original_names) {
+ *i = unit_name_mangle(*name);
+ if (!*i) {
+ strv_free(l);
+ return log_oom();
+ }
+
+ i++;
+ }
+
+ *i = NULL;
+ *mangled_names = l;
+
+ return 0;
+}
+
static int enable_unit(DBusConnection *bus, char **args) {
const char *verb = args[0];
UnitFileChange *changes = NULL;
DBusMessage *m = NULL, *reply = NULL;
int r;
DBusError error;
+ char **mangled_names = NULL;
r = enable_sysv_units(args);
if (r < 0)
dbus_message_iter_init_append(m, &iter);
- r = bus_append_strv_iter(&iter, args+1);
+ r = mangle_names(args+1, &mangled_names);
+ if(r < 0)
+ goto finish;
+
+ r = bus_append_strv_iter(&iter, mangled_names);
if (r < 0) {
log_error("Failed to append unit files.");
goto finish;
unit_file_changes_free(changes, n_changes);
dbus_error_free(&error);
+
+ strv_free(mangled_names);
+
return r;
}
" -n --lines=INTEGER Journal entries to show\n"
" --follow Follow journal\n"
" -o --output=STRING Change journal output mode (short, short-monotonic,\n"
- " verbose, export, json, cat)\n\n"
+ " verbose, export, json, json-pretty, cat)\n\n"
"Unit Commands:\n"
" list-units List loaded units\n"
" start [NAME...] Start (activate) one or more units\n"
" -f --force Force immediate halt/power-off/reboot\n"
" -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
" -d --no-wtmp Don't write wtmp record\n"
- " -n --no-sync Don't sync before halt/power-off/reboot\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n",
program_invocation_short_name,
arg_action == ACTION_REBOOT ? "Reboot" :
{ "force", no_argument, NULL, 'f' },
{ "wtmp-only", no_argument, NULL, 'w' },
{ "no-wtmp", no_argument, NULL, 'd' },
- { "no-sync", no_argument, NULL, 'n' },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{ NULL, 0, NULL, 0 }
};
arg_no_wtmp = true;
break;
- case 'n':
- arg_no_sync = true;
- break;
-
case ARG_NO_WALL:
arg_no_wall = true;
break;
case 'i':
case 'h':
+ case 'n':
/* Compatibility nops */
break;
}
}
- if (!arg_no_sync)
- sync();
-
if (arg_dry)
return 0;