wall.c revision 28695
1234449Sobrien/* 2234449Sobrien * Copyright (c) 1988, 1990, 1993 3234449Sobrien * The Regents of the University of California. All rights reserved. 4234449Sobrien * 5234449Sobrien * Redistribution and use in source and binary forms, with or without 6234449Sobrien * modification, are permitted provided that the following conditions 7234449Sobrien * are met: 8234449Sobrien * 1. Redistributions of source code must retain the above copyright 9234449Sobrien * notice, this list of conditions and the following disclaimer. 10234449Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11234449Sobrien * notice, this list of conditions and the following disclaimer in the 12234449Sobrien * documentation and/or other materials provided with the distribution. 13234449Sobrien * 3. All advertising materials mentioning features or use of this software 14234449Sobrien * must display the following acknowledgement: 15234449Sobrien * This product includes software developed by the University of 16234449Sobrien * California, Berkeley and its contributors. 17234449Sobrien * 4. Neither the name of the University nor the names of its contributors 18234449Sobrien * may be used to endorse or promote products derived from this software 19234449Sobrien * without specific prior written permission. 20234449Sobrien * 21234449Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22234449Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23234449Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24234449Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25234449Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26234449Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27234449Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28234449Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29234449Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30234449Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31234449Sobrien * SUCH DAMAGE. 32234449Sobrien */ 33234449Sobrien 34234449Sobrien#ifndef lint 35234449Sobrienstatic const char copyright[] = 36234449Sobrien"@(#) Copyright (c) 1988, 1990, 1993\n\ 37234449Sobrien The Regents of the University of California. All rights reserved.\n"; 38234449Sobrien#endif /* not lint */ 39234449Sobrien 40234449Sobrien#ifndef lint 41234449Sobrien#if 0 42234449Sobrienstatic char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; 43234449Sobrien#endif 44234449Sobrienstatic const char rcsid[] = 45234449Sobrien "$Id$"; 46234449Sobrien#endif /* not lint */ 47234449Sobrien 48234449Sobrien/* 49234449Sobrien * This program is not related to David Wall, whose Stanford Ph.D. thesis 50234449Sobrien * is entitled "Mechanisms for Broadcast and Selective Broadcast". 51234449Sobrien */ 52234449Sobrien 53234449Sobrien#include <sys/param.h> 54234449Sobrien#include <sys/stat.h> 55234449Sobrien#include <sys/time.h> 56234449Sobrien#include <sys/uio.h> 57234449Sobrien 58234449Sobrien#include <ctype.h> 59234449Sobrien#include <err.h> 60234449Sobrien#include <locale.h> 61234449Sobrien#include <paths.h> 62234449Sobrien#include <pwd.h> 63234449Sobrien#include <stdio.h> 64234449Sobrien#include <stdlib.h> 65234449Sobrien#include <string.h> 66234449Sobrien#include <unistd.h> 67234449Sobrien#include <utmp.h> 68234449Sobrien 69234449Sobrienvoid makemsg __P((char *)); 70234449Sobrienstatic void usage __P((void)); 71234449Sobrien 72234449Sobrien#define IGNOREUSER "sleeper" 73234449Sobrien 74234449Sobrienint nobanner; 75234449Sobrienint mbufsize; 76234449Sobrienchar *mbuf; 77234449Sobrien 78234449Sobrien/* ARGSUSED */ 79234449Sobrienint 80234449Sobrienmain(argc, argv) 81234449Sobrien int argc; 82234449Sobrien char **argv; 83234449Sobrien{ 84234449Sobrien int ch; 85234449Sobrien struct iovec iov; 86234449Sobrien struct utmp utmp; 87234449Sobrien FILE *fp; 88234449Sobrien char *p, *ttymsg(); 89234449Sobrien char line[sizeof(utmp.ut_line) + 1]; 90234449Sobrien 91234449Sobrien (void)setlocale(LC_CTYPE, ""); 92234449Sobrien 93234449Sobrien while ((ch = getopt(argc, argv, "n")) != -1) 94234449Sobrien switch (ch) { 95234449Sobrien case 'n': 96234449Sobrien /* undoc option for shutdown: suppress banner */ 97234449Sobrien if (geteuid() == 0) 98234449Sobrien nobanner = 1; 99234449Sobrien break; 100234449Sobrien case '?': 101234449Sobrien default: 102234449Sobrien usage(); 103234449Sobrien } 104234449Sobrien argc -= optind; 105234449Sobrien argv += optind; 106234449Sobrien if (argc > 1) 107234449Sobrien usage(); 108234449Sobrien 109234449Sobrien makemsg(*argv); 110234449Sobrien 111234449Sobrien if (!(fp = fopen(_PATH_UTMP, "r"))) 112234449Sobrien errx(1, "cannot read %s", _PATH_UTMP); 113234449Sobrien iov.iov_base = mbuf; 114234449Sobrien iov.iov_len = mbufsize; 115234449Sobrien /* NOSTRICT */ 116234449Sobrien while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) { 117234449Sobrien if (!utmp.ut_name[0] || 118234449Sobrien !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) 119234449Sobrien continue; 120234449Sobrien strncpy(line, utmp.ut_line, sizeof(utmp.ut_line)); 121234449Sobrien line[sizeof(utmp.ut_line)] = '\0'; 122234449Sobrien if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) 123234449Sobrien warnx("%s", p); 124234449Sobrien } 125234449Sobrien exit(0); 126234449Sobrien} 127234449Sobrien 128234449Sobrienstatic void 129234449Sobrienusage() 130234449Sobrien{ 131234449Sobrien (void)fprintf(stderr, "usage: wall [file]\n"); 132234449Sobrien exit(1); 133234449Sobrien} 134234449Sobrien 135234449Sobrienvoid 136234449Sobrienmakemsg(fname) 137234449Sobrien char *fname; 138234449Sobrien{ 139234449Sobrien register int cnt; 140234449Sobrien register unsigned char ch; 141234449Sobrien struct tm *lt; 142234449Sobrien struct passwd *pw; 143234449Sobrien struct stat sbuf; 144234449Sobrien time_t now, time(); 145234449Sobrien FILE *fp; 146234449Sobrien int fd; 147234449Sobrien char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15]; 148234449Sobrien char *getlogin(), *strcpy(), *ttyname(); 149234449Sobrien 150234449Sobrien (void)strcpy(tmpname, _PATH_TMP); 151234449Sobrien (void)strcat(tmpname, "/wall.XXXXXX"); 152234449Sobrien if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) 153234449Sobrien errx(1, "can't open temporary file"); 154234449Sobrien (void)unlink(tmpname); 155234449Sobrien 156234449Sobrien if (!nobanner) { 157234449Sobrien if (!(whom = getlogin())) 158234449Sobrien whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 159234449Sobrien (void)gethostname(hostname, sizeof(hostname)); 160234449Sobrien (void)time(&now); 161234449Sobrien lt = localtime(&now); 162234449Sobrien 163234449Sobrien /* 164234449Sobrien * all this stuff is to blank out a square for the message; 165234449Sobrien * we wrap message lines at column 79, not 80, because some 166234449Sobrien * terminals wrap after 79, some do not, and we can't tell. 167234449Sobrien * Which means that we may leave a non-blank character 168234449Sobrien * in column 80, but that can't be helped. 169234449Sobrien */ 170234449Sobrien (void)fprintf(fp, "\r%79s\r\n", " "); 171234449Sobrien (void)sprintf(lbuf, "Broadcast Message from %s@%s", 172234449Sobrien whom, hostname); 173234449Sobrien (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 174234449Sobrien (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2), 175234449Sobrien lt->tm_hour, lt->tm_min); 176234449Sobrien (void)fprintf(fp, "%-79.79s\r\n", lbuf); 177234449Sobrien } 178234449Sobrien (void)fprintf(fp, "%79s\r\n", " "); 179234449Sobrien 180234449Sobrien if (fname && !(freopen(fname, "r", stdin))) 181234449Sobrien errx(1, "can't read %s", fname); 182234449Sobrien while (fgets(lbuf, sizeof(lbuf), stdin)) 183234449Sobrien for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 184234449Sobrien again: 185234449Sobrien if (cnt == 79 || ch == '\n') { 186234449Sobrien for (; cnt < 79; ++cnt) 187234449Sobrien putc(' ', fp); 188234449Sobrien putc('\r', fp); 189234449Sobrien putc('\n', fp); 190234449Sobrien cnt = 0; 191234449Sobrien } else if ( ( (ch & 0x7F) < ' ' /* locale-independent */ 192234449Sobrien || (!isprint(ch) && !isspace(ch)) 193234449Sobrien ) 194234449Sobrien && strchr("\a\f\t\v\b\r\n", ch) == NULL 195234449Sobrien ) { 196234449Sobrien if (ch & 0x80) { 197234449Sobrien ch &= 0x7F; 198234449Sobrien (void)fprintf(fp, "M-"); 199234449Sobrien goto again; 200234449Sobrien } 201234449Sobrien putc('^', fp); 202234449Sobrien putc(ch^0x40, fp); /* DEL to ?, others to alpha */ 203234449Sobrien } else 204234449Sobrien putc(ch, fp); 205234449Sobrien } 206234449Sobrien (void)fprintf(fp, "%79s\r\n", " "); 207234449Sobrien rewind(fp); 208234449Sobrien 209234449Sobrien if (fstat(fd, &sbuf)) 210234449Sobrien errx(1, "can't stat temporary file"); 211234449Sobrien mbufsize = sbuf.st_size; 212234449Sobrien if (!(mbuf = malloc((u_int)mbufsize))) 213234449Sobrien errx(1, "out of memory"); 214234449Sobrien if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) 215234449Sobrien errx(1, "can't read temporary file"); 216234449Sobrien (void)close(fd); 217234449Sobrien} 218234449Sobrien