diff --git a/meson.build b/meson.build index 675b8fa94c7..66d90e15ae8 100644 --- a/meson.build +++ b/meson.build @@ -2386,6 +2386,7 @@ exe = executable( write_sources, include_directories : includes, link_with : [lib_common], + dependencies : [lib_systemd], install_dir : usrbin_exec_dir, install : opt, build_by_default : opt) diff --git a/term-utils/Makemodule.am b/term-utils/Makemodule.am index b7037fb116d..1efe1c57e37 100644 --- a/term-utils/Makemodule.am +++ b/term-utils/Makemodule.am @@ -126,6 +126,10 @@ write_SOURCES = term-utils/write.c write_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS) write_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS) write_LDADD = $(LDADD) libcommon.la +if HAVE_SYSTEMD +write_LDADD += $(SYSTEMD_LIBS) +write_CFLAGS += $(SYSTEMD_CFLAGS) +endif if USE_TTY_GROUP if MAKEINSTALL_DO_CHOWN diff --git a/term-utils/write.c b/term-utils/write.c index 8b86e9a9d5a..b4030d15a4c 100644 --- a/term-utils/write.c +++ b/term-utils/write.c @@ -57,7 +57,12 @@ #include #include #include -#include + +#if defined(HAVE_LIBSYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1 +# include +#else +# include +#endif #include "c.h" #include "carefulputc.h" @@ -129,8 +134,41 @@ static int check_tty(const char *tty, int *tty_writeable, time_t *tty_atime, int */ static int check_utmp(const struct write_control *ctl) { - struct utmpx *u; int res = 1; +#if defined(HAVE_LIBSYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1 + char **sessions_list; + int sessions = sd_get_sessions(&sessions_list); + if (sessions < 0) + errx(EXIT_FAILURE, _("error getting sessions: %s"), + strerror(-sessions)); + + for (int i = 0; i < sessions; i++) { + char *name, *tty; + int r; + + if ((r = sd_session_get_username(sessions_list[i], &name)) < 0) + errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r)); + if (sd_session_get_tty(sessions_list[i], &tty) < 0) { + free(name); + continue; + } + + if (strcmp(ctl->dst_login, name) == 0 && + strcmp(ctl->dst_tty_name, tty) == 0) { + free(name); + free(tty); + res = 0; + break; + } + free(name); + free(tty); + } + for (int i = 0; i < sessions; i++) + free(sessions_list[i]); + free(sessions_list); + +#else + struct utmpx *u; utmpxname(_PATH_UTMP); setutxent(); @@ -144,6 +182,7 @@ static int check_utmp(const struct write_control *ctl) } endutxent(); +#endif return res; } @@ -160,9 +199,70 @@ static int check_utmp(const struct write_control *ctl) */ static void search_utmp(struct write_control *ctl) { - struct utmpx *u; time_t best_atime = 0, tty_atime; int num_ttys = 0, valid_ttys = 0, tty_writeable = 0, user_is_me = 0; + +#if defined(HAVE_LIBSYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1 + char path[256]; + char **sessions_list; + int sessions = sd_get_sessions(&sessions_list); + if (sessions < 0) + errx(EXIT_FAILURE, _("error getting sessions: %s"), + strerror(-sessions)); + + for (int i = 0; i < sessions; i++) { + char *name, *tty; + int r; + + if ((r = sd_session_get_username(sessions_list[i], &name)) < 0) + errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r)); + + if (strcmp(ctl->dst_login, name) != 0) { + free(name); + continue; + } + + if (sd_session_get_tty(sessions_list[i], &tty) < 0) { + free(name); + continue; + } + + num_ttys++; + snprintf(path, sizeof(path), "/dev/%s", tty); + if (check_tty(path, &tty_writeable, &tty_atime, 0)) { + /* bad term? skip */ + free(name); + free(tty); + continue; + } + if (ctl->src_uid && !tty_writeable) { + /* skip ttys with msgs off */ + free(name); + free(tty); + continue; + } + if (strcmp(tty, ctl->src_tty_name) == 0) { + user_is_me = 1; + free(name); + free(tty); + /* don't write to yourself */ + continue; + } + valid_ttys++; + if (best_atime < tty_atime) { + best_atime = tty_atime; + free(ctl->dst_tty_path); + ctl->dst_tty_path = xstrdup(path); + ctl->dst_tty_name = ctl->dst_tty_path + 5; + } + free(name); + free(tty); + } + for (int i = 0; i < sessions; i++) + free(sessions_list[i]); + free(sessions_list); +#else + struct utmpx *u; char path[sizeof(u->ut_line) + 6]; utmpxname(_PATH_UTMP); @@ -197,6 +297,7 @@ static void search_utmp(struct write_control *ctl) } endutxent(); +#endif if (num_ttys == 0) errx(EXIT_FAILURE, _("%s is not logged in"), ctl->dst_login); if (valid_ttys == 0) {