1*c5775359Smjl /* $NetBSD: wall.c,v 1.18 2001/01/05 04:06:49 mjl 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*c5775359Smjl __RCSID("$NetBSD: wall.c,v 1.18 2001/01/05 04:06:49 mjl 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 69*c5775359Smjl void makemsg(const char *); 70*c5775359Smjl int main(int, char **); 7161f28255Scgd 7261f28255Scgd int nobanner; 7361f28255Scgd int mbufsize; 7461f28255Scgd char *mbuf; 7561f28255Scgd 7661f28255Scgd /* ARGSUSED */ 77f7c6bf57Sjtc int 78*c5775359Smjl main(int argc, char **argv) 7961f28255Scgd { 8061f28255Scgd int ch; 8161f28255Scgd struct iovec iov; 8261f28255Scgd struct utmp utmp; 8361f28255Scgd FILE *fp; 84c897d730Schristos char *p; 85b9b17c30Scgd struct passwd *pep = getpwnam("nobody"); 86a8bfd3d1Sjtc char line[sizeof(utmp.ut_line) + 1]; 8761f28255Scgd 88a6f32a1dSlukem while ((ch = getopt(argc, argv, "n")) != -1) 8961f28255Scgd switch (ch) { 9061f28255Scgd case 'n': 9161f28255Scgd /* undoc option for shutdown: suppress banner */ 92b9b17c30Scgd if (geteuid() == 0 || (pep && getuid() == pep->pw_uid)) 9361f28255Scgd nobanner = 1; 9461f28255Scgd break; 9561f28255Scgd case '?': 9661f28255Scgd default: 9761f28255Scgd usage: 9861f28255Scgd (void)fprintf(stderr, "usage: wall [file]\n"); 9961f28255Scgd exit(1); 10061f28255Scgd } 10161f28255Scgd argc -= optind; 10261f28255Scgd argv += optind; 10361f28255Scgd if (argc > 1) 10461f28255Scgd goto usage; 10561f28255Scgd 10661f28255Scgd makemsg(*argv); 10761f28255Scgd 108a6f32a1dSlukem if (!(fp = fopen(_PATH_UTMP, "r"))) 109a6f32a1dSlukem err(1, "cannot read %s", _PATH_UTMP); 11061f28255Scgd iov.iov_base = mbuf; 11161f28255Scgd iov.iov_len = mbufsize; 11261f28255Scgd /* NOSTRICT */ 11361f28255Scgd while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) { 114d18550faSmjl if (!utmp.ut_name[0]) 11561f28255Scgd continue; 116a8bfd3d1Sjtc strncpy(line, utmp.ut_line, sizeof(utmp.ut_line)); 117a8bfd3d1Sjtc line[sizeof(utmp.ut_line)] = '\0'; 118a8bfd3d1Sjtc if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) 119a6f32a1dSlukem warnx("%s", p); 12061f28255Scgd } 12161f28255Scgd exit(0); 12261f28255Scgd } 12361f28255Scgd 124f7c6bf57Sjtc void 125*c5775359Smjl makemsg(const char *fname) 12661f28255Scgd { 12761f28255Scgd register int ch, cnt; 12861f28255Scgd struct tm *lt; 12961f28255Scgd struct passwd *pw; 13061f28255Scgd struct stat sbuf; 131c897d730Schristos time_t now; 13261f28255Scgd FILE *fp; 13361f28255Scgd int fd; 134af26acbcSmycroft const char *whom; 13520117cd1Staca char *p, *tty, tmpname[32], lbuf[100], hostname[MAXHOSTNAMELEN+1]; 13661f28255Scgd 13723768a9eSmrg (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP); 138dd3520c0Schristos if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+"))) 139a6f32a1dSlukem err(1, "can't open temporary file"); 14061f28255Scgd (void)unlink(tmpname); 14161f28255Scgd 14261f28255Scgd if (!nobanner) { 14361f28255Scgd if (!(whom = getlogin())) 14461f28255Scgd whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 14561f28255Scgd (void)gethostname(hostname, sizeof(hostname)); 146ed666575Smrg hostname[sizeof(hostname) - 1] = '\0'; 14761f28255Scgd (void)time(&now); 14861f28255Scgd lt = localtime(&now); 14961f28255Scgd 15061f28255Scgd /* 15161f28255Scgd * all this stuff is to blank out a square for the message; 15261f28255Scgd * we wrap message lines at column 79, not 80, because some 15361f28255Scgd * terminals wrap after 79, some do not, and we can't tell. 15461f28255Scgd * Which means that we may leave a non-blank character 15561f28255Scgd * in column 80, but that can't be helped. 15661f28255Scgd */ 15761f28255Scgd (void)fprintf(fp, "\r%79s\r\n", " "); 15823768a9eSmrg (void)snprintf(lbuf, sizeof lbuf, 15923768a9eSmrg "Broadcast Message from %s@%s", whom, hostname); 16061f28255Scgd (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 16199ebb803Staca tty = ttyname(STDERR_FILENO); 16299ebb803Staca if (tty == NULL) 16320117cd1Staca tty = "??"; 16499ebb803Staca (void)snprintf(lbuf, sizeof lbuf, 16520117cd1Staca " (%s) at %d:%02d ...", tty, lt->tm_hour, 16620117cd1Staca lt->tm_min); 16761f28255Scgd (void)fprintf(fp, "%-79.79s\r\n", lbuf); 16861f28255Scgd } 16961f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 17061f28255Scgd 171a6f32a1dSlukem if (fname && !(freopen(fname, "r", stdin))) 172a6f32a1dSlukem err(1, "can't read %s", fname); 17361f28255Scgd while (fgets(lbuf, sizeof(lbuf), stdin)) 174a8bfd3d1Sjtc for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 17561f28255Scgd if (cnt == 79 || ch == '\n') { 17661f28255Scgd for (; cnt < 79; ++cnt) 17761f28255Scgd putc(' ', fp); 17861f28255Scgd putc('\r', fp); 17961f28255Scgd putc('\n', fp); 180f90eda1cSmycroft cnt = -1; 181f90eda1cSmycroft } 182f90eda1cSmycroft if (ch != '\n') 18361f28255Scgd putc(ch, fp); 18461f28255Scgd } 18561f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 18661f28255Scgd rewind(fp); 18761f28255Scgd 188a6f32a1dSlukem if (fstat(fd, &sbuf)) 189a6f32a1dSlukem err(1, "can't stat temporary file"); 19061f28255Scgd mbufsize = sbuf.st_size; 191a6f32a1dSlukem if (!(mbuf = malloc((u_int)mbufsize))) 192a6f32a1dSlukem err(1, "malloc"); 193a6f32a1dSlukem if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) 194a6f32a1dSlukem err(1, "can't read temporary file"); 19561f28255Scgd (void)close(fd); 19661f28255Scgd } 197