#include "socket-util.h"
#include "fileio.h"
-static const char *arg_type = NULL;
-static const char *arg_load_state = NULL;
-static char **arg_property = NULL;
+static char **arg_types = NULL;
+static char **arg_load_states = NULL;
+static char **arg_properties = NULL;
static bool arg_all = false;
+static enum dependency {
+ DEPENDENCY_FORWARD,
+ DEPENDENCY_REVERSE,
+ DEPENDENCY_AFTER,
+ DEPENDENCY_BEFORE,
+} arg_dependency = DEPENDENCY_FORWARD;
static const char *arg_job_mode = "replace";
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static bool arg_no_block = false;
static bool arg_no_wtmp = false;
static bool arg_no_wall = false;
static bool arg_no_reload = false;
+static bool arg_show_types = false;
static bool arg_ignore_inhibitors = false;
static bool arg_dry = false;
static bool arg_quiet = false;
static const char *arg_host = NULL;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
+static bool arg_plain = false;
static bool private_bus = false;
if (arg_failed)
return streq(u->active_state, "failed");
- return (!arg_type || ((dot = strrchr(u->id, '.')) &&
- streq(dot+1, arg_type))) &&
- (!arg_load_state || streq(u->load_state, arg_load_state)) &&
+ return (!arg_types || ((dot = strrchr(u->id, '.')) &&
+ strv_find(arg_types, dot+1))) &&
+ (!arg_load_states || strv_find(arg_load_states, u->load_state)) &&
(arg_all || !(streq(u->active_state, "inactive")
|| u->following[0]) || u->job_id > 0);
}
id_len = max_id_len;
for (u = unit_infos; u < unit_infos + c; u++) {
- char _cleanup_free_ *e = NULL;
- const char *on_loaded, *off_loaded;
- const char *on_active, *off_active;
+ _cleanup_free_ char *e = NULL;
+ const char *on_loaded, *off_loaded, *on = "";
+ const char *on_active, *off_active, *off = "";
if (!output_show_unit(u))
continue;
n_shown++;
if (streq(u->load_state, "error")) {
- on_loaded = ansi_highlight_red(true);
- off_loaded = ansi_highlight_red(false);
+ on_loaded = on = ansi_highlight_red(true);
+ off_loaded = off = ansi_highlight_red(false);
} else
on_loaded = off_loaded = "";
if (streq(u->active_state, "failed")) {
- on_active = ansi_highlight_red(true);
- off_active = ansi_highlight_red(false);
+ on_active = on = ansi_highlight_red(true);
+ off_active = off = ansi_highlight_red(false);
} else
on_active = off_active = "";
e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
- printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
- id_len, e ? e : u->id,
+ printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s",
+ on, id_len, e ? e : u->id, off,
on_loaded, u->load_state, off_loaded,
on_active, active_len, u->active_state,
sub_len, u->sub_state, off_active,
static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
struct unit_info **unit_infos, unsigned *c) {
DBusMessageIter iter, sub;
- unsigned n_units = 0;
+ size_t size = 0;
int r;
assert(bus);
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- struct unit_info *u;
+ if (!GREEDY_REALLOC(*unit_infos, size, *c + 1))
+ return log_oom();
- if (*c >= n_units) {
- struct unit_info *w;
+ bus_parse_unit_info(&sub, *unit_infos + *c);
+ (*c)++;
- n_units = MAX(2 * *c, 16u);
- w = realloc(*unit_infos, sizeof(struct unit_info) * n_units);
- if (!w)
- return log_oom();
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+}
+
+static int list_units(DBusConnection *bus, char **args) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ struct unit_info *unit_infos = NULL;
+ unsigned c = 0;
+ int r;
+
+ pager_open_if_enabled();
+
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
+
+ qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+
+ output_units_list(unit_infos, c);
+
+ return 0;
+}
+
+static int get_triggered_units(DBusConnection *bus, const char* unit_path,
+ char*** triggered)
+{
+ const char *interface = "org.freedesktop.systemd1.Unit",
+ *triggers_property = "Triggers";
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ DBusMessageIter iter, sub;
+ int r;
+
+ r = bus_method_call_with_reply(bus,
+ "org.freedesktop.systemd1",
+ unit_path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &triggers_property,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+ dbus_message_iter_recurse(&sub, &iter);
+ sub = iter;
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *unit;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+ log_error("Failed to parse reply.");
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_get_basic(&sub, &unit);
+ r = strv_extend(triggered, unit);
+ if (r < 0)
+ return r;
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+}
+
+static int get_listening(DBusConnection *bus, const char* unit_path,
+ char*** listen, unsigned *c)
+{
+ const char *interface = "org.freedesktop.systemd1.Socket",
+ *listen_property = "Listen";
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ DBusMessageIter iter, sub;
+ int r;
+
+ r = bus_method_call_with_reply(bus,
+ "org.freedesktop.systemd1",
+ unit_path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &listen_property,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+ dbus_message_iter_recurse(&sub, &iter);
+ sub = iter;
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ DBusMessageIter sub2;
+ const char *type, *path;
- *unit_infos = w;
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+ log_error("Failed to parse reply.");
+ return -EBADMSG;
}
- u = *unit_infos + *c;
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
+ r = strv_extend(listen, type);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(listen, path);
+ if (r < 0)
+ return r;
- bus_parse_unit_info(&sub, u);
+ (*c) ++;
+ }
dbus_message_iter_next(&sub);
- (*c)++;
}
- if (*c > 0)
- qsort(*unit_infos, *c, sizeof(struct unit_info), compare_unit_info);
+ return 0;
+}
+
+struct socket_info {
+ const char* id;
+
+ char* type;
+ char* path;
+
+ /* Note: triggered is a list here, although it almost certainly
+ * will always be one unit. Nevertheless, dbus API allows for multiple
+ * values, so let's follow that.*/
+ char** triggered;
+
+ /* The strv above is shared. free is set only in the first one. */
+ bool own_triggered;
+};
+
+static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
+ int o = strcmp(a->path, b->path);
+ if (o == 0)
+ o = strcmp(a->type, b->type);
+ return o;
+}
+
+static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
+ struct socket_info *s;
+ unsigned pathlen = sizeof("LISTEN") - 1,
+ typelen = (sizeof("TYPE") - 1) * arg_show_types,
+ socklen = sizeof("UNIT") - 1,
+ servlen = sizeof("ACTIVATES") - 1;
+ const char *on, *off;
+
+ for (s = socket_infos; s < socket_infos + cs; s++) {
+ char **a;
+ unsigned tmp = 0;
+
+ socklen = MAX(socklen, strlen(s->id));
+ if (arg_show_types)
+ typelen = MAX(typelen, strlen(s->type));
+ pathlen = MAX(pathlen, strlen(s->path));
+
+ STRV_FOREACH(a, s->triggered)
+ tmp += strlen(*a) + 2*(a != s->triggered);
+ servlen = MAX(servlen, tmp);
+ }
+
+ if (cs) {
+ if (!arg_no_legend)
+ printf("%-*s %-*.*s%-*s %s\n",
+ pathlen, "LISTEN",
+ typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
+ socklen, "UNIT",
+ "ACTIVATES");
+
+ for (s = socket_infos; s < socket_infos + cs; s++) {
+ char **a;
+
+ if (arg_show_types)
+ printf("%-*s %-*s %-*s",
+ pathlen, s->path, typelen, s->type, socklen, s->id);
+ else
+ printf("%-*s %-*s",
+ pathlen, s->path, socklen, s->id);
+ STRV_FOREACH(a, s->triggered)
+ printf("%s %s",
+ a == s->triggered ? "" : ",", *a);
+ printf("\n");
+ }
+
+ on = ansi_highlight(true);
+ off = ansi_highlight(false);
+ if (!arg_no_legend)
+ printf("\n");
+ } else {
+ on = ansi_highlight_red(true);
+ off = ansi_highlight_red(false);
+ }
+
+ if (!arg_no_legend) {
+ printf("%s%u sockets listed.%s\n", on, cs, off);
+ if (!arg_all)
+ printf("Pass --all to see loaded but inactive sockets, too.\n");
+ }
return 0;
}
-static int list_units(DBusConnection *bus, char **args) {
+static int list_sockets(DBusConnection *bus, char **args) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
_cleanup_free_ struct unit_info *unit_infos = NULL;
- unsigned c = 0;
+ struct socket_info *socket_infos = NULL;
+ const struct unit_info *u;
+ struct socket_info *s;
+ unsigned cu = 0, cs = 0;
+ size_t size = 0;
int r;
pager_open_if_enabled();
- r = get_unit_list(bus, &reply, &unit_infos, &c);
+ r = get_unit_list(bus, &reply, &unit_infos, &cu);
if (r < 0)
return r;
- if (c > 0)
- output_units_list(unit_infos, c);
+ for (u = unit_infos; u < unit_infos + cu; u++) {
+ const char *dot;
+ _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
+ unsigned c = 0, i;
+
+ if (!output_show_unit(u))
+ continue;
+
+ if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
+ continue;
+
+ r = get_triggered_units(bus, u->unit_path, &triggered);
+ if (r < 0)
+ goto cleanup;
+
+ r = get_listening(bus, u->unit_path, &listen, &c);
+ if (r < 0)
+ goto cleanup;
+
+ if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
+ r = log_oom();
+ goto cleanup;
+ }
+
+ for (i = 0; i < c; i++)
+ socket_infos[cs + i] = (struct socket_info) {
+ .id = u->id,
+ .type = listen[i*2],
+ .path = listen[i*2 + 1],
+ .triggered = triggered,
+ .own_triggered = i==0,
+ };
+
+ /* from this point on we will cleanup those socket_infos */
+ cs += c;
+ free(listen);
+ listen = triggered = NULL; /* avoid cleanup */
+ }
+
+ qsort(socket_infos, cs, sizeof(struct socket_info),
+ (__compar_fn_t) socket_info_compare);
+
+ output_sockets_list(socket_infos, cs);
+
+ cleanup:
+ assert(cs == 0 || socket_infos);
+ for (s = socket_infos; s < socket_infos + cs; s++) {
+ free(s->type);
+ free(s->path);
+ if (s->own_triggered)
+ strv_free(s->triggered);
+ }
+ free(socket_infos);
return 0;
}
static bool output_show_unit_file(const UnitFileList *u) {
const char *dot;
- return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
+ return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
}
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
for (u = units; u < units + c; u++) {
- char _cleanup_free_ *e = NULL;
+ _cleanup_free_ char *e = NULL;
const char *on, *off;
const char *id;
size_t len = 0;
size_t max_len = MAX(columns(),20u);
- for (i = level - 1; i >= 0; i--) {
+ if (!arg_plain) {
+ for (i = level - 1; i >= 0; i--) {
+ len += 2;
+ if(len > max_len - 3 && !arg_full) {
+ printf("%s...\n",max_len % 2 ? "" : " ");
+ return 0;
+ }
+ printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
+ }
len += 2;
if(len > max_len - 3 && !arg_full) {
printf("%s...\n",max_len % 2 ? "" : " ");
return 0;
}
- printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
- }
- len += 2;
- if(len > max_len - 3 && !arg_full) {
- printf("%s...\n",max_len % 2 ? "" : " ");
- return 0;
+ printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
}
- printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
if(arg_full){
printf("%s\n", name);
}
static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
- static const char dependencies[] =
- "Requires\0"
- "RequiresOverridable\0"
- "Requisite\0"
- "RequisiteOverridable\0"
- "Wants\0";
+ static const char *dependencies[] = {
+ [DEPENDENCY_FORWARD] = "Requires\0"
+ "RequiresOverridable\0"
+ "Requisite\0"
+ "RequisiteOverridable\0"
+ "Wants\0",
+ [DEPENDENCY_REVERSE] = "RequiredBy\0"
+ "RequiredByOverridable\0"
+ "WantedBy\0"
+ "PartOf\0",
+ [DEPENDENCY_AFTER] = "After\0",
+ [DEPENDENCY_BEFORE] = "Before\0",
+ };
_cleanup_free_ char *path;
const char *interface = "org.freedesktop.systemd1.Unit";
dbus_message_iter_recurse(&sub2, &sub3);
dbus_message_iter_next(&sub);
- if (!nulstr_contains(dependencies, prop))
+ assert(arg_dependency < ELEMENTSOF(dependencies));
+ if (!nulstr_contains(dependencies[arg_dependency], prop))
continue;
if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
return strcasecmp(*a, *b);
}
-static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) {
- char _cleanup_strv_free_ **deps = NULL, **u;
+static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
+ _cleanup_strv_free_ char **deps = NULL, **u;
char **c;
int r = 0;
- u = strv_append(units, name);
+ u = strv_append(*units, name);
if (!u)
return log_oom();
STRV_FOREACH(c, deps) {
if (strv_contains(u, *c)) {
- r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
- if (r < 0)
- return r;
+ if (!arg_plain) {
+ r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
+ if (r < 0)
+ return r;
+ }
continue;
}
return r;
if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
- r = list_dependencies_one(bus, *c, level + 1, u, (branches << 1) | (c[1] == NULL ? 0 : 1));
+ r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
if(r < 0)
return r;
}
}
-
+ if (arg_plain) {
+ strv_free(*units);
+ *units = u;
+ u = NULL;
+ }
return 0;
}
static int list_dependencies(DBusConnection *bus, char **args) {
_cleanup_free_ char *unit = NULL;
+ _cleanup_strv_free_ char **units = NULL;
const char *u;
assert(bus);
puts(u);
- return list_dependencies_one(bus, u, 0, NULL, 0);
+ return list_dependencies_one(bus, u, 0, &units, 0);
+}
+
+static int get_default(DBusConnection *bus, char **args) {
+ char *path = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+ int r;
+ _cleanup_dbus_error_free_ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (!bus || avoid_bus()) {
+ r = unit_file_get_default(arg_scope, arg_root, &path);
+
+ if (r < 0) {
+ log_error("Operation failed: %s", strerror(-r));
+ goto finish;
+ }
+
+ r = 0;
+ } else {
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetDefaultTarget",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+
+ if (r < 0) {
+ log_error("Operation failed: %s", strerror(-r));
+ goto finish;
+ }
+
+ if (!dbus_message_get_args(reply, &error,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID)) {
+ log_error("Failed to parse reply: %s", bus_error_message(&error));
+ dbus_error_free(&error);
+ return -EIO;
+ }
+ }
+
+ if (path)
+ printf("%s\n", path);
+
+finish:
+ if ((!bus || avoid_bus()) && path)
+ free(path);
+
+ return r;
+
}
struct job_info {
for (i = 0, j = jobs; i < n; i++, j++) {
assert(j->name && j->type && j->state);
- l0 = MAX(l0, decimal_str_max(j->id));
+ l0 = MAX(l0, DECIMAL_STR_WIDTH(j->id));
l1 = MAX(l1, strlen(j->name));
l2 = MAX(l2, strlen(j->type));
l3 = MAX(l3, strlen(j->state));
l3, "STATE");
for (i = 0, j = jobs; i < n; i++, j++) {
- char _cleanup_free_ *e = NULL;
+ _cleanup_free_ char *e = NULL;
if (streq(j->state, "running")) {
on = ansi_highlight(true);
goto finish;
}
- if (!greedy_realloc((void**) &jobs, &size,
- sizeof(struct job_info) * (used + 1))) {
+ if (!GREEDY_REALLOC(jobs, size, used + 1)) {
r = log_oom();
goto finish;
}
} WaitData;
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_dbus_error_free_ DBusError error;
WaitData *d = data;
dbus_error_init(&error);
*load_state_property = "LoadState",
*triggered_by_property = "TriggeredBy",
*state;
- char _cleanup_free_ *unit_path = NULL, *n = NULL;
+ _cleanup_free_ char *unit_path = NULL, *n = NULL;
bool print_warning_label = true;
int r;
if (!p)
return log_oom();
- r = set_put(s, p);
+ r = set_consume(s, p);
if (r < 0) {
- free(p);
log_error("Failed to add path to set.");
return r;
}
int r, ret = 0;
const char *method, *mode, *one_name;
- Set _cleanup_set_free_free_ *s = NULL;
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_set_free_free_ Set *s = NULL;
+ _cleanup_dbus_error_free_ DBusError error;
char **name;
dbus_error_init(&error);
if (startswith(*p, "man:")) {
size_t k;
char *e = NULL;
- char _cleanup_free_ *page = NULL, *section = NULL;
+ _cleanup_free_ char *page = NULL, *section = NULL;
const char *args[4] = { "man", NULL, NULL, NULL };
pid_t pid;
/* This is a low-level property printer, see
* print_status_info() for the nicer output */
- if (arg_property && !strv_find(arg_property, name))
+ if (arg_properties && !strv_find(arg_properties, name))
return 0;
switch (dbus_message_iter_get_arg_type(iter)) {
if (exec_status_info_deserialize(&sub, &info) >= 0) {
char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
- char _cleanup_free_ *t;
+ _cleanup_free_ char *t;
t = strv_join(info.argv, " ");
}
static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
- DBusMessage _cleanup_free_ *reply = NULL;
+ _cleanup_free_ DBusMessage *reply = NULL;
const char *interface = "";
int r;
DBusMessageIter iter, sub, sub2, sub3;
static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *path = NULL;
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_dbus_error_free_ DBusError error;
int r;
dbus_error_init(&error);
if (r < 0)
return r;
+ qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+
for (u = unit_infos; u < unit_infos + c; u++) {
- char _cleanup_free_ *p = NULL;
+ _cleanup_free_ char *p = NULL;
if (!output_show_unit(u))
continue;
r = 0;
for (f = 1; args[f]; f++) {
const char *name;
- char *p;
+ _cleanup_free_ char *p = NULL, *q = NULL;
bool found_native = false, found_sysv;
unsigned c = 1;
const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
- char **k, *l, *q = NULL;
+ char **k, *l;
int j;
pid_t pid;
siginfo_t status;
continue;
STRV_FOREACH(k, paths.unit_path) {
- p = NULL;
-
if (!isempty(arg_root))
asprintf(&p, "%s/%s/%s", arg_root, *k, name);
else
found_native = access(p, F_OK) >= 0;
free(p);
+ p = NULL;
if (found_native)
break;
if (found_native)
continue;
- p = NULL;
if (!isempty(arg_root))
asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
else
p[strlen(p) - sizeof(".service") + 1] = 0;
found_sysv = access(p, F_OK) >= 0;
- if (!found_sysv) {
- free(p);
+ if (!found_sysv)
continue;
- }
/* Mark this entry, so that we don't try enabling it as native unit */
args[f] = (char*) "";
l = strv_join((char**)argv, " ");
if (!l) {
- free(q);
- free(p);
r = log_oom();
goto finish;
}
pid = fork();
if (pid < 0) {
log_error("Failed to fork: %m");
- free(p);
- free(q);
r = -errno;
goto finish;
} else if (pid == 0) {
_exit(EXIT_FAILURE);
}
- free(p);
- free(q);
-
j = wait_for_terminate(pid, &status);
if (j < 0) {
log_error("Failed to wait for child: %s", strerror(-r));
UnitFileChange *changes = NULL;
unsigned n_changes = 0, i;
int carries_install_info = -1;
- DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
int r;
- DBusError _cleanup_dbus_error_free_ error;
- char _cleanup_strv_free_ **mangled_names = NULL;
+ _cleanup_dbus_error_free_ DBusError error;
+ _cleanup_strv_free_ char **mangled_names = NULL;
dbus_error_init(&error);
if (!args[1])
return 0;
+ r = mangle_names(args+1, &mangled_names);
+ if (r < 0)
+ goto finish;
+
if (!bus || avoid_bus()) {
if (streq(verb, "enable")) {
- r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+ r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "disable"))
- r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
+ r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
else if (streq(verb, "reenable")) {
- r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+ r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "link"))
- r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+ r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
else if (streq(verb, "preset")) {
- r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+ r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "mask"))
- r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+ r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
else if (streq(verb, "unmask"))
- r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
+ r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
+ else if (streq(verb, "set-default"))
+ r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
else
assert_not_reached("Unknown verb");
else if (streq(verb, "unmask")) {
method = "UnmaskUnitFiles";
send_force = false;
+ } else if (streq(verb, "set-default")) {
+ method = "SetDefaultTarget";
} else
assert_not_reached("Unknown verb");
dbus_message_iter_init_append(m, &iter);
- 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.");
}
static int unit_is_enabled(DBusConnection *bus, char **args) {
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_dbus_error_free_ DBusError error;
int r;
- DBusMessage _cleanup_dbus_message_unref_ *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bool enabled;
char **name;
char *n;
" --version Show package version\n"
" -t --type=TYPE List only units of a particular type\n"
" -p --property=NAME Show only properties by this name\n"
- " -a --all Show all units/properties, including dead/empty ones\n"
+ " -a --all Show all loaded units/properties, including dead/empty\n"
+ " ones. To list all units installed on the system, use\n"
+ " the 'list-unit-files' command instead.\n"
+ " --reverse Show reverse dependencies with 'list-dependencies'\n"
" --failed Show only failed units\n"
" --full Don't ellipsize unit names on output\n"
" --fail When queueing a new job, fail if conflicting jobs are\n"
" pending\n"
+ " --irreversible Create jobs which cannot be implicitly cancelled\n"
+ " --show-types When showing sockets, explicitly show their type\n"
" --ignore-dependencies\n"
" When queueing a new job, ignore all its dependencies\n"
" -i --ignore-inhibitors\n"
" unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
" load [NAME...] Load one or more units\n"
" list-dependencies [NAME] Recursively show units which are required\n"
- " or wanted by this unit\n\n"
+ " or wanted by this unit or by which this\n"
+ " unit is required or wanted\n\n"
"Unit File Commands:\n"
" list-unit-files List installed unit files\n"
" enable [NAME...] Enable one or more unit files\n"
" unmask [NAME...] Unmask one or more units\n"
" link [PATH...] Link one or more units files into\n"
" the search path\n"
+ " get-default Get the name of the default target\n"
+ " set-default NAME Set the default target\n"
" is-enabled [NAME...] Check whether unit files are enabled\n\n"
"Job Commands:\n"
" list-jobs List jobs\n"
enum {
ARG_FAIL = 0x100,
+ ARG_REVERSE,
+ ARG_AFTER,
+ ARG_BEFORE,
+ ARG_SHOW_TYPES,
ARG_IRREVERSIBLE,
ARG_IGNORE_DEPENDENCIES,
ARG_VERSION,
ARG_NO_ASK_PASSWORD,
ARG_FAILED,
ARG_RUNTIME,
- ARG_FORCE
+ ARG_FORCE,
+ ARG_PLAIN
};
static const struct option options[] = {
{ "type", required_argument, NULL, 't' },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
+ { "reverse", no_argument, NULL, ARG_REVERSE },
+ { "after", no_argument, NULL, ARG_AFTER },
+ { "before", no_argument, NULL, ARG_BEFORE },
+ { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
{ "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, ARG_FULL },
{ "fail", no_argument, NULL, ARG_FAIL },
{ "runtime", no_argument, NULL, ARG_RUNTIME },
{ "lines", required_argument, NULL, 'n' },
{ "output", required_argument, NULL, 'o' },
+ { "plain", no_argument, NULL, ARG_PLAIN },
{ NULL, 0, NULL, 0 }
};
puts(SYSTEMD_FEATURES);
return 0;
- case 't':
- if (streq(optarg, "help")) {
- help_types();
- return 0;
- }
+ case 't': {
+ char *word, *state;
+ size_t size;
- if (unit_type_from_string(optarg) >= 0) {
- arg_type = optarg;
- break;
- }
- if (unit_load_state_from_string(optarg) >= 0) {
- arg_load_state = optarg;
- break;
+ FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+ _cleanup_free_ char *type;
+
+ type = strndup(word, size);
+ if (!type)
+ return -ENOMEM;
+
+ if (streq(type, "help")) {
+ help_types();
+ return 0;
+ }
+
+ if (unit_type_from_string(type) >= 0) {
+ if (strv_push(&arg_types, type))
+ return log_oom();
+ type = NULL;
+ continue;
+ }
+
+ if (unit_load_state_from_string(optarg) >= 0) {
+ if (strv_push(&arg_load_states, type))
+ return log_oom();
+ type = NULL;
+ continue;
+ }
+
+ log_error("Unknown unit type or load state '%s'.", type);
+ log_info("Use -t help to see a list of allowed values.");
+ return -EINVAL;
}
- log_error("Unkown unit type or load state '%s'.",
- optarg);
- log_info("Use -t help to see a list of allowed values.");
- return -EINVAL;
+
+ break;
+ }
+
case 'p': {
- char *word, *state;
- size_t size;
/* Make sure that if the empty property list
was specified, we won't show any properties. */
- const char *source = isempty(optarg) ? " " : optarg;
+ if (isempty(optarg) && !arg_properties) {
+ arg_properties = strv_new(NULL, NULL);
+ if (!arg_properties)
+ return log_oom();
+ } else {
+ char *word, *state;
+ size_t size;
- FOREACH_WORD_SEPARATOR(word, size, source, ",", state) {
- char _cleanup_free_ *prop;
- char **tmp;
+ FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+ char *prop;
- prop = strndup(word, size);
- if (!prop)
- return -ENOMEM;
+ prop = strndup(word, size);
+ if (!prop)
+ return log_oom();
- tmp = strv_append(arg_property, prop);
- if (!tmp)
- return -ENOMEM;
-
- strv_free(arg_property);
- arg_property = tmp;
+ if (strv_push(&arg_properties, prop)) {
+ free(prop);
+ return log_oom();
+ }
+ }
}
/* If the user asked for a particular
arg_all = true;
break;
+ case ARG_REVERSE:
+ arg_dependency = DEPENDENCY_REVERSE;
+ break;
+
+ case ARG_AFTER:
+ arg_dependency = DEPENDENCY_AFTER;
+ break;
+
+ case ARG_BEFORE:
+ arg_dependency = DEPENDENCY_BEFORE;
+ break;
+
+ case ARG_SHOW_TYPES:
+ arg_show_types = true;
+ break;
+
case ARG_FAIL:
arg_job_mode = "fail";
break;
arg_ignore_inhibitors = true;
break;
+ case ARG_PLAIN:
+ arg_plain = true;
+ break;
+
case '?':
return -EINVAL;
return systemctl_parse_argv(argc, argv);
}
-static int action_to_runlevel(void) {
+_pure_ static int action_to_runlevel(void) {
static const char table[_ACTION_MAX] = {
[ACTION_HALT] = '0',
}
static int talk_upstart(void) {
- DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_error_free_ DBusError error;
int previous, rl, r;
char
env1_buf[] = "RUNLEVEL=X",
static int talk_initctl(void) {
struct init_request request = {};
int r;
- int _cleanup_close_ fd = -1;
+ _cleanup_close_ int fd = -1;
char rl;
rl = action_to_runlevel();
r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
if (r) {
log_error("Failed to write to "INIT_FIFO": %m");
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
}
return 1;
} verbs[] = {
{ "list-units", LESS, 1, list_units },
{ "list-unit-files", EQUAL, 1, list_unit_files },
+ { "list-sockets", LESS, 1, list_sockets },
{ "list-jobs", EQUAL, 1, list_jobs },
{ "clear-jobs", EQUAL, 1, daemon_reload },
{ "load", MORE, 2, load_unit },
{ "link", MORE, 2, enable_unit },
{ "switch-root", MORE, 2, switch_root },
{ "list-dependencies", LESS, 2, list_dependencies },
+ { "set-default", EQUAL, 2, enable_unit },
+ { "get-default", LESS, 1, get_default },
};
int left;
!streq(verbs[i].verb, "preset") &&
!streq(verbs[i].verb, "mask") &&
!streq(verbs[i].verb, "unmask") &&
- !streq(verbs[i].verb, "link")) {
+ !streq(verbs[i].verb, "link") &&
+ !streq(verbs[i].verb, "set-default") &&
+ !streq(verbs[i].verb, "get-default")) {
if (running_in_chroot() > 0) {
log_info("Running in chroot, ignoring request.");
}
static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
- int _cleanup_close_ fd;
+ _cleanup_close_ int fd;
struct sd_shutdown_command c = {
.usec = t,
.mode = mode,
}
if (arg_when > 0) {
- char _cleanup_free_ *m;
+ _cleanup_free_ char *m;
m = strv_join(arg_wall, " ");
r = send_shutdownd(arg_when,
int main(int argc, char*argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
- DBusError _cleanup_dbus_error_free_ error;
+ _cleanup_dbus_error_free_ DBusError error;
dbus_error_init(&error);
dbus_shutdown();
- strv_free(arg_property);
+ strv_free(arg_types);
+ strv_free(arg_load_states);
+ strv_free(arg_properties);
pager_close();
ask_password_agent_close();