loginctl.c revision c529695e7a30b300fdaa61ace4a8a4ed0e94ad1c
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering/***
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering This file is part of systemd.
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering Copyright 2010 Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering systemd is free software; you can redistribute it and/or modify it
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering under the terms of the GNU Lesser General Public License as published by
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering (at your option) any later version.
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering systemd is distributed in the hope that it will be useful, but
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering Lesser General Public License for more details.
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering You should have received a copy of the GNU Lesser General Public License
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering***/
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include <unistd.h>
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include <errno.h>
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include <string.h>
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include <getopt.h>
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include <pwd.h>
0591220f339c313761f9a208e88fb719db566993Zbigniew Jędrzejewski-Szmek#include <locale.h>
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering
6482f6269c87d2249e52e889a63adbdd50f2d691Ronny Chevalier#include "sd-bus.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "bus-util.h"
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering#include "bus-error.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "log.h"
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering#include "util.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "macro.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "pager.h"
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering#include "build.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "strv.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "unit-name.h"
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering#include "sysfs-show.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "logs-show.h"
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering#include "cgroup-show.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "cgroup-util.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering#include "spawn-polkit-agent.h"
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering#include "verbs.h"
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic char **arg_property = NULL;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poetteringstatic bool arg_all = false;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poetteringstatic bool arg_full = false;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic bool arg_no_pager = false;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic bool arg_legend = true;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic const char *arg_kill_who = NULL;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic int arg_signal = SIGTERM;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic char *arg_host = NULL;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic bool arg_ask_password = true;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic unsigned arg_lines = 10;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic OutputMode arg_output = OUTPUT_SHORT;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic void pager_open_if_enabled(void) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (arg_no_pager)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering pager_open(false);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering /* Open the polkit agent as a child process if necessary */
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (!arg_ask_password)
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (arg_transport != BUS_TRANSPORT_LOCAL)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering polkit_agent_open();
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering}
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poetteringstatic OutputFlags get_output_flags(void) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering arg_all * OUTPUT_SHOW_ALL |
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering arg_full * OUTPUT_FULL_WIDTH |
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering on_tty() * OUTPUT_COLOR;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poetteringstatic int list_sessions(int argc, char *argv[], void *userdata) {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *id, *user, *seat, *object;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering sd_bus *bus = userdata;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering unsigned k = 0;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering uint32_t uid;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering int r;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering assert(bus);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering assert(argv);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering pager_open_if_enabled();
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_call_method(
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering bus,
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering "org.freedesktop.login1",
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering "/org/freedesktop/login1",
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering "org.freedesktop.login1.Manager",
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering "ListSessions",
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering &error, &reply,
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering "");
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering if (r < 0) {
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering log_error("Failed to list sessions: %s", bus_error_message(&error, r));
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return r;
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering }
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering r = sd_bus_message_enter_container(reply, 'a', "(susso)");
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering if (r < 0)
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering return bus_log_parse_error(r);
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering if (arg_legend)
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering k++;
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering }
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering if (r < 0)
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering return bus_log_parse_error(r);
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering if (arg_legend)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering printf("\n%u sessions listed.\n", k);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return 0;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poetteringstatic int list_users(int argc, char *argv[], void *userdata) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering const char *user, *object;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering sd_bus *bus = userdata;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering unsigned k = 0;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering uint32_t uid;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering int r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering assert(bus);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering assert(argv);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann pager_open_if_enabled();
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_call_method(
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering bus,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "org.freedesktop.login1",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "/org/freedesktop/login1",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "org.freedesktop.login1.Manager",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "ListUsers",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering &error, &reply,
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering "");
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0) {
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering log_error("Failed to list users: %s", bus_error_message(&error, r));
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return r;
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering }
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering
7de80bfe2e61d5818601ccfddbadad3b7703ed70Karel Zak r = sd_bus_message_enter_container(reply, 'a', "(uso)");
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering return bus_log_parse_error(r);
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering if (arg_legend)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering printf("%10s %-16s\n", "UID", "USER");
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering printf("%10u %-16s\n", (unsigned) uid, user);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering k++;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering }
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (r < 0)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return bus_log_parse_error(r);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (arg_legend)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering printf("\n%u users listed.\n", k);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return 0;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering}
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poetteringstatic int list_seats(int argc, char *argv[], void *userdata) {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *seat, *object;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering sd_bus *bus = userdata;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering unsigned k = 0;
7de80bfe2e61d5818601ccfddbadad3b7703ed70Karel Zak int r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering assert(bus);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering assert(argv);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering pager_open_if_enabled();
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering r = sd_bus_call_method(
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering bus,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "org.freedesktop.login1",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "/org/freedesktop/login1",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "org.freedesktop.login1.Manager",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "ListSeats",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering &error, &reply,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "");
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (r < 0) {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering log_error("Failed to list seats: %s", bus_error_message(&error, r));
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering }
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering r = sd_bus_message_enter_container(reply, 'a', "(so)");
067d851d30386c553e3a84f59d81d003ff638b91Daniel Wallace if (r < 0)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return bus_log_parse_error(r);
7de80bfe2e61d5818601ccfddbadad3b7703ed70Karel Zak
067d851d30386c553e3a84f59d81d003ff638b91Daniel Wallace if (arg_legend)
067d851d30386c553e3a84f59d81d003ff638b91Daniel Wallace printf("%-16s\n", "SEAT");
7de80bfe2e61d5818601ccfddbadad3b7703ed70Karel Zak
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering printf("%-16s\n", seat);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering k++;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering }
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return bus_log_parse_error(r);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering if (arg_legend)
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering printf("\n%u seats listed.\n", k);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return 0;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poetteringstatic int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann _cleanup_free_ char *path = NULL;
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering const char *cgroup;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering int r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering unsigned c;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering assert(bus);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering assert(unit);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (arg_transport != BUS_TRANSPORT_LOCAL)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return 0;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering path = unit_dbus_path_from_name(unit);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (!path)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return -ENOMEM;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering r = sd_bus_get_property(
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering bus,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "org.freedesktop.systemd1",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering path,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering interface,
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering "ControlGroup",
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering &error, &reply, "s");
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (r < 0)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering r = sd_bus_message_read(reply, "s", &cgroup);
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (r < 0)
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering if (isempty(cgroup))
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return 0;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return 0;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering c = columns();
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (c > 18)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering c -= 18;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering else
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering c = 0;
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering return 0;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poetteringtypedef struct SessionStatusInfo {
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering const char *id;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering uid_t uid;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann const char *name;
3ef63c317481c2b3f1fe39e1b0f130aac3544522Lennart Poettering struct dual_timestamp timestamp;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering unsigned int vtnr;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *seat;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *tty;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *display;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering bool remote;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *remote_host;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *remote_user;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *service;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann pid_t leader;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering const char *type;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *class;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *state;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *scope;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *desktop;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering} SessionStatusInfo;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poetteringtypedef struct UserStatusInfo {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering uid_t uid;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *name;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering struct dual_timestamp timestamp;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *state;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering char **sessions;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *display;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *slice;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering} UserStatusInfo;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poetteringtypedef struct SeatStatusInfo {
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering const char *id;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering const char *active_session;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering char **sessions;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering} SeatStatusInfo;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poetteringstatic int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering const char *contents;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering int r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering r = sd_bus_message_peek_type(m, NULL, &contents);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (contents[0] == 's' || contents[0] == 'o') {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering const char *s;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering char **p = (char **) userdata;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_message_read_basic(m, contents[0], &s);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering free(*p);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering *p = strdup(s);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (!*p)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return -ENOMEM;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering } else {
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering r = sd_bus_message_read_basic(m, contents[0], userdata);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering }
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering r = sd_bus_message_skip(m, contents+1);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_message_exit_container(m);
dca348bcbb462305864526c587495a14a76bfcdeJan Engelhardt if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2Lennart Poettering
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering return 0;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poetteringstatic int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering const char *name;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering int r;
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering assert(bus);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek assert(m);
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = sd_bus_message_enter_container(m, 'a', "(so)");
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = strv_extend(userdata, name);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering }
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
696fd1ef4f2f8574e349332a16987c6772641eddLennart Poettering return sd_bus_message_exit_container(m);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering}
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
067d851d30386c553e3a84f59d81d003ff638b91Daniel Wallacestatic int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering static const struct bus_properties_map map[] = {
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
6569cae18ed640a4e9f52f73e2a3ec54b07d0406Lennart Poettering { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering {}
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering };
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering char since2[FORMAT_TIMESTAMP_MAX], *s2;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering SessionStatusInfo i = {};
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering int r;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (r < 0)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering return log_error_errno(r, "Could not get properties: %m");
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (*new_line)
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering printf("\n");
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering *new_line = true;
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering printf("%s - ", strna(i.id));
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (i.name)
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering printf("%s (%u)\n", i.name, (unsigned) i.uid);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering else
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering printf("%u\n", (unsigned) i.uid);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
41f9172f427bdbb8221c64029f78364b8dd4e527Lennart Poettering 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);
printf("\n");
}
if (!isempty(i.seat)) {
printf("\t Seat: %s", i.seat);
if (i.vtnr > 0)
printf("; vc%u", 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);
if (i.class)
printf("; class %s", i.class);
printf("\n");
} else if (i.type) {
printf("\t Type: %s", i.type);
if (i.class)
printf("; class %s", i.class);
printf("\n");
} else if (i.class)
printf("\t Class: %s\n", i.class);
if (!isempty(i.desktop))
printf("\t Desktop: %s\n", i.desktop);
if (i.state)
printf("\t State: %s\n", i.state);
if (i.scope) {
printf("\t Unit: %s\n", i.scope);
show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
if (arg_transport == BUS_TRANSPORT_LOCAL) {
show_journal_by_unit(
stdout,
i.scope,
arg_output,
0,
i.timestamp.monotonic,
arg_lines,
0,
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
SD_JOURNAL_LOCAL_ONLY,
true,
NULL);
}
}
return 0;
}
static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(UserStatusInfo, name) },
{ "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
{ "State", "s", NULL, offsetof(UserStatusInfo, state) },
{ "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
{ "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
{ "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
{ "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
{ "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
{}
};
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char since2[FORMAT_TIMESTAMP_MAX], *s2;
UserStatusInfo i = {};
int r;
r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
if (r < 0) {
log_error_errno(r, "Could not get properties: %m");
goto finish;
}
if (*new_line)
printf("\n");
*new_line = true;
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.realtime);
s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
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.slice) {
printf("\t Unit: %s\n", i.slice);
show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
show_journal_by_unit(
stdout,
i.slice,
arg_output,
0,
i.timestamp.monotonic,
arg_lines,
0,
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
SD_JOURNAL_LOCAL_ONLY,
true,
NULL);
}
finish:
strv_free(i.sessions);
return r;
}
static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
{ "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
{ "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
{}
};
SeatStatusInfo i = {};
int r;
r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
if (r < 0) {
log_error_errno(r, "Could not get properties: %m");
goto finish;
}
if (*new_line)
printf("\n");
*new_line = true;
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 == BUS_TRANSPORT_LOCAL) {
unsigned c;
c = columns();
if (c > 21)
c -= 21;
else
c = 0;
printf("\t Devices:\n");
show_sysfs(i.id, "\t\t ", c);
}
finish:
strv_free(i.sessions);
return r;
}
static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
if (*new_line)
printf("\n");
*new_line = true;
r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
static int show_session(int argc, char *argv[], void *userdata) {
bool properties, new_line = false;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (argc <= 1) {
/* If not argument is specified inspect the manager
* itself */
if (properties)
return show_properties(bus, "/org/freedesktop/login1", &new_line);
/* And in the pretty case, show data of the calling session */
return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
}
for (i = 1; i < argc; i++) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
const char *path = NULL;
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetSession",
&error, &reply,
"s", argv[i]);
if (r < 0) {
log_error("Failed to get session: %s", bus_error_message(&error, r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_properties(bus, path, &new_line);
else
r = print_session_status_info(bus, path, &new_line);
if (r < 0)
return r;
}
return 0;
}
static int show_user(int argc, char *argv[], void *userdata) {
bool properties, new_line = false;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (argc <= 1) {
/* If not argument is specified inspect the manager
* itself */
if (properties)
return show_properties(bus, "/org/freedesktop/login1", &new_line);
return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
}
for (i = 1; i < argc; i++) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
const char *path = NULL;
uid_t uid;
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetUser",
&error, &reply,
"u", (uint32_t) uid);
if (r < 0) {
log_error("Failed to get user: %s", bus_error_message(&error, r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_properties(bus, path, &new_line);
else
r = print_user_status_info(bus, path, &new_line);
if (r < 0)
return r;
}
return 0;
}
static int show_seat(int argc, char *argv[], void *userdata) {
bool properties, new_line = false;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (argc <= 1) {
/* If not argument is specified inspect the manager
* itself */
if (properties)
return show_properties(bus, "/org/freedesktop/login1", &new_line);
return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
}
for (i = 1; i < argc; i++) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
const char *path = NULL;
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetSeat",
&error, &reply,
"s", argv[i]);
if (r < 0) {
log_error("Failed to get seat: %s", bus_error_message(&error, r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_properties(bus, path, &new_line);
else
r = print_seat_status_info(bus, path, &new_line);
if (r < 0)
return r;
}
return 0;
}
static int activate(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
char *short_argv[3];
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
if (argc < 2) {
/* No argument? Let's convert this into the empty
* session name, which the calls will then resolve to
* the caller's session. */
short_argv[0] = argv[0];
short_argv[1] = (char*) "";
short_argv[2] = NULL;
argv = short_argv;
argc = 2;
}
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
streq(argv[0], "lock-session") ? "LockSession" :
streq(argv[0], "unlock-session") ? "UnlockSession" :
streq(argv[0], "terminate-session") ? "TerminateSession" :
"ActivateSession",
&error, NULL,
"s", argv[i]);
if (r < 0) {
log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int kill_session(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
if (!arg_kill_who)
arg_kill_who = "all";
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"KillSession",
&error, NULL,
"ssi", argv[i], arg_kill_who, arg_signal);
if (r < 0) {
log_error("Could not kill session: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int enable_linger(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
char* short_argv[3];
bool b;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
b = streq(argv[0], "enable-linger");
if (argc < 2) {
short_argv[0] = argv[0];
short_argv[1] = (char*) "";
short_argv[2] = NULL;
argv = short_argv;
argc = 2;
}
for (i = 1; i < argc; i++) {
uid_t uid;
if (isempty(argv[i]))
uid = UID_INVALID;
else {
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
}
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"SetUserLinger",
&error, NULL,
"ubb", (uint32_t) uid, b, true);
if (r < 0) {
log_error("Could not enable linger: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int terminate_user(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
uid_t uid;
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"TerminateUser",
&error, NULL,
"u", (uint32_t) uid);
if (r < 0) {
log_error("Could not terminate user: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int kill_user(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
if (!arg_kill_who)
arg_kill_who = "all";
for (i = 1; i < argc; i++) {
uid_t uid;
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"KillUser",
&error, NULL,
"ui", (uint32_t) uid, arg_signal);
if (r < 0) {
log_error("Could not kill user: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int attach(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
for (i = 2; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"AttachDevice",
&error, NULL,
"ssb", argv[1], argv[i], true);
if (r < 0) {
log_error("Could not attach device: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int flush_devices(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"FlushDevices",
&error, NULL,
"b", true);
if (r < 0)
log_error("Could not flush devices: %s", bus_error_message(&error, -r));
return r;
}
static int lock_sessions(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
&error, NULL,
NULL);
if (r < 0)
log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
return r;
}
static int terminate_seat(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
assert(argv);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"TerminateSeat",
&error, NULL,
"s", argv[i]);
if (r < 0) {
log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
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"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --no-ask-password Don't prompt for password\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" -p --property=NAME Show only properties by this name\n"
" -a --all Show all properties, including empty ones\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" -n --lines=INTEGER Number of journal entries to show\n"
" -o --output=STRING Change journal output mode (short, short-monotonic,\n"
" verbose, export, json, json-pretty, json-sse, cat)\n\n"
"Session Commands:\n"
" list-sessions List sessions\n"
" session-status [ID...] Show session status\n"
" show-session [ID...] Show properties of sessions or the manager\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\n"
"User Commands:\n"
" list-users List users\n"
" user-status [USER...] Show user status\n"
" show-user [USER...] Show properties of users or the manager\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\n"
"Seat Commands:\n"
" list-seats List seats\n"
" seat-status [NAME...] Show seat status\n"
" show-seat [NAME...] Show properties of seats or the manager\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"
, program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
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 },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "lines", required_argument, NULL, 'n' },
{ "output", required_argument, NULL, 'o' },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
switch (c) {
case 'h':
help(0, NULL, NULL);
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case 'p': {
r = strv_extend(&arg_property, optarg);
if (r < 0)
return log_oom();
/* 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 'n':
if (safe_atou(optarg, &arg_lines) < 0) {
log_error("Failed to parse lines '%s'", optarg);
return -EINVAL;
}
break;
case 'o':
arg_output = output_mode_from_string(optarg);
if (arg_output < 0) {
log_error("Unknown output '%s'.", optarg);
return -EINVAL;
}
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
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 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
arg_transport = BUS_TRANSPORT_MACHINE;
arg_host = optarg;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
return 1;
}
static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
{ "session-status", VERB_ANY, VERB_ANY, 0, show_session },
{ "show-session", VERB_ANY, VERB_ANY, 0, show_session },
{ "activate", VERB_ANY, 2, 0, activate },
{ "lock-session", VERB_ANY, VERB_ANY, 0, activate },
{ "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
{ "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
{ "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
{ "terminate-session", 2, VERB_ANY, 0, activate },
{ "kill-session", 2, VERB_ANY, 0, kill_session },
{ "list-users", VERB_ANY, 1, 0, list_users },
{ "user-status", VERB_ANY, VERB_ANY, 0, show_user },
{ "show-user", VERB_ANY, VERB_ANY, 0, show_user },
{ "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
{ "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
{ "terminate-user", 2, VERB_ANY, 0, terminate_user },
{ "kill-user", 2, VERB_ANY, 0, kill_user },
{ "list-seats", VERB_ANY, 1, 0, list_seats },
{ "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
{ "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
{ "attach", 3, VERB_ANY, 0, attach },
{ "flush-devices", VERB_ANY, 1, 0, flush_devices },
{ "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
{}
};
return dispatch_verb(argc, argv, verbs, bus);
}
int main(int argc, char *argv[]) {
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
r = loginctl_main(argc, argv, bus);
finish:
pager_close();
polkit_agent_close();
strv_free(arg_property);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}