+typedef struct SessionStatusInfo {
+ const char *id;
+ uid_t uid;
+ const char *name;
+ usec_t timestamp;
+ const char *control_group;
+ int vtnr;
+ const char *seat;
+ const char *tty;
+ const char *display;
+ bool remote;
+ const char *remote_host;
+ const char *remote_user;
+ const char *service;
+ pid_t leader;
+ const char *type;
+ bool active;
+} SessionStatusInfo;
+
+typedef struct UserStatusInfo {
+ uid_t uid;
+ const char *name;
+ usec_t timestamp;
+ const char *control_group;
+ const char *state;
+ char **sessions;
+ const char *display;
+} UserStatusInfo;
+
+typedef struct SeatStatusInfo {
+ const char *id;
+ const char *active_session;
+ char **sessions;
+} SeatStatusInfo;
+
+static void print_session_status_info(SessionStatusInfo *i) {
+ char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+ char since2[FORMAT_TIMESTAMP_MAX], *s2;
+ assert(i);
+
+ printf("%s - ", strna(i->id));
+
+ if (i->name)
+ printf("%s (%u)\n", i->name, (unsigned) i->uid);
+ else
+ printf("%u\n", (unsigned) i->uid);
+
+ s1 = format_timestamp_pretty(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) {
+ char *t = NULL;
+
+ printf("\t Leader: %u", (unsigned) i->leader);
+
+ get_process_name(i->leader, &t);
+ if (t) {
+ printf(" (%s)", t);
+ free(t);
+ }
+
+ printf("\n");
+ }
+
+ if (i->seat) {
+ printf("\t Seat: %s", i->seat);
+
+ if (i->vtnr > 0)
+ printf("; vc%i", i->vtnr);
+
+ printf("\n");
+ }
+
+ if (i->tty)
+ printf("\t TTY: %s\n", i->tty);
+ else if (i->display)
+ printf("\t Display: %s\n", i->display);
+
+ if (i->remote_host && i->remote_user)
+ printf("\t Remote: %s@%s\n", i->remote_user, i->remote_host);
+ else if (i->remote_host)
+ printf("\t Remote: %s\n", i->remote_host);
+ else if (i->remote_user)
+ printf("\t Remote: user %s\n", i->remote_user);
+ else if (i->remote)
+ printf("\t Remote: Yes\n");
+
+ if (i->service) {
+ printf("\t Service: %s", i->service);
+
+ if (i->type)
+ printf("; type %s", i->type);
+
+ printf("\n");
+ } else if (i->type)
+ printf("\t Type: %s\n", i->type);
+
+ printf("\t Active: %s\n", yes_no(i->active));
+
+ if (i->control_group) {
+ unsigned c;
+
+ printf("\t CGroup: %s\n", i->control_group);
+
+ if (arg_transport != TRANSPORT_SSH) {
+ c = columns();
+ if (c > 18)
+ c -= 18;
+ else
+ c = 0;
+
+ show_cgroup_by_path(i->control_group, "\t\t ", c);
+ }
+ }
+}
+
+static void print_user_status_info(UserStatusInfo *i) {
+ char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+ char since2[FORMAT_TIMESTAMP_MAX], *s2;
+ assert(i);
+
+ if (i->name)
+ printf("%s (%u)\n", i->name, (unsigned) i->uid);
+ else
+ printf("%u\n", (unsigned) i->uid);
+
+ s1 = format_timestamp_pretty(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 (!isempty(i->state))
+ printf("\t State: %s\n", i->state);
+
+ if (!strv_isempty(i->sessions)) {
+ char **l;
+ printf("\tSessions:");
+
+ STRV_FOREACH(l, i->sessions) {
+ if (streq_ptr(*l, i->display))
+ printf(" *%s", *l);
+ else
+ printf(" %s", *l);
+ }
+
+ printf("\n");
+ }
+
+ if (i->control_group) {
+ unsigned c;
+
+ printf("\t CGroup: %s\n", i->control_group);
+
+ if (arg_transport != TRANSPORT_SSH) {
+ c = columns();
+ if (c > 18)
+ c -= 18;
+ else
+ c = 0;
+
+ show_cgroup_by_path(i->control_group, "\t\t ", c);
+ }
+ }
+}
+
+static void print_seat_status_info(SeatStatusInfo *i) {
+ assert(i);
+
+ printf("%s\n", strna(i->id));
+
+ if (!strv_isempty(i->sessions)) {
+ char **l;
+ printf("\tSessions:");
+
+ STRV_FOREACH(l, i->sessions) {
+ if (streq_ptr(*l, i->active_session))
+ printf(" *%s", *l);
+ else
+ printf(" %s", *l);
+ }
+
+ printf("\n");
+ }
+
+ if (arg_transport != TRANSPORT_SSH) {
+ unsigned c;
+
+ c = columns();
+ if (c > 21)
+ c -= 21;
+ else
+ c = 0;
+
+ printf("\t Devices:\n");
+
+ show_sysfs(i->id, "\t\t ", c);
+ }
+}
+
+static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *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, "Id"))
+ i->id = s;
+ else if (streq(name, "Name"))
+ i->name = s;
+ else if (streq(name, "ControlGroupPath"))
+ i->control_group = s;
+ else if (streq(name, "TTY"))
+ i->tty = s;
+ else if (streq(name, "Display"))
+ i->display = s;
+ else if (streq(name, "RemoteHost"))
+ i->remote_host = s;
+ else if (streq(name, "RemoteUser"))
+ i->remote_user = s;
+ else if (streq(name, "Service"))
+ i->service = s;
+ else if (streq(name, "Type"))
+ i->type = s;
+ }
+ break;
+ }
+
+ case DBUS_TYPE_UINT32: {
+ uint32_t u;
+
+ dbus_message_iter_get_basic(iter, &u);
+
+ if (streq(name, "VTNr"))
+ i->vtnr = (int) u;
+ else if (streq(name, "Leader"))
+ i->leader = (pid_t) u;
+
+ break;
+ }
+
+ case DBUS_TYPE_BOOLEAN: {
+ dbus_bool_t b;
+
+ dbus_message_iter_get_basic(iter, &b);
+
+ if (streq(name, "Remote"))
+ i->remote = b;
+ else if (streq(name, "Active"))
+ i->active = b;
+
+ 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_STRUCT: {
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
+ uint32_t u;
+
+ dbus_message_iter_get_basic(&sub, &u);
+ i->uid = (uid_t) u;
+
+ } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
+ const char *s;
+
+ dbus_message_iter_get_basic(&sub, &s);
+
+ if (!isempty(s))
+ i->seat = s;
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *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, "ControlGroupPath"))
+ i->control_group = s;
+ else if (streq(name, "State"))
+ i->state = s;
+ }
+ break;
+ }
+
+ case DBUS_TYPE_UINT32: {
+ uint32_t u;
+
+ dbus_message_iter_get_basic(iter, &u);
+
+ if (streq(name, "UID"))
+ i->uid = (uid_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_STRUCT: {
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
+ const char *s;
+
+ dbus_message_iter_get_basic(&sub, &s);
+
+ if (!isempty(s))
+ i->display = s;
+ }
+
+ break;
+ }
+
+ case DBUS_TYPE_ARRAY: {
+
+ if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+ DBusMessageIter sub, sub2;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *id;
+ const char *path;
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+ char **l;
+
+ l = strv_append(i->sessions, id);
+ if (!l)
+ return -ENOMEM;
+
+ strv_free(i->sessions);
+ i->sessions = l;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *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, "Id"))
+ i->id = s;
+ }
+ break;
+ }
+
+ case DBUS_TYPE_STRUCT: {
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
+ const char *s;
+
+ dbus_message_iter_get_basic(&sub, &s);
+
+ if (!isempty(s))
+ i->active_session = s;
+ }
+
+ break;
+ }
+
+ case DBUS_TYPE_ARRAY: {
+
+ if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+ DBusMessageIter sub, sub2;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *id;
+ const char *path;
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+ char **l;
+
+ l = strv_append(i->sessions, id);
+ if (!l)
+ return -ENOMEM;
+
+ strv_free(i->sessions);
+ i->sessions = l;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int print_property(const char *name, DBusMessageIter *iter) {
+ assert(name);
+ assert(iter);
+
+ if (arg_property && !strv_find(arg_property, name))
+ return 0;
+
+ switch (dbus_message_iter_get_arg_type(iter)) {
+
+ case DBUS_TYPE_STRUCT: {
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
+ (streq(name, "Display") || streq(name, "ActiveSession"))) {
+ const char *s;
+
+ dbus_message_iter_get_basic(&sub, &s);
+
+ if (arg_all || !isempty(s))
+ printf("%s=%s\n", name, s);
+ return 0;
+ }
+ break;
+ }
+
+ case DBUS_TYPE_ARRAY:
+
+ if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+ DBusMessageIter sub, sub2;
+ bool found = false;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *id;
+ const char *path;
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+ if (found)
+ printf(" %s", id);
+ else {
+ printf("%s=%s", name, id);
+ found = true;
+ }
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ if (!found && arg_all)
+ printf("%s=\n", name);
+ else if (found)
+ printf("\n");
+
+ return 0;
+ }
+
+ break;
+ }
+
+ if (generic_print_property(name, iter, arg_all) > 0)
+ return 0;
+
+ if (arg_all)
+ printf("%s=[unprintable]\n", name);
+
+ return 0;
+}
+
+static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
+ DBusMessage *m = NULL, *reply = NULL;
+ const char *interface = "";
+ int r;
+ DBusError error;
+ DBusMessageIter iter, sub, sub2, sub3;
+ SessionStatusInfo session_info;
+ UserStatusInfo user_info;
+ SeatStatusInfo seat_info;
+
+ assert(bus);
+ assert(path);
+ assert(new_line);
+
+ zero(session_info);
+ zero(user_info);
+ zero(seat_info);
+
+ dbus_error_init(&error);
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll");
+ if (!m) {
+ log_error("Could not allocate message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ r = -EIO;
+ goto finish;
+ }
+
+ 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_DICT_ENTRY) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (*new_line)
+ printf("\n");
+
+ *new_line = true;
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *name;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&sub2, &sub3);
+
+ if (show_properties)
+ r = print_property(name, &sub3);
+ else if (strstr(verb, "session"))
+ r = status_property_session(name, &sub3, &session_info);
+ else if (strstr(verb, "user"))
+ r = status_property_user(name, &sub3, &user_info);
+ else
+ r = status_property_seat(name, &sub3, &seat_info);
+
+ if (r < 0) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ if (!show_properties) {
+ if (strstr(verb, "session"))
+ print_session_status_info(&session_info);
+ else if (strstr(verb, "user"))
+ print_user_status_info(&user_info);
+ else
+ print_seat_status_info(&seat_info);
+ }
+
+ strv_free(seat_info.sessions);
+ strv_free(user_info.sessions);
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int show(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int r, ret = 0;
+ DBusError error;
+ unsigned i;
+ bool show_properties, new_line = false;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ show_properties = !strstr(args[0], "status");
+
+ if (show_properties)
+ pager_open_if_enabled();
+
+ if (show_properties && n <= 1) {
+ /* If not argument is specified inspect the manager
+ * itself */
+
+ ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
+ goto finish;
+ }
+
+ for (i = 1; i < n; i++) {
+ const char *path = NULL;
+
+ if (strstr(args[0], "session")) {
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "GetSession");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ } else if (strstr(args[0], "user")) {
+ uid_t uid;
+ uint32_t u;
+
+ r = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+ if (r < 0) {
+ log_error("User %s unknown.", args[i]);
+ r = -ENOENT;
+ goto finish;
+ }
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "GetUser");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ u = (uint32_t) uid;
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &u,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+ } else {
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "GetSeat");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ 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));
+ ret = -EIO;
+ goto finish;
+ }
+
+ r = show_one(args[0], bus, path, show_properties, &new_line);
+ if (r != 0)
+ ret = r;
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int activate(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 1; i < n; i++) {
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ streq(args[0], "lock-session") ? "LockSession" :
+ streq(args[0], "unlock-session") ? "UnlockSession" :
+ streq(args[0], "terminate-session") ? "TerminateSession" :
+ "ActivateSession");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int kill_session(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ if (!arg_kill_who)
+ arg_kill_who = "all";
+
+ for (i = 1; i < n; i++) {
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "KillSession");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_STRING, &arg_kill_who,
+ DBUS_TYPE_INT32, arg_signal,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+ dbus_bool_t b, interactive = true;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ b = streq(args[0], "enable-linger");
+
+ for (i = 1; i < n; i++) {
+ uint32_t u;
+ uid_t uid;
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetUserLinger");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+ if (ret < 0) {
+ log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
+ goto finish;
+ }
+
+ u = (uint32_t) uid;
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &u,
+ DBUS_TYPE_BOOLEAN, &b,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 1; i < n; i++) {
+ uint32_t u;
+ uid_t uid;
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "TerminateUser");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+ if (ret < 0) {
+ log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
+ goto finish;
+ }
+
+ u = (uint32_t) uid;
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &u,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int kill_user(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ if (!arg_kill_who)
+ arg_kill_who = "all";
+
+ for (i = 1; i < n; i++) {
+ uid_t uid;
+ uint32_t u;
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "KillUser");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+ if (ret < 0) {
+ log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
+ goto finish;
+ }
+
+ u = (uint32_t) uid;
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &u,
+ DBUS_TYPE_INT32, arg_signal,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int attach(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+ dbus_bool_t interactive = true;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 2; i < n; i++) {
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "AttachDevice");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[1],
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ dbus_bool_t interactive = true;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "FlushDevices");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int ret = 0;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 1; i < n; i++) {
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "TerminateSeat");
+ if (!m) {
+ log_error("Could not allocate message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &args[i],
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to issue method call: %s", bus_error_message(&error));
+ ret = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+