summaryrefslogtreecommitdiffstats
path: root/term-utils
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--term-utils/Makemodule.am12
-rw-r--r--term-utils/agetty.816
-rw-r--r--term-utils/agetty.8.adoc8
-rw-r--r--term-utils/agetty.c149
-rw-r--r--term-utils/mesg.16
-rw-r--r--term-utils/mesg.c4
-rw-r--r--term-utils/script-playutils.c2
-rw-r--r--term-utils/script.16
-rw-r--r--term-utils/script.c8
-rw-r--r--term-utils/scriptlive.16
-rw-r--r--term-utils/scriptlive.c4
-rw-r--r--term-utils/scriptreplay.16
-rw-r--r--term-utils/scriptreplay.c5
-rw-r--r--term-utils/setterm.19
-rw-r--r--term-utils/setterm.1.adoc4
-rw-r--r--term-utils/setterm.c6
-rw-r--r--term-utils/wall.16
-rw-r--r--term-utils/wall.c84
-rw-r--r--term-utils/write.17
-rw-r--r--term-utils/write.1.adoc2
-rw-r--r--term-utils/write.c194
21 files changed, 370 insertions, 174 deletions
diff --git a/term-utils/Makemodule.am b/term-utils/Makemodule.am
index 07004d4..1efe1c5 100644
--- a/term-utils/Makemodule.am
+++ b/term-utils/Makemodule.am
@@ -58,6 +58,10 @@ endif
if HAVE_ECONF
agetty_LDADD += -leconf
endif
+if HAVE_SYSTEMD
+agetty_LDADD += $(SYSTEMD_LIBS)
+agetty_CFLAGS = $(SYSTEMD_CFLAGS)
+endif
endif # BUILD_AGETTY
@@ -98,6 +102,10 @@ dist_noinst_DATA += term-utils/wall.1.adoc
wall_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
wall_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS)
wall_LDADD = $(LDADD) libcommon.la
+if HAVE_SYSTEMD
+wall_LDADD += $(SYSTEMD_LIBS)
+wall_CFLAGS += $(SYSTEMD_CFLAGS)
+endif
if USE_TTY_GROUP
if MAKEINSTALL_DO_CHOWN
install-exec-hook-wall::
@@ -118,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/agetty.8 b/term-utils/agetty.8
index 5b9a121..5b855fe 100644
--- a/term-utils/agetty.8
+++ b/term-utils/agetty.8
@@ -2,12 +2,12 @@
.\" Title: agetty
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-12-01
+.\" Date: 2024-03-20
.\" Manual: System Administration
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "AGETTY" "8" "2023-12-01" "util\-linux 2.39.3" "System Administration"
+.TH "AGETTY" "8" "2024-03-20" "util\-linux 2.40" "System Administration"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -574,6 +574,16 @@ problem reports (if \fBsyslog\fP(3) is not used).
.RS 4
\fBinit\fP(8) configuration file for SysV\-style init daemon.
.RE
+.SH "CREDENTIALS"
+.sp
+\fBagetty\fP supports configuration via systemd credentials (see \c
+.URL "https://systemd.io/CREDENTIALS/" "" ")."
+\fBagetty\fP reads the following systemd credentials:
+.sp
+\fBagetty.autologin\fP (string)
+.RS 4
+If set, configures \fBagetty\fP to automatically log in the specified user without asking for a username or password, similarly to the \fB\-\-autologin\fP option.
+.RE
.SH "BUGS"
.sp
The baud\-rate detection feature (the \fB\-\-extract\-baud\fP option) requires that \fBagetty\fP be scheduled soon enough after completion of a dial\-in call (within 30 ms with modems that talk at 2400 baud). For robustness, always use the \fB\-\-extract\-baud\fP option in combination with a multiple baud rate command\-line argument, so that BREAK processing is enabled.
diff --git a/term-utils/agetty.8.adoc b/term-utils/agetty.8.adoc
index c51e562..f127630 100644
--- a/term-utils/agetty.8.adoc
+++ b/term-utils/agetty.8.adoc
@@ -319,6 +319,14 @@ problem reports (if *syslog*(3) is not used).
_/etc/inittab_::
*init*(8) configuration file for SysV-style init daemon.
+== CREDENTIALS
+
+*agetty* supports configuration via systemd credentials (see https://systemd.io/CREDENTIALS/). *agetty* reads the following systemd credentials:
+
+*agetty.autologin* (string)::
+
+If set, configures *agetty* to automatically log in the specified user without asking for a username or password, similarly to the *--autologin* option.
+
== BUGS
The baud-rate detection feature (the *--extract-baud* option) requires that *agetty* be scheduled soon enough after completion of a dial-in call (within 30 ms with modems that talk at 2400 baud). For robustness, always use the *--extract-baud* option in combination with a multiple baud rate command-line argument, so that BREAK processing is enabled.
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index cf87255..0fc6f15 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -48,6 +48,8 @@
#include "ttyutils.h"
#include "color-names.h"
#include "env.h"
+#include "path.h"
+#include "fileutils.h"
#include "logindefs.h"
@@ -73,35 +75,16 @@
# endif
#endif
+#ifdef USE_SYSTEMD
+# include <systemd/sd-daemon.h>
+# include <systemd/sd-login.h>
+#endif
+
#ifdef __linux__
# include <sys/kd.h>
# define USE_SYSLOG
-# ifndef DEFAULT_VCTERM
-# define DEFAULT_VCTERM "linux"
-# endif
-# if defined (__s390__) || defined (__s390x__)
-# define DEFAULT_TTYS0 "dumb"
-# define DEFAULT_TTY32 "ibm327x"
-# define DEFAULT_TTYS1 "vt220"
-# endif
-# ifndef DEFAULT_STERM
-# define DEFAULT_STERM "vt102"
-# endif
#elif defined(__GNU__)
# define USE_SYSLOG
-# ifndef DEFAULT_VCTERM
-# define DEFAULT_VCTERM "hurd"
-# endif
-# ifndef DEFAULT_STERM
-# define DEFAULT_STERM "vt102"
-# endif
-#else
-# ifndef DEFAULT_VCTERM
-# define DEFAULT_VCTERM "vt100"
-# endif
-# ifndef DEFAULT_STERM
-# define DEFAULT_STERM "vt100"
-# endif
#endif
#ifdef __FreeBSD_kernel__
@@ -139,7 +122,6 @@
# define ISSUE_SUPPORT
# if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT)
# include <dirent.h>
-# include "fileutils.h"
# define ISSUEDIR_SUPPORT
# define ISSUEDIR_EXT ".issue"
# define ISSUEDIR_EXTSIZ (sizeof(ISSUEDIR_EXT) - 1)
@@ -353,6 +335,7 @@ static void reload_agettys(void);
static void print_issue_file(struct issue *ie, struct options *op, struct termios *tp);
static void eval_issue_file(struct issue *ie, struct options *op, struct termios *tp);
static void show_issue(struct options *op);
+static void load_credentials(struct options *op);
/* Fake hostname for ut_host specified on command line. */
@@ -413,6 +396,9 @@ int main(int argc, char **argv)
}
#endif /* DEBUGGING */
+ /* Load systemd credentials. */
+ load_credentials(&options);
+
/* Parse command-line arguments. */
parse_args(argc, argv, &options);
@@ -575,7 +561,6 @@ int main(int argc, char **argv)
log_warn(_("%s: can't change process priority: %m"),
options.tty);
- free(options.osrelease);
#ifdef DEBUGGING
if (close_stream(dbf) != 0)
log_err("write failed: %s", DEBUG_OUTPUT);
@@ -583,6 +568,10 @@ int main(int argc, char **argv)
/* Let the login program take care of password validation. */
execv(options.login, login_argv);
+
+ free(options.osrelease);
+ free(options.autolog);
+
log_err(_("%s: can't exec %s: %m"), options.tty, login_argv[0]);
}
@@ -779,7 +768,10 @@ static void parse_args(int argc, char **argv, struct options *op)
op->flags |= F_EIGHTBITS;
break;
case 'a':
- op->autolog = optarg;
+ free(op->autolog);
+ op->autolog = strdup(optarg);
+ if (!op->autolog)
+ log_err(_("failed to allocate memory: %m"));
break;
case 'c':
op->flags |= F_KEEPCFLAGS;
@@ -1182,35 +1174,6 @@ static void open_tty(const char *tty, struct termios *tp, struct options *op)
if (tcgetattr(STDIN_FILENO, tp) < 0)
log_err(_("%s: failed to get terminal attributes: %m"), tty);
-#ifdef HAVE_GETTTYNAM
- if (!op->term) {
- struct ttyent *ent = getttynam(tty);
- /* a bit nasty as it's never freed */
- if (ent && ent->ty_type) {
- op->term = strdup(ent->ty_type);
- if (!op->term)
- log_err(_("failed to allocate memory: %m"));
- }
- }
-#endif
-
-#if defined (__s390__) || defined (__s390x__)
- if (!op->term) {
- /*
- * Special terminal on first serial line on a S/390(x) which
- * is due legacy reasons a block terminal of type 3270 or
- * higher. Whereas the second serial line on a S/390(x) is
- * a real character terminal which is compatible with VT220.
- */
- if (strcmp(op->tty, "ttyS0") == 0) /* linux/drivers/s390/char/con3215.c */
- op->term = DEFAULT_TTYS0;
- else if (strncmp(op->tty, "3270/tty", 8) == 0) /* linux/drivers/s390/char/con3270.c */
- op->term = DEFAULT_TTY32;
- else if (strcmp(op->tty, "ttyS1") == 0) /* linux/drivers/s390/char/sclp_vt220.c */
- op->term = DEFAULT_TTYS1;
- }
-#endif
-
#if defined(__FreeBSD_kernel__)
login_tty (0);
#endif
@@ -1227,16 +1190,16 @@ static void open_tty(const char *tty, struct termios *tp, struct options *op)
#endif
{
op->flags |= F_VCONSOLE;
- if (!op->term)
- op->term = DEFAULT_VCTERM;
} else {
#ifdef K_RAW
op->kbmode = K_RAW;
#endif
- if (!op->term)
- op->term = DEFAULT_STERM;
}
+ op->term = get_terminal_default_type(op->tty, !(op->flags & F_VCONSOLE));
+ if (!op->term)
+ log_err(_("failed to allocate memory: %m"));
+
if (setenv("TERM", op->term, 1) != 0)
log_err(_("failed to set the %s environment variable"), "TERM");
}
@@ -2021,7 +1984,7 @@ static void eval_issue_file(struct issue *ie,
/* Fallback @sysconfstaticdir (usually /usr/lib) -- the file is not
* required to read the dir
*/
- issuefile_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_FILENAME, op, tp);
+ issuefile_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_FILENAME, op, tp);
issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp);
done:
@@ -2524,9 +2487,9 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" --nice <number> run login with this priority\n"), out);
fputs(_(" --reload reload prompts on running agetty instances\n"), out);
fputs(_(" --list-speeds display supported baud rates\n"), out);
- printf( " --help %s\n", USAGE_OPTSTR_HELP);
- printf( " --version %s\n", USAGE_OPTSTR_VERSION);
- printf(USAGE_MAN_TAIL("agetty(8)"));
+ fprintf(out, " --help %s\n", USAGE_OPTSTR_HELP);
+ fprintf(out, " --version %s\n", USAGE_OPTSTR_VERSION);
+ fprintf(out, USAGE_MAN_TAIL("agetty(8)"));
exit(EXIT_SUCCESS);
}
@@ -2556,7 +2519,7 @@ static void dolog(int priority
* automatically prepended to the message. If we write directly to
* /dev/console, we must prepend the process name ourselves.
*/
- openlog(program_invocation_short_name, LOG_PID, LOG_AUTHPRIV);
+ openlog("agetty", LOG_PID, LOG_AUTHPRIV);
vsyslog(priority, fmt, ap);
closelog();
#else
@@ -2864,12 +2827,23 @@ static void output_special_char(struct issue *ie,
case 'U':
{
int users = 0;
- struct utmpx *ut;
- setutxent();
- while ((ut = getutxent()))
- if (ut->ut_type == USER_PROCESS)
- users++;
- endutxent();
+#ifdef USE_SYSTEMD
+ if (sd_booted() > 0) {
+ users = sd_get_sessions(NULL);
+ if (users < 0)
+ users = 0;
+ } else {
+#endif
+ users = 0;
+ struct utmpx *ut;
+ setutxent();
+ while ((ut = getutxent()))
+ if (ut->ut_type == USER_PROCESS)
+ users++;
+ endutxent();
+#ifdef USE_SYSTEMD
+ }
+#endif
if (c == 'U')
fprintf(ie->output, P_("%d user", "%d users", users), users);
else
@@ -3020,3 +2994,36 @@ static void reload_agettys(void)
errx(EXIT_FAILURE, _("--reload is unsupported on your system"));
#endif
}
+
+static void load_credentials(struct options *op) {
+ char *env;
+ DIR *dir;
+ struct dirent *d;
+ struct path_cxt *pc;
+
+ env = safe_getenv("CREDENTIALS_DIRECTORY");
+ if (!env)
+ return;
+
+ pc = ul_new_path("%s", env);
+ if (!pc) {
+ log_warn(_("failed to initialize path context"));
+ return;
+ }
+
+ dir = ul_path_opendir(pc, NULL);
+ if (!dir) {
+ log_warn(_("failed to open credentials directory"));
+ return;
+ }
+
+ while ((d = xreaddir(dir))) {
+ char *str;
+
+ if (strcmp(d->d_name, "agetty.autologin") == 0) {
+ ul_path_read_string(pc, &str, d->d_name);
+ free(op->autolog);
+ op->autolog = str;
+ }
+ }
+}
diff --git a/term-utils/mesg.1 b/term-utils/mesg.1
index cafb57e..332bbba 100644
--- a/term-utils/mesg.1
+++ b/term-utils/mesg.1
@@ -2,12 +2,12 @@
.\" Title: mesg
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-11-21
+.\" Date: 2024-01-31
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "MESG" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands"
+.TH "MESG" "1" "2024-01-31" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
diff --git a/term-utils/mesg.c b/term-utils/mesg.c
index cb0b493..23e2f0d 100644
--- a/term-utils/mesg.c
+++ b/term-utils/mesg.c
@@ -82,8 +82,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(USAGE_OPTIONS, out);
fputs(_(" -v, --verbose explain what is being done\n"), out);
- printf(USAGE_HELP_OPTIONS(16));
- printf(USAGE_MAN_TAIL("mesg(1)"));
+ fprintf(out, USAGE_HELP_OPTIONS(16));
+ fprintf(out, USAGE_MAN_TAIL("mesg(1)"));
exit(EXIT_SUCCESS);
}
diff --git a/term-utils/script-playutils.c b/term-utils/script-playutils.c
index 699865b..1dec1af 100644
--- a/term-utils/script-playutils.c
+++ b/term-utils/script-playutils.c
@@ -165,7 +165,7 @@ static struct replay_log *replay_new_log(struct replay_setup *stp,
assert(streams);
assert(filename);
- stp->logs = xrealloc(stp->logs, (stp->nlogs + 1) * sizeof(*log));
+ stp->logs = xreallocarray(stp->logs, stp->nlogs + 1, sizeof(*log));
log = &stp->logs[stp->nlogs];
stp->nlogs++;
diff --git a/term-utils/script.1 b/term-utils/script.1
index fb6f4b5..5e5c337 100644
--- a/term-utils/script.1
+++ b/term-utils/script.1
@@ -2,12 +2,12 @@
.\" Title: script
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-11-21
+.\" Date: 2024-01-31
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "SCRIPT" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands"
+.TH "SCRIPT" "1" "2024-01-31" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
diff --git a/term-utils/script.c b/term-utils/script.c
index 7752c29..3457ac8 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -216,8 +216,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -q, --quiet be quiet\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(31));
- printf(USAGE_MAN_TAIL("script(1)"));
+ fprintf(out, USAGE_HELP_OPTIONS(31));
+ fprintf(out, USAGE_MAN_TAIL("script(1)"));
exit(EXIT_SUCCESS);
}
@@ -260,8 +260,8 @@ static struct script_log *log_associate(struct script_control *ctl,
}
/* add log to the stream */
- stream->logs = xrealloc(stream->logs,
- (stream->nlogs + 1) * sizeof(log));
+ stream->logs = xreallocarray(stream->logs,
+ stream->nlogs + 1, sizeof(log));
stream->logs[stream->nlogs] = log;
stream->nlogs++;
diff --git a/term-utils/scriptlive.1 b/term-utils/scriptlive.1
index f94a034..ef3990c 100644
--- a/term-utils/scriptlive.1
+++ b/term-utils/scriptlive.1
@@ -2,12 +2,12 @@
.\" Title: scriptlive
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-10-23
+.\" Date: 2024-01-31
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "SCRIPTLIVE" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands"
+.TH "SCRIPTLIVE" "1" "2024-01-31" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
diff --git a/term-utils/scriptlive.c b/term-utils/scriptlive.c
index f8434ad..40d68dd 100644
--- a/term-utils/scriptlive.c
+++ b/term-utils/scriptlive.c
@@ -73,9 +73,9 @@ usage(void)
fputs(_(" -c, --command <command> run command rather than interactive shell\n"), out);
fputs(_(" -d, --divisor <num> speed up or slow down execution with time divisor\n"), out);
fputs(_(" -m, --maxdelay <num> wait at most this many seconds between updates\n"), out);
- printf(USAGE_HELP_OPTIONS(25));
+ fprintf(out, USAGE_HELP_OPTIONS(25));
- printf(USAGE_MAN_TAIL("scriptlive(1)"));
+ fprintf(out, USAGE_MAN_TAIL("scriptlive(1)"));
exit(EXIT_SUCCESS);
}
diff --git a/term-utils/scriptreplay.1 b/term-utils/scriptreplay.1
index f03eded..0e538a1 100644
--- a/term-utils/scriptreplay.1
+++ b/term-utils/scriptreplay.1
@@ -2,12 +2,12 @@
.\" Title: scriptreplay
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-10-23
+.\" Date: 2024-01-31
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "SCRIPTREPLAY" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands"
+.TH "SCRIPTREPLAY" "1" "2024-01-31" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
diff --git a/term-utils/scriptreplay.c b/term-utils/scriptreplay.c
index fb68499..98501a8 100644
--- a/term-utils/scriptreplay.c
+++ b/term-utils/scriptreplay.c
@@ -68,9 +68,9 @@ usage(void)
fputs(_(" -m, --maxdelay <num> wait at most this many seconds between updates\n"), out);
fputs(_(" -x, --stream <name> stream type (out, in, signal or info)\n"), out);
fputs(_(" -c, --cr-mode <type> CR char mode (auto, never, always)\n"), out);
- printf(USAGE_HELP_OPTIONS(25));
+ fprintf(out, USAGE_HELP_OPTIONS(25));
- printf(USAGE_MAN_TAIL("scriptreplay(1)"));
+ fprintf(out, USAGE_MAN_TAIL("scriptreplay(1)"));
exit(EXIT_SUCCESS);
}
@@ -134,6 +134,7 @@ setterm(struct termios *backup)
tattr = *backup;
cfmakeraw(&tattr);
tattr.c_lflag |= ISIG;
+ tattr.c_iflag |= IXON;
tcsetattr(STDOUT_FILENO, TCSANOW, &tattr);
return 1;
}
diff --git a/term-utils/setterm.1 b/term-utils/setterm.1
index 955593e..30d0cc7 100644
--- a/term-utils/setterm.1
+++ b/term-utils/setterm.1
@@ -2,12 +2,12 @@
.\" Title: setterm
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-11-21
+.\" Date: 2024-03-20
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "SETTERM" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands"
+.TH "SETTERM" "1" "2024-03-20" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -252,6 +252,9 @@ Display help text and exit.
.RS 4
Print version and exit.
.RE
+.SH "WARNING"
+.sp
+Use of \fBsetterm\fP in combination with stdout redirection can have unexpected results, as some options operate on stdin. To prevent problems, always redirect both stdin and stdout to the same device.
.SH "COMPATIBILITY"
.sp
Since version 2.25 \fBsetterm\fP has support for long options with two hyphens, for example \fB\-\-help\fP, beside the historical long options with a single hyphen, for example \fB\-help\fP. In scripts it is better to use the backward\-compatible single hyphen rather than the double hyphen. Currently there are no plans nor good reasons to discontinue single\-hyphen compatibility.
diff --git a/term-utils/setterm.1.adoc b/term-utils/setterm.1.adoc
index 880fe10..365c4bb 100644
--- a/term-utils/setterm.1.adoc
+++ b/term-utils/setterm.1.adoc
@@ -156,6 +156,10 @@ Turns underline mode on or off.
include::man-common/help-version.adoc[]
+== WARNING
+
+Use of *setterm* in combination with stdout redirection can have unexpected results, as some options operate on stdin. To prevent problems, always redirect both stdin and stdout to the same device.
+
== COMPATIBILITY
Since version 2.25 *setterm* has support for long options with two hyphens, for example *--help*, beside the historical long options with a single hyphen, for example *-help*. In scripts it is better to use the backward-compatible single hyphen rather than the double hyphen. Currently there are no plans nor good reasons to discontinue single-hyphen compatibility.
diff --git a/term-utils/setterm.c b/term-utils/setterm.c
index e91abc9..8ec10ee 100644
--- a/term-utils/setterm.c
+++ b/term-utils/setterm.c
@@ -438,10 +438,10 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" --bfreq[=<number>] bell frequency in Hertz\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf( " --help %s\n", USAGE_OPTSTR_HELP);
- printf( " --version %s\n", USAGE_OPTSTR_VERSION);
+ fprintf(out, " --help %s\n", USAGE_OPTSTR_HELP);
+ fprintf(out, " --version %s\n", USAGE_OPTSTR_VERSION);
- printf(USAGE_MAN_TAIL("setterm(1)"));
+ fprintf(out, USAGE_MAN_TAIL("setterm(1)"));
exit(EXIT_SUCCESS);
}
diff --git a/term-utils/wall.1 b/term-utils/wall.1
index 9bc21ca..eee0c2b 100644
--- a/term-utils/wall.1
+++ b/term-utils/wall.1
@@ -2,12 +2,12 @@
.\" Title: wall
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-10-23
+.\" Date: 2024-01-31
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "WALL" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands"
+.TH "WALL" "1" "2024-01-31" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
diff --git a/term-utils/wall.c b/term-utils/wall.c
index 377db45..588d3a9 100644
--- a/term-utils/wall.c
+++ b/term-utils/wall.c
@@ -61,6 +61,11 @@
#include <sys/types.h>
#include <grp.h>
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+# include <systemd/sd-login.h>
+# include <systemd/sd-daemon.h>
+#endif
+
#include "nls.h"
#include "xalloc.h"
#include "strutils.h"
@@ -96,8 +101,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -n, --nobanner do not print banner, works only for root\n"), out);
fputs(_(" -t, --timeout <timeout> write timeout in seconds\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(25));
- printf(USAGE_MAN_TAIL("wall(1)"));
+ fprintf(out, USAGE_HELP_OPTIONS(25));
+ fprintf(out, USAGE_MAN_TAIL("wall(1)"));
exit(EXIT_SUCCESS);
}
@@ -135,7 +140,7 @@ static struct group_workspace *init_group_workspace(const char *group)
buf->requested_group = get_group_gid(group);
buf->ngroups = sysconf(_SC_NGROUPS_MAX) + 1; /* room for the primary gid */
- buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups);
+ buf->groups = xcalloc(buf->ngroups, sizeof(*buf->groups));
return buf;
}
@@ -246,29 +251,64 @@ int main(int argc, char **argv)
iov.iov_base = mbuf;
iov.iov_len = mbufsize;
- while((utmpptr = getutxent())) {
- if (!utmpptr->ut_user[0])
- continue;
+
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+ if (sd_booted() > 0) {
+ char **sessions_list;
+ int sessions;
+
+ 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 (!(group_buf && !is_gr_member(name, group_buf))) {
+ if (sd_session_get_tty(sessions_list[i], &tty) >= 0) {
+ if ((p = ttymsg(&iov, 1, tty, timeout)) != NULL)
+ warnx("%s", p);
+
+ free(tty);
+ }
+ }
+ free(name);
+ free(sessions_list[i]);
+ }
+ free(sessions_list);
+ } else
+#endif
+ {
+ while ((utmpptr = getutxent())) {
+ if (!utmpptr->ut_user[0])
+ continue;
#ifdef USER_PROCESS
- if (utmpptr->ut_type != USER_PROCESS)
- continue;
+ if (utmpptr->ut_type != USER_PROCESS)
+ continue;
#endif
- /* Joey Hess reports that use-sessreg in /etc/X11/wdm/ produces
- * ut_line entries like :0, and a write to /dev/:0 fails.
- *
- * It also seems that some login manager may produce empty ut_line.
- */
- if (!*utmpptr->ut_line || *utmpptr->ut_line == ':')
- continue;
+ /* Joey Hess reports that use-sessreg in /etc/X11/wdm/ produces
+ * ut_line entries like :0, and a write to /dev/:0 fails.
+ *
+ * It also seems that some login manager may produce empty ut_line.
+ */
+ if (!*utmpptr->ut_line || *utmpptr->ut_line == ':')
+ continue;
- if (group_buf && !is_gr_member(utmpptr->ut_user, group_buf))
- continue;
+ if (group_buf && !is_gr_member(utmpptr->ut_user, group_buf))
+ continue;
- mem2strcpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line), sizeof(line));
- if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
- warnx("%s", p);
+ mem2strcpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line), sizeof(line));
+ if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
+ warnx("%s", p);
+ }
+ endutxent();
}
- endutxent();
+
free(mbuf);
free_group_workspace(group_buf);
exit(EXIT_SUCCESS);
@@ -328,7 +368,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
int i;
for (i = 0; i < mvecsz; i++) {
- fputs(mvec[i], fs);
+ fputs_careful(mvec[i], fs, '^', true, TERM_WIDTH);
if (i < mvecsz - 1)
fputc(' ', fs);
}
diff --git a/term-utils/write.1 b/term-utils/write.1
index 53bb475..5e91495 100644
--- a/term-utils/write.1
+++ b/term-utils/write.1
@@ -2,12 +2,12 @@
.\" Title: write
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-11-21
+.\" Date: 2024-03-20
.\" Manual: User Commands
-.\" Source: util-linux 2.39.3
+.\" Source: util-linux 2.40
.\" Language: English
.\"
-.TH "WRITE" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands"
+.TH "WRITE" "1" "2024-03-20" "util\-linux 2.40" "User Commands"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -29,6 +29,7 @@
.\}
.SH "NAME"
write \- send a message to another user
+.SH "SYNOPSIS"
.sp
\fBwrite\fP \fIuser\fP [\fIttyname\fP]
.SH "DESCRIPTION"
diff --git a/term-utils/write.1.adoc b/term-utils/write.1.adoc
index f6a01de..22b537f 100644
--- a/term-utils/write.1.adoc
+++ b/term-utils/write.1.adoc
@@ -47,6 +47,8 @@ SUCH DAMAGE.
write - send a message to another user
+== SYNOPSIS
+
*write* _user_ [_ttyname_]
== DESCRIPTION
diff --git a/term-utils/write.c b/term-utils/write.c
index a5a2128..3784f03 100644
--- a/term-utils/write.c
+++ b/term-utils/write.c
@@ -59,6 +59,11 @@
#include <unistd.h>
#include <utmpx.h>
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+# include <systemd/sd-login.h>
+# include <systemd/sd-daemon.h>
+#endif
+
#include "c.h"
#include "carefulputc.h"
#include "closestream.h"
@@ -91,8 +96,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_("Send a message to another user.\n"), out);
fputs(USAGE_OPTIONS, out);
- printf(USAGE_HELP_OPTIONS(16));
- printf(USAGE_MAN_TAIL("write(1)"));
+ fprintf(out, USAGE_HELP_OPTIONS(16));
+ fprintf(out, USAGE_MAN_TAIL("write(1)"));
exit(EXIT_SUCCESS);
}
@@ -131,19 +136,56 @@ static int check_utmp(const struct write_control *ctl)
{
struct utmpx *u;
int res = 1;
-
- utmpxname(_PATH_UTMP);
- setutxent();
-
- while ((u = getutxent())) {
- if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) == 0 &&
- strncmp(ctl->dst_tty_name, u->ut_line, sizeof(u->ut_line)) == 0) {
- res = 0;
- break;
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+ if (sd_booted() > 0) {
+ 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 {
+#endif
+ utmpxname(_PATH_UTMP);
+ setutxent();
+
+ while ((u = getutxent())) {
+ if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) == 0 &&
+ strncmp(ctl->dst_tty_name, u->ut_line, sizeof(u->ut_line)) == 0) {
+ res = 0;
+ break;
+ }
}
- }
- endutxent();
+ endutxent();
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+ }
+#endif
return res;
}
@@ -163,40 +205,106 @@ 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;
- char path[sizeof(u->ut_line) + 6];
-
- utmpxname(_PATH_UTMP);
- setutxent();
-
- while ((u = getutxent())) {
- if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) != 0)
- continue;
- num_ttys++;
- snprintf(path, sizeof(path), "/dev/%s", u->ut_line);
- if (check_tty(path, &tty_writeable, &tty_atime, 0))
- /* bad term? skip */
- continue;
- if (ctl->src_uid && !tty_writeable)
- /* skip ttys with msgs off */
- continue;
- if (memcmp(u->ut_line, ctl->src_tty_name, strlen(ctl->src_tty_name) + 1) == 0) {
- user_is_me = 1;
- /* don't write to yourself */
- continue;
+
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+ if (sd_booted() > 0) {
+ 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);
}
- if (u->ut_type != USER_PROCESS)
- /* it's not a valid entry */
- 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;
+ for (int i = 0; i < sessions; i++)
+ free(sessions_list[i]);
+ free(sessions_list);
+ } else
+#endif
+ {
+ char path[sizeof(u->ut_line) + 6];
+
+ utmpxname(_PATH_UTMP);
+ setutxent();
+
+ while ((u = getutxent())) {
+ if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) != 0)
+ continue;
+ num_ttys++;
+ snprintf(path, sizeof(path), "/dev/%s", u->ut_line);
+ if (check_tty(path, &tty_writeable, &tty_atime, 0))
+ /* bad term? skip */
+ continue;
+ if (ctl->src_uid && !tty_writeable)
+ /* skip ttys with msgs off */
+ continue;
+ if (memcmp(u->ut_line, ctl->src_tty_name, strlen(ctl->src_tty_name) + 1) == 0) {
+ user_is_me = 1;
+ /* don't write to yourself */
+ continue;
+ }
+ if (u->ut_type != USER_PROCESS)
+ /* it's not a valid entry */
+ 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;
+ }
}
+
+ endutxent();
}
- endutxent();
if (num_ttys == 0)
errx(EXIT_FAILURE, _("%s is not logged in"), ctl->dst_login);
if (valid_ttys == 0) {