diff options
Diffstat (limited to 'term-utils/wall.c')
-rw-r--r-- | term-utils/wall.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/term-utils/wall.c b/term-utils/wall.c new file mode 100644 index 0000000..30324aa --- /dev/null +++ b/term-utils/wall.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Modified Sun Mar 12 10:34:34 1995, faith@cs.unc.edu, for Linux + */ + +/* + * This program is not related to David Wall, whose Stanford Ph.D. thesis + * is entitled "Mechanisms for Broadcast and Selective Broadcast". + * + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> + +#include <errno.h> +#include <paths.h> +#include <ctype.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <utmp.h> +#include <getopt.h> + +#include "nls.h" +#include "xalloc.h" +#include "strutils.h" +#include "ttymsg.h" +#include "pathnames.h" +#include "carefulputc.h" +#include "c.h" +#include "fileutils.h" +#include "closestream.h" + +#define IGNOREUSER "sleeper" +#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 void __attribute__((__noreturn__)) usage(FILE *out) +{ + fputs(_("\nUsage:\n"), out); + fprintf(out, + _(" %s [options] [<file>]\n"),program_invocation_short_name); + + fputs(_("\nOptions:\n"), out); + fputs(_(" -n, --nobanner do not print banner, works only for root\n" + " -t, --timeout <timeout> write timeout in seconds\n" + " -V, --version output version information and exit\n" + " -h, --help display this help and exit\n\n"), out); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + +int +main(int argc, char **argv) { + int ch; + struct iovec iov; + struct utmp *utmpptr; + char *p; + char line[sizeof(utmpptr->ut_line) + 1]; + int print_banner = TRUE; + char *mbuf; + size_t mbufsize; + unsigned timeout = WRITE_TIME_OUT; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + + static const struct option longopts[] = { + { "nobanner", no_argument, 0, 'n' }, + { "timeout", required_argument, 0, 't' }, + { "version", no_argument, 0, 'V' }, + { "help", no_argument, 0, 'h' }, + { NULL, 0, 0, 0 } + }; + + while ((ch = getopt_long(argc, argv, "nt:Vh", longopts, NULL)) != -1) { + switch (ch) { + case 'n': + if (geteuid() == 0) + print_banner = FALSE; + else + warnx(_("--nobanner is available only for root")); + break; + case 't': + timeout = strtou32_or_err(optarg, _("invalid timeout argument")); + if (timeout < 1) + errx(EXIT_FAILURE, _("invalid timeout argument: %s"), optarg); + break; + case 'V': + printf(_("%s from %s\n"), program_invocation_short_name, + PACKAGE_STRING); + exit(EXIT_SUCCESS); + case 'h': + usage(stdout); + default: + usage(stderr); + } + } + argc -= optind; + argv += optind; + if (argc > 1) + usage(stderr); + + mbuf = makemsg(*argv, &mbufsize, print_banner); + + iov.iov_base = mbuf; + iov.iov_len = mbufsize; + while((utmpptr = getutent())) { + if (!utmpptr->ut_name[0] || + !strncmp(utmpptr->ut_name, IGNOREUSER, + sizeof(utmpptr->ut_name))) + continue; +#ifdef USER_PROCESS + 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. */ + if (utmpptr->ut_line[0] == ':') + continue; + + xstrncpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line)); + if ((p = ttymsg(&iov, 1, line, timeout)) != NULL) + warnx("%s", p); + } + endutent(); + free(mbuf); + exit(EXIT_SUCCESS); +} + +char * +makemsg(char *fname, size_t *mbufsize, int print_banner) +{ + register int ch, cnt; + struct tm *lt; + struct passwd *pw; + struct stat sbuf; + time_t now; + FILE *fp; + char *p, *whom, *where, *hostname, *lbuf, *tmpname, *mbuf; + long line_max; + + hostname = xmalloc(sysconf(_SC_HOST_NAME_MAX) + 1); + line_max = sysconf(_SC_LINE_MAX); + lbuf = xmalloc(line_max); + + if ((fp = xfmkstemp(&tmpname, NULL)) == NULL) + err(EXIT_FAILURE, _("can't open temporary file")); + unlink(tmpname); + free(tmpname); + + if (print_banner == TRUE) { + if (!(whom = getlogin()) || !*whom) + whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; + if (!whom) { + whom = "someone"; + warn(_("cannot get passwd uid")); + } + where = ttyname(STDOUT_FILENO); + if (!where) { + where = "somewhere"; + warn(_("cannot get tty name")); + } + gethostname(hostname, sizeof(hostname)); + time(&now); + lt = localtime(&now); + + /* + * all this stuff is to blank out a square for the message; + * we wrap message lines at column 79, not 80, because some + * terminals wrap after 79, some do not, and we can't tell. + * Which means that we may leave a non-blank character + * in column 80, but that can't be helped. + */ + /* snprintf is not always available, but the sprintf's here + will not overflow as long as %d takes at most 100 chars */ + fprintf(fp, "\r%79s\r\n", " "); + sprintf(lbuf, _("Broadcast Message from %s@%s"), + whom, hostname); + fprintf(fp, "%-79.79s\007\007\r\n", lbuf); + sprintf(lbuf, " (%s) at %d:%02d ...", + where, lt->tm_hour, lt->tm_min); + fprintf(fp, "%-79.79s\r\n", lbuf); + } + fprintf(fp, "%79s\r\n", " "); + + free(hostname); + + 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); + } + + 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); + } + } + fprintf(fp, "%79s\r\n", " "); + + free(lbuf); + rewind(fp); + + if (fstat(fileno(fp), &sbuf)) + err(EXIT_FAILURE, _("stat failed")); + + *mbufsize = (size_t) sbuf.st_size; + mbuf = xmalloc(*mbufsize); + + if (fread(mbuf, 1, *mbufsize, fp) != *mbufsize) + err(EXIT_FAILURE, _("fread failed")); + + if (close_stream(fp) != 0) + errx(EXIT_FAILURE, _("write error")); + return mbuf; +} |