From: Thorsten Kukuk Date: Mon, 4 Sep 2023 08:08:13 +0000 (+0200) Subject: shared/wall: use logind if build without utmp support X-Git-Tag: v255-rc1~564 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=53c0397b1dbc95f144d9a551c2086d132933e8ce;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 21ec5a785bf..c8d92c4d3e3 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -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"); } diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 2d1af602c0b..dcbd195fe2d 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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); diff --git a/src/login/logind-utmp.c b/src/login/logind-wall.c similarity index 97% rename from src/login/logind-utmp.c rename to src/login/logind-wall.c index 4db127a4c52..aa735223340 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-wall.c @@ -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; } diff --git a/src/login/meson.build b/src/login/meson.build index 9804a36ce12..276e920dfc3 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -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] diff --git a/src/shared/meson.build b/src/shared/meson.build index 01e85b617f1..67f4f4517d2 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -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', diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index c79764ced02..c90e07d4d15 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -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; -} diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h index 97be719abf8..ec1e27771e9 100644 --- a/src/shared/utmp-wtmp.h +++ b/src/shared/utmp-wtmp.h @@ -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 */ diff --git a/src/shared/wall.c b/src/shared/wall.c new file mode 100644 index 00000000000..e99fd9029c6 --- /dev/null +++ b/src/shared/wall.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include + +#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); +} diff --git a/src/shared/wall.h b/src/shared/wall.h new file mode 100644 index 00000000000..4423c394044 --- /dev/null +++ b/src/shared/wall.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +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); diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 46d2307ad31..87c610bc73b 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -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: