X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Floginctl.c;h=3637a408dcdf0a339a2e8f8fe3f7b086a5a2076b;hb=6a95dff87daf899a96135c7ab87aa1b1a67f6afc;hp=cfbc5fe02b7be66060c765f96fd6f4832b71a0ce;hpb=9185c8e6266d607df665d24f525b48b39e20d847;p=elogind.git diff --git a/src/login/loginctl.c b/src/login/loginctl.c index cfbc5fe02..3637a408d 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -40,6 +40,7 @@ static char **arg_property = NULL; static bool arg_all = false; +static bool arg_full = false; static bool arg_no_pager = false; static const char *arg_kill_who = NULL; static int arg_signal = SIGTERM; @@ -49,7 +50,8 @@ static enum transport { TRANSPORT_POLKIT } arg_transport = TRANSPORT_NORMAL; static bool arg_ask_password = true; -static const char *arg_host = NULL; +static char *arg_host = NULL; +static char *arg_user = NULL; static void pager_open_if_enabled(void) { @@ -57,7 +59,7 @@ static void pager_open_if_enabled(void) { if (arg_no_pager) return; - pager_open(); + pager_open(false); } static void polkit_agent_open_if_enabled(void) { @@ -71,7 +73,7 @@ static void polkit_agent_open_if_enabled(void) { } static int list_sessions(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; int r; DBusMessageIter iter, sub, sub2; unsigned k = 0; @@ -88,14 +90,13 @@ static int list_sessions(DBusConnection *bus, char **args, unsigned n) { NULL, DBUS_TYPE_INVALID); if (r) - goto finish; + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -109,8 +110,7 @@ static int list_sessions(DBusConnection *bus, char **args, unsigned n) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -121,8 +121,7 @@ static int list_sessions(DBusConnection *bus, char **args, unsigned n) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat); @@ -135,17 +134,11 @@ static int list_sessions(DBusConnection *bus, char **args, unsigned n) { if (on_tty()) printf("\n%u sessions listed.\n", k); - r = 0; - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int list_users(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; int r; DBusMessageIter iter, sub, sub2; unsigned k = 0; @@ -162,14 +155,13 @@ static int list_users(DBusConnection *bus, char **args, unsigned n) { NULL, DBUS_TYPE_INVALID); if (r) - goto finish; + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -183,8 +175,7 @@ static int list_users(DBusConnection *bus, char **args, unsigned n) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -193,8 +184,7 @@ static int list_users(DBusConnection *bus, char **args, unsigned n) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } printf("%10u %-16s\n", (unsigned) uid, user); @@ -207,17 +197,11 @@ static int list_users(DBusConnection *bus, char **args, unsigned n) { if (on_tty()) printf("\n%u users listed.\n", k); - r = 0; - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int list_seats(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; int r; DBusMessageIter iter, sub, sub2; unsigned k = 0; @@ -234,14 +218,13 @@ static int list_seats(DBusConnection *bus, char **args, unsigned n) { NULL, DBUS_TYPE_INVALID); if (r) - goto finish; + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -254,8 +237,7 @@ static int list_seats(DBusConnection *bus, char **args, unsigned n) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -263,8 +245,7 @@ static int list_seats(DBusConnection *bus, char **args, unsigned n) { if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } printf("%-16s\n", seat); @@ -277,13 +258,70 @@ static int list_seats(DBusConnection *bus, char **args, unsigned n) { if (on_tty()) printf("\n%u seats listed.\n", k); - r = 0; + return 0; +} -finish: - if (reply) - dbus_message_unref(reply); +static int list_machines(DBusConnection *bus, char **args, unsigned n) { + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + DBusMessageIter iter, sub, sub2; + unsigned k = 0; + int r; - return r; + pager_open_if_enabled(); + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListMachines", + &reply, + NULL, + DBUS_TYPE_INVALID); + if (r) + return r; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + return -EIO; + } + + dbus_message_iter_recurse(&iter, &sub); + + if (on_tty()) + printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE"); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *name, *class, *service, *object; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + return -EIO; + } + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &class, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &service, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { + log_error("Failed to parse reply."); + return -EIO; + } + + printf("%-32s %-9s %-16s\n", name, class, service); + + k++; + + dbus_message_iter_next(&sub); + } + + if (on_tty()) + printf("\n%u machines listed.\n", k); + + return 0; } typedef struct SessionStatusInfo { @@ -304,6 +342,7 @@ typedef struct SessionStatusInfo { const char *type; const char *class; const char *state; + const char *slice; } SessionStatusInfo; typedef struct UserStatusInfo { @@ -314,6 +353,7 @@ typedef struct UserStatusInfo { const char *state; char **sessions; const char *display; + const char *slice; } UserStatusInfo; typedef struct SeatStatusInfo { @@ -322,6 +362,18 @@ typedef struct SeatStatusInfo { char **sessions; } SeatStatusInfo; +typedef struct MachineStatusInfo { + const char *name; + sd_id128_t id; + const char *default_control_group; + const char *class; + const char *service; + const char *slice; + const char *root_directory; + pid_t leader; + usec_t timestamp; +} MachineStatusInfo; + static void print_session_status_info(SessionStatusInfo *i) { char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; @@ -343,15 +395,13 @@ static void print_session_status_info(SessionStatusInfo *i) { printf("\t Since: %s\n", s2); if (i->leader > 0) { - char *t = NULL; + _cleanup_free_ char *t = NULL; printf("\t Leader: %u", (unsigned) i->leader); get_process_comm(i->leader, &t); - if (t) { + if (t) printf(" (%s)", t); - free(t); - } printf("\n"); } @@ -400,8 +450,14 @@ static void print_session_status_info(SessionStatusInfo *i) { if (i->state) printf("\t State: %s\n", i->state); + if (i->slice) + printf("\t Slice: %s\n", i->slice); + if (i->default_control_group) { unsigned c; + int output_flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH; printf("\t CGroup: %s\n", i->default_control_group); @@ -412,7 +468,10 @@ static void print_session_status_info(SessionStatusInfo *i) { else c = 0; - show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, &i->leader, i->leader > 0 ? 1 : 0); + show_cgroup_and_extra_by_spec(i->default_control_group, + "\t\t ", c, false, &i->leader, + i->leader > 0 ? 1 : 0, + output_flags); } } } @@ -438,6 +497,9 @@ static void print_user_status_info(UserStatusInfo *i) { if (!isempty(i->state)) printf("\t State: %s\n", i->state); + if (i->slice) + printf("\t Slice: %s\n", i->slice); + if (!strv_isempty(i->sessions)) { char **l; printf("\tSessions:"); @@ -454,6 +516,9 @@ static void print_user_status_info(UserStatusInfo *i) { if (i->default_control_group) { unsigned c; + int output_flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH; printf("\t CGroup: %s\n", i->default_control_group); @@ -464,7 +529,8 @@ static void print_user_status_info(UserStatusInfo *i) { else c = 0; - show_cgroup_by_path(i->default_control_group, "\t\t ", c, false, arg_all); + show_cgroup_by_path(i->default_control_group, "\t\t ", + c, false, output_flags); } } } @@ -503,6 +569,76 @@ static void print_seat_status_info(SeatStatusInfo *i) { } } +static void print_machine_status_info(MachineStatusInfo *i) { + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; + char since2[FORMAT_TIMESTAMP_MAX], *s2; + assert(i); + + fputs(strna(i->name), stdout); + + if (!sd_id128_equal(i->id, SD_ID128_NULL)) + printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id)); + else + putchar('\n'); + + s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp); + s2 = format_timestamp(since2, sizeof(since2), i->timestamp); + + if (s1) + printf("\t Since: %s; %s\n", s2, s1); + else if (s2) + printf("\t Since: %s\n", s2); + + if (i->leader > 0) { + _cleanup_free_ char *t = NULL; + + printf("\t Leader: %u", (unsigned) i->leader); + + get_process_comm(i->leader, &t); + if (t) + printf(" (%s)", t); + + putchar('\n'); + } + + if (i->service) { + printf("\t Service: %s", i->service); + + if (i->class) + printf("; class %s", i->class); + + putchar('\n'); + } else if (i->class) + printf("\t Class: %s\n", i->class); + + if (i->slice) + printf("\t Slice: %s\n", i->slice); + if (i->root_directory) + printf("\t Root: %s\n", i->root_directory); + + if (i->default_control_group) { + unsigned c; + int output_flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH; + + printf("\t CGroup: %s\n", i->default_control_group); + + if (arg_transport != TRANSPORT_SSH) { + c = columns(); + if (c > 18) + c -= 18; + else + c = 0; + + show_cgroup_and_extra_by_spec(i->default_control_group, + "\t\t ", c, false, &i->leader, + i->leader > 0 ? 1 : 0, + output_flags); + } + } +} + static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) { assert(name); assert(iter); @@ -536,6 +672,8 @@ static int status_property_session(const char *name, DBusMessageIter *iter, Sess i->type = s; else if (streq(name, "Class")) i->class = s; + else if (streq(name, "Slice")) + i->slice = s; else if (streq(name, "State")) i->state = s; } @@ -621,6 +759,8 @@ static int status_property_user(const char *name, DBusMessageIter *iter, UserSta i->name = s; else if (streq(name, "DefaultControlGroup")) i->default_control_group = s; + else if (streq(name, "Slice")) + i->slice = s; else if (streq(name, "State")) i->state = s; } @@ -772,6 +912,80 @@ static int status_property_seat(const char *name, DBusMessageIter *iter, SeatSta return 0; } +static int status_property_machine(const char *name, DBusMessageIter *iter, MachineStatusInfo *i) { + assert(name); + assert(iter); + assert(i); + + switch (dbus_message_iter_get_arg_type(iter)) { + + case DBUS_TYPE_STRING: { + const char *s; + + dbus_message_iter_get_basic(iter, &s); + + if (!isempty(s)) { + if (streq(name, "Name")) + i->name = s; + else if (streq(name, "DefaultControlGroup")) + i->default_control_group = s; + else if (streq(name, "Class")) + i->class = s; + else if (streq(name, "Service")) + i->service = s; + else if (streq(name, "Slice")) + i->slice = s; + else if (streq(name, "RootDirectory")) + i->root_directory = s; + } + break; + } + + case DBUS_TYPE_UINT32: { + uint32_t u; + + dbus_message_iter_get_basic(iter, &u); + + if (streq(name, "Leader")) + i->leader = (pid_t) u; + + break; + } + + case DBUS_TYPE_UINT64: { + uint64_t u; + + dbus_message_iter_get_basic(iter, &u); + + if (streq(name, "Timestamp")) + i->timestamp = (usec_t) u; + + break; + } + + case DBUS_TYPE_ARRAY: { + DBusMessageIter sub; + + dbus_message_iter_recurse(iter, &sub); + + if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE && streq(name, "Id")) { + void *v; + int n; + + dbus_message_iter_get_fixed_array(&sub, &v, &n); + if (n == 0) + i->id = SD_ID128_NULL; + else if (n == 16) + memcpy(&i->id, v, n); + } + + break; + } + } + + return 0; +} + static int print_property(const char *name, DBusMessageIter *iter) { assert(name); assert(iter); @@ -850,17 +1064,14 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo const char *interface = ""; int r; DBusMessageIter iter, sub, sub2, sub3; - SessionStatusInfo session_info; - UserStatusInfo user_info; - SeatStatusInfo seat_info; + SessionStatusInfo session_info = {}; + UserStatusInfo user_info = {}; + SeatStatusInfo seat_info = {}; + MachineStatusInfo machine_info = {}; assert(path); assert(new_line); - zero(session_info); - zero(user_info); - zero(seat_info); - r = bus_method_call_with_reply( bus, "org.freedesktop.login1", @@ -920,8 +1131,10 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo r = status_property_session(name, &sub3, &session_info); else if (strstr(verb, "user")) r = status_property_user(name, &sub3, &user_info); - else + else if (strstr(verb, "seat")) r = status_property_seat(name, &sub3, &seat_info); + else + r = status_property_machine(name, &sub3, &machine_info); if (r < 0) { log_error("Failed to parse reply."); @@ -936,8 +1149,10 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo print_session_status_info(&session_info); else if (strstr(verb, "user")) print_user_status_info(&user_info); - else + else if (strstr(verb, "seat")) print_seat_status_info(&seat_info); + else + print_machine_status_info(&machine_info); } r = 0; @@ -950,7 +1165,7 @@ finish: } static int show(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; int r, ret = 0; DBusError error; unsigned i; @@ -1000,7 +1215,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) { } u = (uint32_t) uid; - ret = bus_method_call_with_reply ( + ret = bus_method_call_with_reply( bus, "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1010,9 +1225,10 @@ static int show(DBusConnection *bus, char **args, unsigned n) { NULL, DBUS_TYPE_UINT32, &u, DBUS_TYPE_INVALID); - } else { - ret = bus_method_call_with_reply ( + } else if (strstr(args[0], "seat")) { + + ret = bus_method_call_with_reply( bus, "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1022,8 +1238,22 @@ static int show(DBusConnection *bus, char **args, unsigned n) { NULL, DBUS_TYPE_STRING, &args[i], DBUS_TYPE_INVALID); + + } else { + + ret = bus_method_call_with_reply( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "GetMachine", + &reply, + NULL, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_INVALID); } - if (ret) + + if (ret < 0) goto finish; if (!dbus_message_get_args(reply, &error, @@ -1037,15 +1267,9 @@ static int show(DBusConnection *bus, char **args, unsigned n) { r = show_one(args[0], bus, path, show_properties, &new_line); if (r != 0) ret = r; - - dbus_message_unref(reply); - reply = NULL; } finish: - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; @@ -1081,7 +1305,6 @@ finish: } static int kill_session(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; assert(args); @@ -1090,28 +1313,58 @@ static int kill_session(DBusConnection *bus, char **args, unsigned n) { arg_kill_who = "all"; for (i = 1; i < n; i++) { - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "KillSession", - NULL, - NULL, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_STRING, &arg_kill_who, - DBUS_TYPE_INT32, &arg_signal, - DBUS_TYPE_INVALID); - if (ret) - goto finish; + int r; + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "KillSession", + NULL, + NULL, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_STRING, &arg_kill_who, + DBUS_TYPE_INT32, &arg_signal, + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; +} + +static int kill_machine(DBusConnection *bus, char **args, unsigned n) { + unsigned i; + + assert(args); + + if (!arg_kill_who) + arg_kill_who = "all"; + + for (i = 1; i < n; i++) { + int r; + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "KillMachine", + NULL, + NULL, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_STRING, &arg_kill_who, + DBUS_TYPE_INT32, &arg_signal, + DBUS_TYPE_INVALID); + if (r) + return r; + } + + return 0; } static int enable_linger(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; dbus_bool_t b, interactive = true; @@ -1124,36 +1377,35 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) { for (i = 1; i < n; i++) { uint32_t u; uid_t uid; + int r; - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); - if (ret < 0) { - log_error("Failed to resolve user %s: %s", args[i], strerror(-ret)); - goto finish; + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to resolve user %s: %s", args[i], strerror(-r)); + return r; } u = (uint32_t) uid; - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetUserLinger", - NULL, - NULL, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_BOOLEAN, &b, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID); - if (ret) - goto finish; + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "SetUserLinger", + NULL, + NULL, + DBUS_TYPE_UINT32, &u, + DBUS_TYPE_BOOLEAN, &b, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; } static int terminate_user(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; assert(args); @@ -1161,34 +1413,33 @@ static int terminate_user(DBusConnection *bus, char **args, unsigned n) { for (i = 1; i < n; i++) { uint32_t u; uid_t uid; + int r; - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); - if (ret < 0) { - log_error("Failed to look up user %s: %s", args[i], strerror(-ret)); - goto finish; + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; } u = (uint32_t) uid; - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "TerminateUser", - NULL, - NULL, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_INVALID); - if (ret) - goto finish; + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "TerminateUser", + NULL, + NULL, + DBUS_TYPE_UINT32, &u, + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; } static int kill_user(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; assert(args); @@ -1199,35 +1450,34 @@ static int kill_user(DBusConnection *bus, char **args, unsigned n) { for (i = 1; i < n; i++) { uid_t uid; uint32_t u; + int r; - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); - if (ret < 0) { - log_error("Failed to look up user %s: %s", args[i], strerror(-ret)); - goto finish; + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; } u = (uint32_t) uid; - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "KillUser", - NULL, - NULL, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_INT32, &arg_signal, - DBUS_TYPE_INVALID); - if (ret) - goto finish; + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "KillUser", + NULL, + NULL, + DBUS_TYPE_UINT32, &u, + DBUS_TYPE_INT32, &arg_signal, + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; } static int attach(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; dbus_bool_t interactive = true; @@ -1236,24 +1486,25 @@ static int attach(DBusConnection *bus, char **args, unsigned n) { polkit_agent_open_if_enabled(); for (i = 2; i < n; i++) { - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "AttachDevice", - NULL, - NULL, - DBUS_TYPE_STRING, &args[1], - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID); - if (ret) - goto finish; + int r; + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "AttachDevice", + NULL, + NULL, + DBUS_TYPE_STRING, &args[1], + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; } static int flush_devices(DBusConnection *bus, char **args, unsigned n) { @@ -1276,6 +1527,8 @@ static int flush_devices(DBusConnection *bus, char **args, unsigned n) { } static int lock_sessions(DBusConnection *bus, char **args, unsigned n) { + assert(args); + polkit_agent_open_if_enabled(); return bus_method_call_with_reply ( @@ -1283,35 +1536,60 @@ static int lock_sessions(DBusConnection *bus, char **args, unsigned n) { "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", - "LockSessions", + streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions", NULL, NULL, DBUS_TYPE_INVALID); } static int terminate_seat(DBusConnection *bus, char **args, unsigned n) { - int ret = 0; unsigned i; assert(args); for (i = 1; i < n; i++) { - ret = bus_method_call_with_reply ( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "TerminateSeat", - NULL, - NULL, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_INVALID); - if (ret) - goto finish; + int r; + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "TerminateSeat", + NULL, + NULL, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_INVALID); + if (r) + return r; } -finish: - return ret; + return 0; +} + +static int terminate_machine(DBusConnection *bus, char **args, unsigned n) { + unsigned i; + + assert(args); + + for (i = 1; i < n; i++) { + int r; + + r = bus_method_call_with_reply ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "TerminateMachine", + NULL, + NULL, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_INVALID); + if (r) + return r; + } + + return 0; } static int help(void) { @@ -1323,6 +1601,7 @@ static int help(void) { " -p --property=NAME Show only properties by this name\n" " -a --all Show all properties, including empty ones\n" " --kill-who=WHO Who to send signal to\n" + " -l --full Do not ellipsize output\n" " -s --signal=SIGNAL Which signal to send\n" " --no-ask-password Don't prompt for password\n" " -H --host=[USER@]HOST Show information for remote host\n" @@ -1336,6 +1615,7 @@ static int help(void) { " lock-session [ID...] Screen lock one or more sessions\n" " unlock-session [ID...] Screen unlock one or more sessions\n" " lock-sessions Screen lock all current sessions\n" + " unlock-sessions Screen unlock all current sessions\n" " terminate-session [ID...] Terminate one or more sessions\n" " kill-session [ID...] Send signal to processes of a session\n" " list-users List users\n" @@ -1350,7 +1630,12 @@ static int help(void) { " show-seat [NAME...] Show properties of one or more seats\n" " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n" " flush-devices Flush all device associations\n" - " terminate-seat [NAME...] Terminate all sessions on one or more seats\n", + " terminate-seat [NAME...] Terminate all sessions on one or more seats\n" + " list-machines List running VMs and containers\n" + " machine-status [NAME...] Show VM/container status\n" + " show-machine [NAME...] Show properties of one or more VMs/containers\n" + " terminate-machine [NAME...] Terminate one or more VMs/containers\n" + " kill-machine [NAME...] Send signal to processes of a VM/container\n", program_invocation_short_name); return 0; @@ -1362,7 +1647,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_NO_PAGER, ARG_KILL_WHO, - ARG_NO_ASK_PASSWORD + ARG_NO_ASK_PASSWORD, }; static const struct option options[] = { @@ -1370,6 +1655,7 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "property", required_argument, NULL, 'p' }, { "all", no_argument, NULL, 'a' }, + { "full", no_argument, NULL, 'l' }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "kill-who", required_argument, NULL, ARG_KILL_WHO }, { "signal", required_argument, NULL, 's' }, @@ -1384,7 +1670,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hp:als:H:P", options, NULL)) >= 0) { switch (c) { @@ -1394,7 +1680,6 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: puts(PACKAGE_STRING); - puts(DISTRIBUTION); puts(SYSTEMD_FEATURES); return 0; @@ -1419,6 +1704,10 @@ static int parse_argv(int argc, char *argv[]) { arg_all = true; break; + case 'l': + arg_full = true; + break; + case ARG_NO_PAGER: arg_no_pager = true; break; @@ -1445,7 +1734,7 @@ static int parse_argv(int argc, char *argv[]) { case 'H': arg_transport = TRANSPORT_SSH; - arg_host = optarg; + parse_user_at_host(optarg, &arg_user, &arg_host); break; case '?': @@ -1472,28 +1761,34 @@ static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError const int argc; int (* const dispatch)(DBusConnection *bus, char **args, unsigned n); } verbs[] = { - { "list-sessions", LESS, 1, list_sessions }, - { "session-status", MORE, 2, show }, - { "show-session", MORE, 1, show }, - { "activate", EQUAL, 2, activate }, - { "lock-session", MORE, 2, activate }, - { "unlock-session", MORE, 2, activate }, - { "lock-sessions", EQUAL, 1, lock_sessions }, - { "terminate-session", MORE, 2, activate }, - { "kill-session", MORE, 2, kill_session }, - { "list-users", EQUAL, 1, list_users }, - { "user-status", MORE, 2, show }, - { "show-user", MORE, 1, show }, - { "enable-linger", MORE, 2, enable_linger }, - { "disable-linger", MORE, 2, enable_linger }, - { "terminate-user", MORE, 2, terminate_user }, - { "kill-user", MORE, 2, kill_user }, - { "list-seats", EQUAL, 1, list_seats }, - { "seat-status", MORE, 2, show }, - { "show-seat", MORE, 1, show }, - { "attach", MORE, 3, attach }, - { "flush-devices", EQUAL, 1, flush_devices }, - { "terminate-seat", MORE, 2, terminate_seat }, + { "list-sessions", LESS, 1, list_sessions }, + { "session-status", MORE, 2, show }, + { "show-session", MORE, 1, show }, + { "activate", EQUAL, 2, activate }, + { "lock-session", MORE, 2, activate }, + { "unlock-session", MORE, 2, activate }, + { "lock-sessions", EQUAL, 1, lock_sessions }, + { "unlock-sessions", EQUAL, 1, lock_sessions }, + { "terminate-session", MORE, 2, activate }, + { "kill-session", MORE, 2, kill_session }, + { "list-users", EQUAL, 1, list_users }, + { "user-status", MORE, 2, show }, + { "show-user", MORE, 1, show }, + { "enable-linger", MORE, 2, enable_linger }, + { "disable-linger", MORE, 2, enable_linger }, + { "terminate-user", MORE, 2, terminate_user }, + { "kill-user", MORE, 2, kill_user }, + { "list-seats", EQUAL, 1, list_seats }, + { "seat-status", MORE, 2, show }, + { "show-seat", MORE, 1, show }, + { "attach", MORE, 3, attach }, + { "flush-devices", EQUAL, 1, flush_devices }, + { "terminate-seat", MORE, 2, terminate_seat }, + { "list-machines", EQUAL, 1, list_machines }, + { "machine-status", MORE, 2, show }, + { "show-machine", MORE, 1, show }, + { "terminate-machine", MORE, 2, terminate_machine }, + { "kill-machine", MORE, 2, kill_machine }, }; int left;