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