loginctl.c revision 9444b1f20e311f073864d81e913bd4f32fe95cfd
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2010 Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <dbus/dbus.h>
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <unistd.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <errno.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <string.h>
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include <getopt.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <pwd.h>
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering#include <locale.h>
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "log.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "util.h"
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include "macro.h"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen#include "pager.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "dbus-common.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "build.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "strv.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "cgroup-show.h"
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering#include "sysfs-show.h"
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek#include "spawn-polkit-agent.h"
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic char **arg_property = NULL;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic bool arg_all = false;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic bool arg_full = false;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic bool arg_no_pager = false;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic const char *arg_kill_who = NULL;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic int arg_signal = SIGTERM;
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poetteringstatic enum transport {
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek TRANSPORT_NORMAL,
f8294e4175918117ca6c131720bcf287eadcd029Josh Triplett TRANSPORT_SSH,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek TRANSPORT_POLKIT
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} arg_transport = TRANSPORT_NORMAL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic bool arg_ask_password = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic char *arg_host = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic char *arg_user = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void pager_open_if_enabled(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Cache result before we open the pager */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_no_pager)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pager_open(false);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Open the polkit agent as a child process if necessary */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!arg_ask_password)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering polkit_agent_open();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int list_sessions(DBusConnection *bus, char **args, unsigned n) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBusMessageIter iter, sub, sub2;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned k = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pager_open_if_enabled();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering r = bus_method_call_with_reply (
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering bus,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1",
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering "/org/freedesktop/login1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1.Manager",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "ListSessions",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &reply,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBUS_TYPE_INVALID);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering dbus_message_iter_recurse(&iter, &sub);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (on_tty())
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *id, *user, *seat, *object;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt uint32_t uid;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_recurse(&sub, &sub2);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering k++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_next(&sub);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (on_tty())
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\n%u sessions listed.\n", k);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int list_users(DBusConnection *bus, char **args, unsigned n) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBusMessageIter iter, sub, sub2;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned k = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pager_open_if_enabled();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = bus_method_call_with_reply (
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "/org/freedesktop/login1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1.Manager",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "ListUsers",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &reply,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBUS_TYPE_INVALID);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_recurse(&iter, &sub);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (on_tty())
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("%10s %-16s\n", "UID", "USER");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *user, *object;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint32_t uid;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_recurse(&sub, &sub2);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek printf("%10u %-16s\n", (unsigned) uid, user);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering k++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_next(&sub);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (on_tty())
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\n%u users listed.\n", k);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int list_seats(DBusConnection *bus, char **args, unsigned n) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek DBusMessageIter iter, sub, sub2;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned k = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pager_open_if_enabled();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = bus_method_call_with_reply (
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "/org/freedesktop/login1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.login1.Manager",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "ListSeats",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &reply,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBUS_TYPE_INVALID);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_iter_recurse(&iter, &sub);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (on_tty())
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("%-16s\n", "SEAT");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek const char *seat, *object;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Failed to parse reply.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EIO;
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_recurse(&sub, &sub2);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_error("Failed to parse reply.");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -EIO;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering printf("%-16s\n", seat);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering k++;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_next(&sub);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (on_tty())
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering printf("\n%u seats listed.\n", k);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int list_machines(DBusConnection *bus, char **args, unsigned n) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering DBusMessageIter iter, sub, sub2;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering unsigned k = 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek pager_open_if_enabled();
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = bus_method_call_with_reply (
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bus,
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek "org.freedesktop.login1",
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek "/org/freedesktop/login1",
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek "org.freedesktop.login1.Manager",
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek "ListMachines",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering &reply,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering NULL,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering DBUS_TYPE_INVALID);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_error("Failed to parse reply.");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -EIO;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_recurse(&iter, &sub);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (on_tty())
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *name, *class, *service, *object;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_error("Failed to parse reply.");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -EIO;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_recurse(&sub, &sub2);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &class, true) < 0 ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &service, true) < 0 ||
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_error("Failed to parse reply.");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -EIO;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering printf("%-32s %-9s %-16s\n", name, class, service);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering k++;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering dbus_message_iter_next(&sub);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (on_tty())
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering printf("\n%u machines listed.\n", k);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringtypedef struct SessionStatusInfo {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *id;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uid_t uid;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *name;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering usec_t timestamp;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *default_control_group;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int vtnr;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *seat;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *tty;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *display;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bool remote;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *remote_host;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *remote_user;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *service;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering pid_t leader;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *type;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *class;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *state;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *slice;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering} SessionStatusInfo;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringtypedef struct UserStatusInfo {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uid_t uid;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *name;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering usec_t timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *default_control_group;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *state;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering char **sessions;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering const char *display;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *slice;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} UserStatusInfo;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poetteringtypedef struct SeatStatusInfo {
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering const char *id;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering const char *active_session;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char **sessions;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} SeatStatusInfo;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poetteringtypedef struct MachineStatusInfo {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *name;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering sd_id128_t id;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *default_control_group;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *class;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *service;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *slice;
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek const char *root_directory;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pid_t leader;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering usec_t timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} MachineStatusInfo;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void print_session_status_info(SessionStatusInfo *i) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char since2[FORMAT_TIMESTAMP_MAX], *s2;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(i);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("%s - ", strna(i->id));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->name)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("%s (%u)\n", i->name, (unsigned) i->uid);
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen else
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen printf("%u\n", (unsigned) i->uid);
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering if (s1)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Since: %s; %s\n", s2, s1);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering else if (s2)
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering printf("\t Since: %s\n", s2);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering if (i->leader > 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *t = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering printf("\t Leader: %u", (unsigned) i->leader);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering get_process_comm(i->leader, &t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (t)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf(" (%s)", t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering printf("\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->seat) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Seat: %s", i->seat);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->vtnr > 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("; vc%i", i->vtnr);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek printf("\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->tty)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering printf("\t TTY: %s\n", i->tty);
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering else if (i->display)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Display: %s\n", i->display);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->remote_host && i->remote_user)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Remote: %s@%s\n", i->remote_user, i->remote_host);
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering else if (i->remote_host)
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek printf("\t Remote: %s\n", i->remote_host);
03ee5c38cb0da193dd08733fb4c0c2809cee6a99Lennart Poettering else if (i->remote_user)
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek printf("\t Remote: user %s\n", i->remote_user);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else if (i->remote)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Remote: Yes\n");
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (i->service) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Service: %s", i->service);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->type)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("; type %s", i->type);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (i->class)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("; class %s", i->class);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (i->type) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Type: %s\n", i->type);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (i->class)
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt printf("; class %s", i->class);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (i->class)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Class: %s\n", i->class);
6baa7db00812437bbc87e73faa1a11b6cf631958Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering if (i->state)
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering printf("\t State: %s\n", i->state);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering if (i->slice)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering printf("\t Slice: %s\n", i->slice);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (i->default_control_group) {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt unsigned c;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt int output_flags =
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering arg_all * OUTPUT_SHOW_ALL |
8531ae707d4d0203e83304d4af948b8169a5fce1Lennart Poettering arg_full * OUTPUT_FULL_WIDTH;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt printf("\t CGroup: %s\n", i->default_control_group);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_transport != TRANSPORT_SSH) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering c = columns();
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (c > 18)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering c -= 18;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering else
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering c = 0;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering show_cgroup_and_extra_by_spec(i->default_control_group,
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering "\t\t ", c, false, &i->leader,
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering i->leader > 0 ? 1 : 0,
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering output_flags);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering}
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poetteringstatic void print_user_status_info(UserStatusInfo *i) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering char since2[FORMAT_TIMESTAMP_MAX], *s2;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering assert(i);
if (i->name)
printf("%s (%u)\n", i->name, (unsigned) i->uid);
else
printf("%u\n", (unsigned) i->uid);
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 (!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:");
STRV_FOREACH(l, i->sessions) {
if (streq_ptr(*l, i->display))
printf(" *%s", *l);
else
printf(" %s", *l);
}
printf("\n");
}
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_by_path(i->default_control_group, "\t\t ",
c, false, output_flags);
}
}
}
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 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);
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, "DefaultControlGroup"))
i->default_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;
else if (streq(name, "Class"))
i->class = s;
else if (streq(name, "Slice"))
i->slice = 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, "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;
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, "DefaultControlGroup"))
i->default_control_group = s;
else if (streq(name, "Slice"))
i->slice = 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 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);
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) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *interface = "";
int r;
DBusMessageIter iter, sub, sub2, sub3;
SessionStatusInfo session_info = {};
UserStatusInfo user_info = {};
SeatStatusInfo seat_info = {};
MachineStatusInfo machine_info = {};
assert(path);
assert(new_line);
r = bus_method_call_with_reply(
bus,
"org.freedesktop.login1",
path,
"org.freedesktop.DBus.Properties",
"GetAll",
&reply,
NULL,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_INVALID);
if (r < 0)
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 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.");
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 if (strstr(verb, "seat"))
print_seat_status_info(&seat_info);
else
print_machine_status_info(&machine_info);
}
r = 0;
finish:
strv_free(seat_info.sessions);
strv_free(user_info.sessions);
return r;
}
static int show(DBusConnection *bus, char **args, unsigned n) {
_cleanup_dbus_message_unref_ DBusMessage *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");
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")) {
ret = bus_method_call_with_reply (
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetSession",
&reply,
NULL,
DBUS_TYPE_STRING, &args[i],
DBUS_TYPE_INVALID);
} else if (strstr(args[0], "user")) {
uid_t uid;
uint32_t u;
ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
if (ret < 0) {
log_error("User %s unknown.", args[i]);
goto finish;
}
u = (uint32_t) uid;
ret = bus_method_call_with_reply(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetUser",
&reply,
NULL,
DBUS_TYPE_UINT32, &u,
DBUS_TYPE_INVALID);
} else if (strstr(args[0], "seat")) {
ret = bus_method_call_with_reply(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetSeat",
&reply,
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 < 0)
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;
}
finish:
dbus_error_free(&error);
return ret;
}
static int activate(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",
streq(args[0], "lock-session") ? "LockSession" :
streq(args[0], "unlock-session") ? "UnlockSession" :
streq(args[0], "terminate-session") ? "TerminateSession" :
"ActivateSession",
NULL,
NULL,
DBUS_TYPE_STRING, &args[i],
DBUS_TYPE_INVALID);
if (ret)
goto finish;
}
finish:
return ret;
}
static int kill_session(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",
"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;
}
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) {
unsigned i;
dbus_bool_t b, interactive = true;
assert(args);
polkit_agent_open_if_enabled();
b = streq(args[0], "enable-linger");
for (i = 1; i < n; i++) {
uint32_t u;
uid_t uid;
int r;
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;
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;
}
return 0;
}
static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
unsigned i;
assert(args);
for (i = 1; i < n; i++) {
uint32_t u;
uid_t uid;
int r;
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;
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;
}
return 0;
}
static int kill_user(DBusConnection *bus, char **args, unsigned n) {
unsigned i;
assert(args);
if (!arg_kill_who)
arg_kill_who = "all";
for (i = 1; i < n; i++) {
uid_t uid;
uint32_t u;
int r;
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;
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;
}
return 0;
}
static int attach(DBusConnection *bus, char **args, unsigned n) {
unsigned i;
dbus_bool_t interactive = true;
assert(args);
polkit_agent_open_if_enabled();
for (i = 2; i < n; i++) {
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;
}
return 0;
}
static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
dbus_bool_t interactive = true;
assert(args);
polkit_agent_open_if_enabled();
return bus_method_call_with_reply (
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"FlushDevices",
NULL,
NULL,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID);
}
static int lock_sessions(DBusConnection *bus, char **args, unsigned n) {
assert(args);
polkit_agent_open_if_enabled();
return bus_method_call_with_reply (
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
NULL,
NULL,
DBUS_TYPE_INVALID);
}
static int terminate_seat(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",
"TerminateSeat",
NULL,
NULL,
DBUS_TYPE_STRING, &args[i],
DBUS_TYPE_INVALID);
if (r)
return r;
}
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) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Send control commands to or query the login manager.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -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"
" -P --privileged Acquire privileges before execution\n"
" --no-pager Do not pipe output into a pager\n\n"
"Commands:\n"
" list-sessions List sessions\n"
" session-status [ID...] Show session status\n"
" show-session [ID...] Show properties of one or more sessions\n"
" activate [ID] Activate a session\n"
" 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"
" user-status [USER...] Show user status\n"
" show-user [USER...] Show properties of one or more users\n"
" enable-linger [USER...] Enable linger state of one or more users\n"
" disable-linger [USER...] Disable linger state of one or more users\n"
" terminate-user [USER...] Terminate all sessions of one or more users\n"
" kill-user [USER...] Send signal to processes of a user\n"
" list-seats List seats\n"
" seat-status [NAME...] Show seat status\n"
" 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"
" 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;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_KILL_WHO,
ARG_NO_ASK_PASSWORD,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "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' },
{ "host", required_argument, NULL, 'H' },
{ "privileged", no_argument, NULL, 'P' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hp:als:H:P", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case 'p': {
char **l;
l = strv_append(arg_property, optarg);
if (!l)
return -ENOMEM;
strv_free(arg_property);
arg_property = l;
/* If the user asked for a particular
* property, show it to him, even if it is
* empty. */
arg_all = true;
break;
}
case 'a':
arg_all = true;
break;
case 'l':
arg_full = true;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case ARG_KILL_WHO:
arg_kill_who = optarg;
break;
case 's':
arg_signal = signal_from_string_try_harder(optarg);
if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
break;
case 'P':
arg_transport = TRANSPORT_POLKIT;
break;
case 'H':
arg_transport = TRANSPORT_SSH;
parse_user_at_host(optarg, &arg_user, &arg_host);
break;
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
return 1;
}
static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
static const struct {
const char* verb;
const enum {
MORE,
LESS,
EQUAL
} argc_cmp;
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 },
{ "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;
unsigned i;
assert(argc >= 0);
assert(argv);
assert(error);
left = argc - optind;
if (left <= 0)
/* Special rule: no arguments means "list-sessions" */
i = 0;
else {
if (streq(argv[optind], "help")) {
help();
return 0;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;
if (i >= ELEMENTSOF(verbs)) {
log_error("Unknown operation %s", argv[optind]);
return -EINVAL;
}
}
switch (verbs[i].argc_cmp) {
case EQUAL:
if (left != verbs[i].argc) {
log_error("Invalid number of arguments.");
return -EINVAL;
}
break;
case MORE:
if (left < verbs[i].argc) {
log_error("Too few arguments.");
return -EINVAL;
}
break;
case LESS:
if (left > verbs[i].argc) {
log_error("Too many arguments.");
return -EINVAL;
}
break;
default:
assert_not_reached("Unknown comparison operator.");
}
if (!bus) {
log_error("Failed to get D-Bus connection: %s", error->message);
return -EIO;
}
return verbs[i].dispatch(bus, argv + optind, left);
}
int main(int argc, char*argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
DBusError error;
dbus_error_init(&error);
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r < 0)
goto finish;
else if (r == 0) {
retval = EXIT_SUCCESS;
goto finish;
}
if (arg_transport == TRANSPORT_NORMAL)
bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
else if (arg_transport == TRANSPORT_POLKIT)
bus_connect_system_polkit(&bus, &error);
else if (arg_transport == TRANSPORT_SSH)
bus_connect_system_ssh(NULL, arg_host, &bus, &error);
else
assert_not_reached("Uh, invalid transport...");
r = loginctl_main(bus, argc, argv, &error);
retval = r < 0 ? EXIT_FAILURE : r;
finish:
if (bus) {
dbus_connection_flush(bus);
dbus_connection_close(bus);
dbus_connection_unref(bus);
}
dbus_error_free(&error);
dbus_shutdown();
strv_free(arg_property);
pager_close();
return retval;
}