1*2abe3770Sitojun /* $NetBSD: wall.c,v 1.20 2002/08/16 20:21:49 itojun 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*2abe3770Sitojun __RCSID("$NetBSD: wall.c,v 1.20 2002/08/16 20:21:49 itojun 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> 60*2abe3770Sitojun #include <errno.h> 61a8bfd3d1Sjtc #include <paths.h> 6261f28255Scgd #include <pwd.h> 6361f28255Scgd #include <stdio.h> 6461f28255Scgd #include <stdlib.h> 65f7c6bf57Sjtc #include <string.h> 66f7c6bf57Sjtc #include <unistd.h> 67c897d730Schristos #include <util.h> 68a8bfd3d1Sjtc 69c020d65eSchristos #include "utmpentry.h" 70c020d65eSchristos 71c5775359Smjl void makemsg(const char *); 72c5775359Smjl int main(int, char **); 7361f28255Scgd 7461f28255Scgd int nobanner; 75*2abe3770Sitojun size_t mbufsize; 7661f28255Scgd char *mbuf; 7761f28255Scgd 7861f28255Scgd /* ARGSUSED */ 79f7c6bf57Sjtc int 80c5775359Smjl main(int argc, char **argv) 8161f28255Scgd { 8261f28255Scgd int ch; 8361f28255Scgd struct iovec iov; 84c897d730Schristos char *p; 85*2abe3770Sitojun struct passwd *pep; 86c020d65eSchristos struct utmpentry *ep; 87*2abe3770Sitojun gid_t egid; 88*2abe3770Sitojun 89*2abe3770Sitojun egid = getegid(); 90*2abe3770Sitojun if (setegid(getgid()) == -1) 91*2abe3770Sitojun err(1, "setegid"); 92*2abe3770Sitojun pep = getpwnam("nobody"); 9361f28255Scgd 94a6f32a1dSlukem while ((ch = getopt(argc, argv, "n")) != -1) 9561f28255Scgd switch (ch) { 9661f28255Scgd case 'n': 9761f28255Scgd /* undoc option for shutdown: suppress banner */ 98b9b17c30Scgd if (geteuid() == 0 || (pep && getuid() == pep->pw_uid)) 9961f28255Scgd nobanner = 1; 10061f28255Scgd break; 10161f28255Scgd case '?': 10261f28255Scgd default: 10361f28255Scgd usage: 10461f28255Scgd (void)fprintf(stderr, "usage: wall [file]\n"); 10561f28255Scgd exit(1); 10661f28255Scgd } 10761f28255Scgd argc -= optind; 10861f28255Scgd argv += optind; 10961f28255Scgd if (argc > 1) 11061f28255Scgd goto usage; 11161f28255Scgd 11261f28255Scgd makemsg(*argv); 11361f28255Scgd 11461f28255Scgd iov.iov_base = mbuf; 11561f28255Scgd iov.iov_len = mbufsize; 116c020d65eSchristos (void)getutentries(NULL, &ep); 117*2abe3770Sitojun (void)setegid(egid); 118c020d65eSchristos for (; ep; ep = ep->next) 119c020d65eSchristos if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL) 120a6f32a1dSlukem warnx("%s", p); 12161f28255Scgd exit(0); 12261f28255Scgd } 12361f28255Scgd 124f7c6bf57Sjtc void 125c5775359Smjl makemsg(const char *fname) 12661f28255Scgd { 127*2abe3770Sitojun 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); 138*2abe3770Sitojun if ((fd = mkstemp(tmpname)) == -1) 139a6f32a1dSlukem err(1, "can't open temporary file"); 14061f28255Scgd (void)unlink(tmpname); 141*2abe3770Sitojun if (!(fp = fdopen(fd, "r+"))) 142*2abe3770Sitojun err(1, "can't open temporary file"); 14361f28255Scgd 14461f28255Scgd if (!nobanner) { 14561f28255Scgd if (!(whom = getlogin())) 14661f28255Scgd whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 14761f28255Scgd (void)gethostname(hostname, sizeof(hostname)); 148ed666575Smrg hostname[sizeof(hostname) - 1] = '\0'; 14961f28255Scgd (void)time(&now); 15061f28255Scgd lt = localtime(&now); 15161f28255Scgd 15261f28255Scgd /* 15361f28255Scgd * all this stuff is to blank out a square for the message; 15461f28255Scgd * we wrap message lines at column 79, not 80, because some 15561f28255Scgd * terminals wrap after 79, some do not, and we can't tell. 15661f28255Scgd * Which means that we may leave a non-blank character 15761f28255Scgd * in column 80, but that can't be helped. 15861f28255Scgd */ 15961f28255Scgd (void)fprintf(fp, "\r%79s\r\n", " "); 16023768a9eSmrg (void)snprintf(lbuf, sizeof lbuf, 16123768a9eSmrg "Broadcast Message from %s@%s", whom, hostname); 16261f28255Scgd (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 16399ebb803Staca tty = ttyname(STDERR_FILENO); 16499ebb803Staca if (tty == NULL) 16520117cd1Staca tty = "??"; 16699ebb803Staca (void)snprintf(lbuf, sizeof lbuf, 16720117cd1Staca " (%s) at %d:%02d ...", tty, lt->tm_hour, 16820117cd1Staca lt->tm_min); 16961f28255Scgd (void)fprintf(fp, "%-79.79s\r\n", lbuf); 17061f28255Scgd } 17161f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 17261f28255Scgd 173a6f32a1dSlukem if (fname && !(freopen(fname, "r", stdin))) 174a6f32a1dSlukem err(1, "can't read %s", fname); 17561f28255Scgd while (fgets(lbuf, sizeof(lbuf), stdin)) 176a8bfd3d1Sjtc for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 17761f28255Scgd if (cnt == 79 || ch == '\n') { 17861f28255Scgd for (; cnt < 79; ++cnt) 17961f28255Scgd putc(' ', fp); 18061f28255Scgd putc('\r', fp); 18161f28255Scgd putc('\n', fp); 182f90eda1cSmycroft cnt = -1; 183f90eda1cSmycroft } 184f90eda1cSmycroft if (ch != '\n') 18561f28255Scgd putc(ch, fp); 18661f28255Scgd } 18761f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 18861f28255Scgd rewind(fp); 18961f28255Scgd 190a6f32a1dSlukem if (fstat(fd, &sbuf)) 191a6f32a1dSlukem err(1, "can't stat temporary file"); 192*2abe3770Sitojun if (sbuf.st_size > SIZE_T_MAX) 193*2abe3770Sitojun errx(1, "file too big"); 19461f28255Scgd mbufsize = sbuf.st_size; 195*2abe3770Sitojun if (!(mbuf = malloc(mbufsize))) 196a6f32a1dSlukem err(1, "malloc"); 197*2abe3770Sitojun if (fread(mbuf, 1, mbufsize, fp) != mbufsize) 198a6f32a1dSlukem err(1, "can't read temporary file"); 199*2abe3770Sitojun (void)fclose(fp); 20061f28255Scgd } 201