1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-11 09:18:07 +03:00

shared/wall: use logind if build without utmp support

If systemd is build without utmp support, use sd_get_sessions() in
utmp_wall() to get a list of logged in users with the corresponding tty.
This commit is contained in:
Thorsten Kukuk 2023-09-04 10:08:13 +02:00 committed by Luca Boccassi
parent 468018703c
commit 53c0397b1d
10 changed files with 227 additions and 153 deletions

View File

@ -6,7 +6,7 @@
#include "journald-wall.h"
#include "process-util.h"
#include "string-util.h"
#include "utmp-wtmp.h"
#include "wall.h"
void server_forward_wall(
Server *s,
@ -48,7 +48,7 @@ void server_forward_wall(
} else
l = message;
r = utmp_wall(l, "systemd-journald", NULL, NULL, NULL);
r = wall(l, "systemd-journald", NULL, NULL, NULL);
if (r < 0)
log_debug_errno(r, "Failed to send wall message: %m");
}

View File

@ -57,6 +57,7 @@
#include "user-util.h"
#include "utmp-wtmp.h"
#include "virt.h"
#include "wall.h"
/* As a random fun fact sysvinit had a 252 (256-(strlen(" \r\n")+1))
* character limit for the wall message.
@ -2342,8 +2343,8 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_CANCELED_STR,
username ? "OPERATOR=%s" : NULL, username);
utmp_wall("System shutdown has been cancelled",
username, tty, logind_wall_tty_filter, m);
(void) wall("System shutdown has been cancelled",
username, tty, logind_wall_tty_filter, m);
}
reset_scheduled_shutdown(m);

View File

@ -18,7 +18,7 @@
#include "strv.h"
#include "unit-name.h"
#include "user-util.h"
#include "utmp-wtmp.h"
#include "wall.h"
static usec_t when_wall(usec_t n, usec_t elapse) {
static const int wall_timers[] = {
@ -94,7 +94,7 @@ static int warn_wall(Manager *m, usec_t n) {
username ? "OPERATOR=%s" : NULL, username);
if (m->enable_wall_messages)
utmp_wall(l, username, m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
(void) wall(l, username, m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
return 1;
}

View File

@ -26,7 +26,7 @@ liblogind_core_sources = files(
'logind-session.c',
'logind-user-dbus.c',
'logind-user.c',
'logind-utmp.c',
'logind-wall.c',
)
liblogind_core_sources += [logind_gperf_c]

View File

@ -168,6 +168,7 @@ shared_sources = files(
'verbs.c',
'vlan-util.c',
'volatile-util.c',
'wall.c',
'watchdog.c',
'web-util.c',
'wifi-util.c',

View File

@ -280,130 +280,3 @@ int utmp_put_runlevel(int runlevel, int previous) {
return write_entry_both(&store);
}
#define TIMEOUT_USEC (50 * USEC_PER_MSEC)
static int write_to_terminal(const char *tty, const char *message) {
_cleanup_close_ int fd = -EBADF;
const char *p;
size_t left;
usec_t end;
assert(tty);
assert(message);
fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
if (!isatty(fd))
return -ENOTTY;
p = message;
left = strlen(message);
end = usec_add(now(CLOCK_MONOTONIC), TIMEOUT_USEC);
while (left > 0) {
ssize_t n;
usec_t t;
int k;
t = now(CLOCK_MONOTONIC);
if (t >= end)
return -ETIME;
k = fd_wait_for_event(fd, POLLOUT, end - t);
if (ERRNO_IS_NEG_TRANSIENT(k))
continue;
if (k < 0)
return k;
if (k == 0)
return -ETIME;
n = write(fd, p, left);
if (n < 0) {
if (ERRNO_IS_TRANSIENT(errno))
continue;
return -errno;
}
assert((size_t) n <= left);
p += n;
left -= n;
}
return 0;
}
int utmp_wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata) {
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
_cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
struct utmpx *u;
int r;
hn = gethostname_malloc();
if (!hn)
return -ENOMEM;
if (!username) {
un = getlogname_malloc();
if (!un)
return -ENOMEM;
}
if (!origin_tty) {
getttyname_harder(STDIN_FILENO, &stdin_tty);
origin_tty = stdin_tty;
}
if (asprintf(&text,
"\r\n"
"Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
"%s\r\n\r\n",
un ?: username, hn,
origin_tty ? " on " : "", strempty(origin_tty),
FORMAT_TIMESTAMP(now(CLOCK_REALTIME)),
message) < 0)
return -ENOMEM;
utmpx = utxent_start();
r = 0;
while ((u = getutxent())) {
_cleanup_free_ char *buf = NULL;
const char *path;
int q;
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
continue;
/* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */
if (path_startswith(u->ut_line, "/dev/"))
path = u->ut_line;
else {
if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
return -ENOMEM;
path = buf;
}
/* It seems that the address field is always set for remote logins.
* For local logins and other local entries, we get [0,0,0,0]. */
bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6));
if (!match_tty || match_tty(path, is_local, userdata)) {
q = write_to_terminal(path, text);
if (q < 0)
r = q;
}
}
return r;
}

View File

@ -18,13 +18,6 @@ int utmp_put_runlevel(int runlevel, int previous);
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user);
int utmp_wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata);
static inline bool utxent_start(void) {
setutxent();
return true;
@ -54,13 +47,5 @@ static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int
static inline int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user) {
return 0;
}
static inline int utmp_wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata) {
return 0;
}
#endif /* ENABLE_UTMP */

203
src/shared/wall.c Normal file
View File

@ -0,0 +1,203 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
#include "sd-login.h"
#include "errno-util.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "io-util.h"
#include "path-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "user-util.h"
#include "utmp-wtmp.h"
#include "wall.h"
#define TIMEOUT_USEC (50 * USEC_PER_MSEC)
static int write_to_terminal(const char *tty, const char *message) {
_cleanup_close_ int fd = -EBADF;
const char *p;
size_t left;
usec_t end;
assert(tty);
assert(message);
fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
if (!isatty(fd))
return -ENOTTY;
p = message;
left = strlen(message);
end = usec_add(now(CLOCK_MONOTONIC), TIMEOUT_USEC);
while (left > 0) {
ssize_t n;
usec_t t;
int k;
t = now(CLOCK_MONOTONIC);
if (t >= end)
return -ETIME;
k = fd_wait_for_event(fd, POLLOUT, end - t);
if (ERRNO_IS_NEG_TRANSIENT(k))
continue;
if (k < 0)
return k;
if (k == 0)
return -ETIME;
n = write(fd, p, left);
if (n < 0) {
if (ERRNO_IS_TRANSIENT(errno))
continue;
return -errno;
}
assert((size_t) n <= left);
p += n;
left -= n;
}
return 0;
}
#if ENABLE_UTMP
static int do_wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata) {
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
struct utmpx *u;
int r;
utmpx = utxent_start();
r = 0;
while ((u = getutxent())) {
_cleanup_free_ char *buf = NULL;
const char *path;
int q;
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
continue;
/* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */
if (path_startswith(u->ut_line, "/dev/"))
path = u->ut_line;
else {
if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
return -ENOMEM;
path = buf;
}
/* It seems that the address field is always set for remote logins.
* For local logins and other local entries, we get [0,0,0,0]. */
bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6));
if (!match_tty || match_tty(path, is_local, userdata)) {
q = write_to_terminal(path, message);
if (q < 0)
r = q;
}
}
return r;
}
#else
static int do_wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata) {
int r;
_cleanup_strv_free_ char **sessions = NULL;
r = sd_get_sessions(&sessions);
if (r < 0)
return r;
STRV_FOREACH(s, sessions) {
_cleanup_free_ char *path = NULL, *tty = NULL, *rhost = NULL;
int q;
q = sd_session_get_tty(*s, &tty);
if (q < 0) {
if (q != -ENXIO && q != -ENODATA)
r = q;
continue;
}
path = strjoin("/dev/", tty);
if (!path)
return -ENOMEM;
(void) sd_session_get_remote_host(*s, &rhost);
bool is_local = !rhost;
if (!match_tty || match_tty(path, is_local, userdata)) {
q = write_to_terminal(path, message);
if (q < 0)
r = q;
}
}
return r;
}
#endif
int wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata) {
_cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
hn = gethostname_malloc();
if (!hn)
return -ENOMEM;
if (!username) {
un = getlogname_malloc();
if (!un)
return -ENOMEM;
}
if (!origin_tty) {
(void) getttyname_harder(STDIN_FILENO, &stdin_tty);
origin_tty = stdin_tty;
}
if (asprintf(&text,
"\r\n"
"Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
"%s\r\n\r\n",
un ?: username, hn,
origin_tty ? " on " : "", strempty(origin_tty),
FORMAT_TIMESTAMP(now(CLOCK_REALTIME)),
message) < 0)
return -ENOMEM;
return do_wall(text, username, origin_tty, match_tty, userdata);
}

11
src/shared/wall.h Normal file
View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
int wall(
const char *message,
const char *username,
const char *origin_tty,
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
void *userdata);

View File

@ -41,7 +41,7 @@
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "utmp-wtmp.h"
#include "wall.h"
static enum {
ACTION_LIST,
@ -216,16 +216,16 @@ static int process_one_password_file(const char *filename) {
return 0;
case ACTION_WALL: {
_cleanup_free_ char *wall = NULL;
_cleanup_free_ char *msg = NULL;
if (asprintf(&wall,
if (asprintf(&msg,
"Password entry required for \'%s\' (PID " PID_FMT ").\r\n"
"Please enter password with the systemd-tty-ask-password-agent tool.",
strna(message),
pid) < 0)
return log_oom();
(void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
(void) wall(msg, NULL, NULL, wall_tty_match, NULL);
return 0;
}
case ACTION_QUERY: