wall.c revision 50477
126497Sache/*
226497Sache * Copyright (c) 1988, 1990, 1993
3136644Sache *	The Regents of the University of California.  All rights reserved.
421308Sache *
526497Sache * Redistribution and use in source and binary forms, with or without
626497Sache * modification, are permitted provided that the following conditions
726497Sache * are met:
826497Sache * 1. Redistributions of source code must retain the above copyright
926497Sache *    notice, this list of conditions and the following disclaimer.
1026497Sache * 2. Redistributions in binary form must reproduce the above copyright
1126497Sache *    notice, this list of conditions and the following disclaimer in the
1226497Sache *    documentation and/or other materials provided with the distribution.
1326497Sache * 3. All advertising materials mentioning features or use of this software
1426497Sache *    must display the following acknowledgement:
1526497Sache *	This product includes software developed by the University of
1626497Sache *	California, Berkeley and its contributors.
1758310Sache * 4. Neither the name of the University nor the names of its contributors
1826497Sache *    may be used to endorse or promote products derived from this software
1926497Sache *    without specific prior written permission.
2026497Sache *
21136644Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22136644Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23136644Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24136644Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25136644Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26136644Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27136644Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28136644Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2921308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3021308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3126497Sache * SUCH DAMAGE.
3235486Sache */
3321308Sache
3421308Sache#ifndef lint
3521308Sachestatic const char copyright[] =
3621308Sache"@(#) Copyright (c) 1988, 1990, 1993\n\
3721308Sache	The Regents of the University of California.  All rights reserved.\n";
3821308Sache#endif /* not lint */
3921308Sache
4047558Sache#ifndef lint
4147558Sache#if 0
4221308Sachestatic char sccsid[] = "@(#)wall.c	8.2 (Berkeley) 11/16/93";
4321308Sache#endif
4421308Sachestatic const char rcsid[] =
4521308Sache  "$FreeBSD: head/usr.bin/wall/wall.c 50477 1999-08-28 01:08:13Z peter $";
46157184Sache#endif /* not lint */
47157184Sache
4875406Sache/*
4947558Sache * This program is not related to David Wall, whose Stanford Ph.D. thesis
5047558Sache * is entitled "Mechanisms for Broadcast and Selective Broadcast".
5126497Sache */
5226497Sache
5321308Sache#include <sys/param.h>
5426497Sache#include <sys/stat.h>
5526497Sache#include <sys/uio.h>
5626497Sache
5726497Sache#include <ctype.h>
58136644Sache#include <err.h>
59136644Sache#include <locale.h>
6026497Sache#include <paths.h>
6126497Sache#include <pwd.h>
6226497Sache#include <stdio.h>
6326497Sache#include <stdlib.h>
6426497Sache#include <string.h>
65119610Sache#include <time.h>
66119610Sache#include <unistd.h>
67119610Sache#include <utmp.h>
6826497Sache
6926497Sachevoid	makemsg __P((char *));
7026497Sachestatic void usage __P((void));
7126497Sache
7221308Sache#define	IGNOREUSER	"sleeper"
7326497Sache
7421308Sacheint nobanner;
7521308Sacheint mbufsize;
76157184Sachechar *mbuf;
7726497Sache
7821308Sache/* ARGSUSED */
7958310Sacheint
8058310Sachemain(argc, argv)
8126497Sache	int argc;
82119610Sache	char **argv;
8321308Sache{
8475406Sache	int ch;
8575406Sache	struct iovec iov;
8621308Sache	struct utmp utmp;
8775406Sache	FILE *fp;
8875406Sache	char *p, *ttymsg();
8975406Sache	char line[sizeof(utmp.ut_line) + 1];
90119610Sache
9175406Sache	(void)setlocale(LC_CTYPE, "");
9275406Sache
9321308Sache	while ((ch = getopt(argc, argv, "n")) != -1)
9447558Sache		switch (ch) {
9521308Sache		case 'n':
9621308Sache			/* undoc option for shutdown: suppress banner */
9721308Sache			if (geteuid() == 0)
9821308Sache				nobanner = 1;
9935486Sache			break;
10035486Sache		case '?':
10121308Sache		default:
10221308Sache			usage();
10321308Sache		}
10421308Sache	argc -= optind;
10521308Sache	argv += optind;
10621308Sache	if (argc > 1)
10721308Sache		usage();
10821308Sache
10921308Sache	makemsg(*argv);
11026497Sache
11175406Sache	if (!(fp = fopen(_PATH_UTMP, "r")))
112119610Sache		errx(1, "cannot read %s", _PATH_UTMP);
113119610Sache	iov.iov_base = mbuf;
11421308Sache	iov.iov_len = mbufsize;
11521308Sache	/* NOSTRICT */
11621308Sache	while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) {
11726497Sache		if (!utmp.ut_name[0] ||
11875406Sache		    !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name)))
119119610Sache			continue;
12021308Sache		strncpy(line, utmp.ut_line, sizeof(utmp.ut_line));
121119610Sache		line[sizeof(utmp.ut_line)] = '\0';
12226497Sache		if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL)
12321308Sache			warnx("%s", p);
12421308Sache	}
12521308Sache	exit(0);
126119610Sache}
12721308Sache
12821308Sachestatic void
12921308Sacheusage()
13021308Sache{
13121308Sache	(void)fprintf(stderr, "usage: wall [file]\n");
13221308Sache	exit(1);
13321308Sache}
13447558Sache
13535486Sachevoid
13635486Sachemakemsg(fname)
13735486Sache	char *fname;
13821308Sache{
13947558Sache	register int cnt;
14075406Sache	register unsigned char ch;
14121308Sache	struct tm *lt;
14221308Sache	struct passwd *pw;
143119610Sache	struct stat sbuf;
144119610Sache	time_t now;
14521308Sache	FILE *fp;
146119610Sache	int fd;
14735486Sache	char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[256], tmpname[64];
148119610Sache
14958310Sache	snprintf(tmpname, sizeof(tmpname), "%s/wall.XXXXXX", _PATH_TMP);
15035486Sache
15121308Sache	if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+")))
15221308Sache		errx(1, "can't open temporary file");
15326497Sache	(void)unlink(tmpname);
15447558Sache
15521308Sache	if (!nobanner) {
15621308Sache		if (!(whom = getlogin()))
15721308Sache			whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
15826497Sache		(void)gethostname(hostname, sizeof(hostname));
15947558Sache		(void)time(&now);
16021308Sache		lt = localtime(&now);
16121308Sache
162119610Sache		/*
163119610Sache		 * all this stuff is to blank out a square for the message;
164119610Sache		 * we wrap message lines at column 79, not 80, because some
165119610Sache		 * terminals wrap after 79, some do not, and we can't tell.
166119610Sache		 * Which means that we may leave a non-blank character
167119610Sache		 * in column 80, but that can't be helped.
16858310Sache		 */
16958310Sache		(void)fprintf(fp, "\r%79s\r\n", " ");
17026497Sache		(void)snprintf(lbuf, sizeof(lbuf),
17175406Sache		    "Broadcast Message from %s@%s",
17275406Sache		    whom, hostname);
17375406Sache		(void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf);
17426497Sache		(void)snprintf(lbuf, sizeof(lbuf),
17526497Sache		    "        (%s) at %d:%02d ...", ttyname(2),
17626497Sache		    lt->tm_hour, lt->tm_min);
17726497Sache		(void)fprintf(fp, "%-79.79s\r\n", lbuf);
17826497Sache	}
17926497Sache	(void)fprintf(fp, "%79s\r\n", " ");
18026497Sache
18126497Sache	if (fname && !(freopen(fname, "r", stdin)))
18226497Sache		errx(1, "can't read %s", fname);
18326497Sache	while (fgets(lbuf, sizeof(lbuf), stdin))
18426497Sache		for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
18526497Sache			if (cnt == 79 || ch == '\n') {
18626497Sache				for (; cnt < 79; ++cnt)
18726497Sache					putc(' ', fp);
18826497Sache				putc('\r', fp);
18926497Sache				putc('\n', fp);
19026497Sache				cnt = 0;
19158310Sache			} else if (((ch & 0x80) && ch < 0xA0) ||
19258310Sache				   /* disable upper controls */
19326497Sache				   (!isprint(ch) && !isspace(ch) &&
19447558Sache				    ch != '\a' && ch != '\b')
19547558Sache				  ) {
19647558Sache				if (ch & 0x80) {
19747558Sache					ch &= 0x7F;
19847558Sache					putc('M', fp);
19921308Sache					if (++cnt == 79) {
20026497Sache						putc('\r', fp);
20121308Sache						putc('\n', fp);
20221308Sache						cnt = 0;
20335486Sache					}
20435486Sache					putc('-', fp);
20535486Sache					if (++cnt == 79) {
20635486Sache						putc('\r', fp);
20721308Sache						putc('\n', fp);
20821308Sache						cnt = 0;
20958310Sache					}
21026497Sache				}
211119610Sache				if (iscntrl(ch)) {
21221308Sache					ch ^= 040;
21358310Sache					putc('^', fp);
21458310Sache					if (++cnt == 79) {
215119610Sache						putc('\r', fp);
21658310Sache						putc('\n', fp);
21758310Sache						cnt = 0;
21858310Sache					}
21958310Sache				}
220119610Sache			}
221119610Sache			putc(ch, fp);
222136644Sache		}
223119610Sache	(void)fprintf(fp, "%79s\r\n", " ");
224119610Sache	rewind(fp);
225119610Sache
226119610Sache	if (fstat(fd, &sbuf))
227119610Sache		errx(1, "can't stat temporary file");
228119610Sache	mbufsize = sbuf.st_size;
22921308Sache	if (!(mbuf = malloc((u_int)mbufsize)))
230136644Sache		errx(1, "out of memory");
231136644Sache	if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize)
232119610Sache		errx(1, "can't read temporary file");
233119610Sache	(void)close(fd);
23421308Sache}
235136644Sache