1*99ebb803Staca /* $NetBSD: wall.c,v 1.14 2000/09/04 15:21:24 taca Exp $ */ 2a8bfd3d1Sjtc 361f28255Scgd /* 4a8bfd3d1Sjtc * Copyright (c) 1988, 1990, 1993 5a8bfd3d1Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * Redistribution and use in source and binary forms, with or without 861f28255Scgd * modification, are permitted provided that the following conditions 961f28255Scgd * are met: 1061f28255Scgd * 1. Redistributions of source code must retain the above copyright 1161f28255Scgd * notice, this list of conditions and the following disclaimer. 1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1361f28255Scgd * notice, this list of conditions and the following disclaimer in the 1461f28255Scgd * documentation and/or other materials provided with the distribution. 1561f28255Scgd * 3. All advertising materials mentioning features or use of this software 1661f28255Scgd * must display the following acknowledgement: 1761f28255Scgd * This product includes software developed by the University of 1861f28255Scgd * California, Berkeley and its contributors. 1961f28255Scgd * 4. Neither the name of the University nor the names of its contributors 2061f28255Scgd * may be used to endorse or promote products derived from this software 2161f28255Scgd * without specific prior written permission. 2261f28255Scgd * 2361f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2461f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2561f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2661f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2761f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2861f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2961f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3061f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3161f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3261f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3361f28255Scgd * SUCH DAMAGE. 3461f28255Scgd */ 3561f28255Scgd 36c897d730Schristos #include <sys/cdefs.h> 3761f28255Scgd #ifndef lint 38c897d730Schristos __COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\n\ 39c897d730Schristos The Regents of the University of California. All rights reserved.\n"); 4061f28255Scgd #endif /* not lint */ 4161f28255Scgd 4261f28255Scgd #ifndef lint 43a8bfd3d1Sjtc #if 0 44a8bfd3d1Sjtc static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; 45a8bfd3d1Sjtc #endif 46*99ebb803Staca __RCSID("$NetBSD: wall.c,v 1.14 2000/09/04 15:21:24 taca Exp $"); 4761f28255Scgd #endif /* not lint */ 4861f28255Scgd 4961f28255Scgd /* 5061f28255Scgd * This program is not related to David Wall, whose Stanford Ph.D. thesis 5161f28255Scgd * is entitled "Mechanisms for Broadcast and Selective Broadcast". 5261f28255Scgd */ 5361f28255Scgd 5461f28255Scgd #include <sys/param.h> 5561f28255Scgd #include <sys/stat.h> 5661f28255Scgd #include <sys/time.h> 5761f28255Scgd #include <sys/uio.h> 58a8bfd3d1Sjtc 59a6f32a1dSlukem #include <err.h> 60a8bfd3d1Sjtc #include <paths.h> 6161f28255Scgd #include <pwd.h> 6261f28255Scgd #include <stdio.h> 6361f28255Scgd #include <stdlib.h> 64f7c6bf57Sjtc #include <string.h> 65f7c6bf57Sjtc #include <unistd.h> 66a8bfd3d1Sjtc #include <utmp.h> 67c897d730Schristos #include <util.h> 68a8bfd3d1Sjtc 69a8bfd3d1Sjtc void makemsg __P((char *)); 70c897d730Schristos int main __P((int, char *[])); 7161f28255Scgd 7261f28255Scgd #define IGNOREUSER "sleeper" 7361f28255Scgd 7461f28255Scgd int nobanner; 7561f28255Scgd int mbufsize; 7661f28255Scgd char *mbuf; 7761f28255Scgd 7861f28255Scgd /* ARGSUSED */ 79f7c6bf57Sjtc int 8061f28255Scgd main(argc, argv) 8161f28255Scgd int argc; 8261f28255Scgd char **argv; 8361f28255Scgd { 8461f28255Scgd int ch; 8561f28255Scgd struct iovec iov; 8661f28255Scgd struct utmp utmp; 8761f28255Scgd FILE *fp; 88c897d730Schristos char *p; 89b9b17c30Scgd struct passwd *pep = getpwnam("nobody"); 90a8bfd3d1Sjtc char line[sizeof(utmp.ut_line) + 1]; 9161f28255Scgd 92a6f32a1dSlukem while ((ch = getopt(argc, argv, "n")) != -1) 9361f28255Scgd switch (ch) { 9461f28255Scgd case 'n': 9561f28255Scgd /* undoc option for shutdown: suppress banner */ 96b9b17c30Scgd if (geteuid() == 0 || (pep && getuid() == pep->pw_uid)) 9761f28255Scgd nobanner = 1; 9861f28255Scgd break; 9961f28255Scgd case '?': 10061f28255Scgd default: 10161f28255Scgd usage: 10261f28255Scgd (void)fprintf(stderr, "usage: wall [file]\n"); 10361f28255Scgd exit(1); 10461f28255Scgd } 10561f28255Scgd argc -= optind; 10661f28255Scgd argv += optind; 10761f28255Scgd if (argc > 1) 10861f28255Scgd goto usage; 10961f28255Scgd 11061f28255Scgd makemsg(*argv); 11161f28255Scgd 112a6f32a1dSlukem if (!(fp = fopen(_PATH_UTMP, "r"))) 113a6f32a1dSlukem err(1, "cannot read %s", _PATH_UTMP); 11461f28255Scgd iov.iov_base = mbuf; 11561f28255Scgd iov.iov_len = mbufsize; 11661f28255Scgd /* NOSTRICT */ 11761f28255Scgd while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) { 11861f28255Scgd if (!utmp.ut_name[0] || 11961f28255Scgd !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) 12061f28255Scgd continue; 121a8bfd3d1Sjtc strncpy(line, utmp.ut_line, sizeof(utmp.ut_line)); 122a8bfd3d1Sjtc line[sizeof(utmp.ut_line)] = '\0'; 123a8bfd3d1Sjtc if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) 124a6f32a1dSlukem warnx("%s", p); 12561f28255Scgd } 12661f28255Scgd exit(0); 12761f28255Scgd } 12861f28255Scgd 129f7c6bf57Sjtc void 13061f28255Scgd makemsg(fname) 13161f28255Scgd char *fname; 13261f28255Scgd { 13361f28255Scgd register int ch, cnt; 13461f28255Scgd struct tm *lt; 13561f28255Scgd struct passwd *pw; 13661f28255Scgd struct stat sbuf; 137c897d730Schristos time_t now; 13861f28255Scgd FILE *fp; 13961f28255Scgd int fd; 140af26acbcSmycroft const char *whom; 141*99ebb803Staca char *p, *tty, hostname[MAXHOSTNAMELEN+1], lbuf[100], tmpname[15]; 14261f28255Scgd 14323768a9eSmrg (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP); 144dd3520c0Schristos if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+"))) 145a6f32a1dSlukem err(1, "can't open temporary file"); 14661f28255Scgd (void)unlink(tmpname); 14761f28255Scgd 14861f28255Scgd if (!nobanner) { 14961f28255Scgd if (!(whom = getlogin())) 15061f28255Scgd whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 15161f28255Scgd (void)gethostname(hostname, sizeof(hostname)); 152ed666575Smrg hostname[sizeof(hostname) - 1] = '\0'; 15361f28255Scgd (void)time(&now); 15461f28255Scgd lt = localtime(&now); 15561f28255Scgd 15661f28255Scgd /* 15761f28255Scgd * all this stuff is to blank out a square for the message; 15861f28255Scgd * we wrap message lines at column 79, not 80, because some 15961f28255Scgd * terminals wrap after 79, some do not, and we can't tell. 16061f28255Scgd * Which means that we may leave a non-blank character 16161f28255Scgd * in column 80, but that can't be helped. 16261f28255Scgd */ 16361f28255Scgd (void)fprintf(fp, "\r%79s\r\n", " "); 16423768a9eSmrg (void)snprintf(lbuf, sizeof lbuf, 16523768a9eSmrg "Broadcast Message from %s@%s", whom, hostname); 16661f28255Scgd (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 167*99ebb803Staca tty = ttyname(STDERR_FILENO); 168*99ebb803Staca if (tty == NULL) 169*99ebb803Staca (void)snprintf(lbuf, sizeof lbuf, 170*99ebb803Staca " at %d:%02d ...", 171*99ebb803Staca lt->tm_hour, lt->tm_min); 172*99ebb803Staca else 173*99ebb803Staca (void)snprintf(lbuf, sizeof lbuf, 174*99ebb803Staca " (%s) at %d:%02d ...", 175*99ebb803Staca tty, lt->tm_hour, lt->tm_min); 17661f28255Scgd (void)fprintf(fp, "%-79.79s\r\n", lbuf); 17761f28255Scgd } 17861f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 17961f28255Scgd 180a6f32a1dSlukem if (fname && !(freopen(fname, "r", stdin))) 181a6f32a1dSlukem err(1, "can't read %s", fname); 18261f28255Scgd while (fgets(lbuf, sizeof(lbuf), stdin)) 183a8bfd3d1Sjtc for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 18461f28255Scgd if (cnt == 79 || ch == '\n') { 18561f28255Scgd for (; cnt < 79; ++cnt) 18661f28255Scgd putc(' ', fp); 18761f28255Scgd putc('\r', fp); 18861f28255Scgd putc('\n', fp); 189f90eda1cSmycroft cnt = -1; 190f90eda1cSmycroft } 191f90eda1cSmycroft if (ch != '\n') 19261f28255Scgd putc(ch, fp); 19361f28255Scgd } 19461f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 19561f28255Scgd rewind(fp); 19661f28255Scgd 197a6f32a1dSlukem if (fstat(fd, &sbuf)) 198a6f32a1dSlukem err(1, "can't stat temporary file"); 19961f28255Scgd mbufsize = sbuf.st_size; 200a6f32a1dSlukem if (!(mbuf = malloc((u_int)mbufsize))) 201a6f32a1dSlukem err(1, "malloc"); 202a6f32a1dSlukem if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) 203a6f32a1dSlukem err(1, "can't read temporary file"); 20461f28255Scgd (void)close(fd); 20561f28255Scgd } 206