wall: allow to specify <message> on command line

wall(1) from sysvinit supports

   # wall I love this company!

semantic, This patch add this functionally to the util-linux wall.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2013-08-13 11:45:54 +02:00
parent e781a04fec
commit cdd3cc7fa4
2 changed files with 69 additions and 37 deletions

View File

@ -33,15 +33,17 @@
.\"
.\" Modified for Linux, Mon Mar 8 18:07:38 1993, faith@cs.unc.edu
.\"
.TH WALL "1" "September 2011" "util-linux" "User Commands"
.TH WALL "1" "August 2013" "util-linux" "User Commands"
.SH NAME
wall \- write a message to users
.SH SYNOPSIS
.B wall
[-n] [-t TIMEOUT] [file]
[-n] [-t TIMEOUT] [file | message]
.SH DESCRIPTION
.B Wall
displays the contents of
displays a
.I message
or contents of
.I file
or, by default, its standard input, on the terminals of all currently logged
in users. The command will cut over 79 character long lines to new lines.
@ -51,8 +53,9 @@ always put carriage return and new line at the end of each line.
Only the superuser can write on the terminals of users who have chosen to
deny messages or are using a program which automatically denies messages.
.PP
Reading from a file is refused when the invoker is not superuser and the
program is suid or sgid.
Reading from a
.I file
is refused when the invoker is not superuser and the program is suid or sgid.
.SH OPTIONS
.TP
\fB\-n\fR, \fB\-\-nobanner\fR

View File

@ -73,14 +73,15 @@
#define WRITE_TIME_OUT 300 /* in seconds */
/* Function prototypes */
char *makemsg(char *fname, size_t *mbufsize, int print_banner);
static void usage(FILE *out);
static char *makemsg(char *fname, char **mvec, int mvecsz,
size_t *mbufsize, int print_banner);
static void __attribute__((__noreturn__)) usage(FILE *out)
{
fputs(_("\nUsage:\n"), out);
fprintf(out,
_(" %s [options] [<file>]\n"),program_invocation_short_name);
_(" %s [options] [<file> | <message>]\n"),
program_invocation_short_name);
fputs(_("\nOptions:\n"), out);
fputs(_(" -n, --nobanner do not print banner, works only for root\n"
@ -99,9 +100,11 @@ main(int argc, char **argv) {
char *p;
char line[sizeof(utmpptr->ut_line) + 1];
int print_banner = TRUE;
char *mbuf;
char *mbuf, *fname = NULL;
size_t mbufsize;
unsigned timeout = WRITE_TIME_OUT;
char **mvec = NULL;
int mvecsz = 0;
static const struct option longopts[] = {
{ "nobanner", no_argument, 0, 'n' },
@ -141,10 +144,15 @@ main(int argc, char **argv) {
}
argc -= optind;
argv += optind;
if (argc > 1)
usage(stderr);
mbuf = makemsg(*argv, &mbufsize, print_banner);
if (argc == 1 && access(argv[0], F_OK) == 0)
fname = argv[0];
else if (argc >= 1) {
mvec = argv;
mvecsz = argc;
}
mbuf = makemsg(fname, mvec, mvecsz, &mbufsize, print_banner);
iov.iov_base = mbuf;
iov.iov_len = mbufsize;
@ -173,8 +181,7 @@ main(int argc, char **argv) {
exit(EXIT_SUCCESS);
}
char *
makemsg(char *fname, size_t *mbufsize, int print_banner)
static char *makemsg(char *fname, char **mvec, int mvecsz, size_t *mbufsize, int print_banner)
{
register int ch, cnt;
struct tm *lt;
@ -229,34 +236,56 @@ makemsg(char *fname, size_t *mbufsize, int print_banner)
}
fprintf(fp, "%79s\r\n", " ");
if (fname) {
if (mvec) {
/*
* When we are not root, but suid or sgid, refuse to read files
* (e.g. device files) that the user may not have access to.
* After all, our invoker can easily do "wall < file"
* instead of "wall file".
* Read message from argv[]
*/
uid_t uid = getuid();
if (uid && (uid != geteuid() || getgid() != getegid()))
errx(EXIT_FAILURE, _("will not read %s - use stdin."),
fname);
int i;
if (!freopen(fname, "r", stdin))
err(EXIT_FAILURE, _("cannot open %s"), fname);
}
for (i = 0; i < mvecsz; i++) {
fputs(mvec[i], fp);
if (i < mvecsz - 1)
fputc(' ', fp);
}
fputc('\r', fp);
fputc('\n', fp);
while (fgets(lbuf, line_max, stdin)) {
for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
if (cnt == 79 || ch == '\n') {
for (; cnt < 79; ++cnt)
putc(' ', fp);
putc('\r', fp);
putc('\n', fp);
cnt = 0;
} else {
/*
* read message from <file>
*/
if (fname) {
/*
* When we are not root, but suid or sgid, refuse to read files
* (e.g. device files) that the user may not have access to.
* After all, our invoker can easily do "wall < file"
* instead of "wall file".
*/
uid_t uid = getuid();
if (uid && (uid != geteuid() || getgid() != getegid()))
errx(EXIT_FAILURE, _("will not read %s - use stdin."),
fname);
if (!freopen(fname, "r", stdin))
err(EXIT_FAILURE, _("cannot open %s"), fname);
}
/*
* Read message from stdin.
*/
while (fgets(lbuf, line_max, stdin)) {
for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
if (cnt == 79 || ch == '\n') {
for (; cnt < 79; ++cnt)
putc(' ', fp);
putc('\r', fp);
putc('\n', fp);
cnt = 0;
}
if (ch != '\n')
carefulputc(ch, fp);
}
if (ch != '\n')
carefulputc(ch, fp);
}
}
fprintf(fp, "%79s\r\n", " ");