wall.c revision 202200
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1988, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3487675Smarkm#include <sys/cdefs.h> 3587675Smarkm 3687675Smarkm__FBSDID("$FreeBSD: head/usr.bin/wall/wall.c 202200 2010-01-13 18:09:54Z ed $"); 3787675Smarkm 381590Srgrimes#ifndef lint 3928695Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1988, 1990, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287675Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587675Smarkmstatic const char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; 4628695Scharnier#endif 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * This program is not related to David Wall, whose Stanford Ph.D. thesis 501590Srgrimes * is entitled "Mechanisms for Broadcast and Selective Broadcast". 511590Srgrimes */ 521590Srgrimes 531590Srgrimes#include <sys/param.h> 541590Srgrimes#include <sys/stat.h> 551590Srgrimes#include <sys/uio.h> 561590Srgrimes 5728695Scharnier#include <ctype.h> 5828695Scharnier#include <err.h> 5973255Simp#include <grp.h> 6025777Sache#include <locale.h> 611590Srgrimes#include <paths.h> 621590Srgrimes#include <pwd.h> 631590Srgrimes#include <stdio.h> 641590Srgrimes#include <stdlib.h> 651590Srgrimes#include <string.h> 6629434Sache#include <time.h> 671590Srgrimes#include <unistd.h> 68202200Sed#include <utmpx.h> 691590Srgrimes 7083242Sdd#include "ttymsg.h" 7183242Sdd 7273255Simpstatic void makemsg(char *); 7373255Simpstatic void usage(void); 741590Srgrimes 7573255Simpstruct wallgroup { 7673255Simp struct wallgroup *next; 7773255Simp char *name; 7873255Simp gid_t gid; 7973255Simp} *grouplist; 801590Srgrimesint nobanner; 811590Srgrimesint mbufsize; 821590Srgrimeschar *mbuf; 831590Srgrimes 84155875Scognetstatic int 85200156Sedttystat(char *line) 86155875Scognet{ 87155875Scognet struct stat sb; 88155875Scognet char ttybuf[MAXPATHLEN]; 89155875Scognet 90200156Sed (void)snprintf(ttybuf, sizeof(ttybuf), "%s%s", _PATH_DEV, line); 91155875Scognet if (stat(ttybuf, &sb) == 0) { 92155875Scognet return (0); 93155875Scognet } else 94155875Scognet return (-1); 95155875Scognet} 96155875Scognet 971590Srgrimesint 9873255Simpmain(int argc, char *argv[]) 991590Srgrimes{ 1001590Srgrimes struct iovec iov; 101200156Sed struct utmpx *utmp; 10273255Simp int ch; 10383082Sru int ingroup; 10473255Simp struct wallgroup *g; 10573255Simp struct group *grp; 10683242Sdd char **np; 10783242Sdd const char *p; 10873255Simp struct passwd *pw; 1091590Srgrimes 11025777Sache (void)setlocale(LC_CTYPE, ""); 11125777Sache 11273255Simp while ((ch = getopt(argc, argv, "g:n")) != -1) 1131590Srgrimes switch (ch) { 1141590Srgrimes case 'n': 1151590Srgrimes /* undoc option for shutdown: suppress banner */ 1161590Srgrimes if (geteuid() == 0) 1171590Srgrimes nobanner = 1; 1181590Srgrimes break; 11973255Simp case 'g': 12073255Simp g = (struct wallgroup *)malloc(sizeof *g); 12173255Simp g->next = grouplist; 12273255Simp g->name = optarg; 12373255Simp g->gid = -1; 12473255Simp grouplist = g; 12573255Simp break; 1261590Srgrimes case '?': 1271590Srgrimes default: 12828695Scharnier usage(); 1291590Srgrimes } 1301590Srgrimes argc -= optind; 1311590Srgrimes argv += optind; 1321590Srgrimes if (argc > 1) 13328695Scharnier usage(); 1341590Srgrimes 13573255Simp for (g = grouplist; g; g = g->next) { 13673255Simp grp = getgrnam(g->name); 13773320Simp if (grp != NULL) 13873255Simp g->gid = grp->gr_gid; 13973320Simp else 14073320Simp warnx("%s: no such group", g->name); 14173255Simp } 14273255Simp 1431590Srgrimes makemsg(*argv); 1441590Srgrimes 1451590Srgrimes iov.iov_base = mbuf; 1461590Srgrimes iov.iov_len = mbufsize; 1471590Srgrimes /* NOSTRICT */ 148200156Sed while ((utmp = getutxent()) != NULL) { 149200156Sed if (utmp->ut_type != USER_PROCESS) 1501590Srgrimes continue; 151200156Sed if (ttystat(utmp->ut_line) != 0) 152155875Scognet continue; 15373255Simp if (grouplist) { 15483082Sru ingroup = 0; 155200156Sed pw = getpwnam(utmp->ut_user); 15673255Simp if (!pw) 15773255Simp continue; 15873255Simp for (g = grouplist; g && ingroup == 0; g = g->next) { 15987675Smarkm if (g->gid == (gid_t)-1) 16073255Simp continue; 16173255Simp if (g->gid == pw->pw_gid) 16273255Simp ingroup = 1; 16383082Sru else if ((grp = getgrgid(g->gid)) != NULL) { 16483082Sru for (np = grp->gr_mem; *np; np++) { 165200156Sed if (strcmp(*np, utmp->ut_user) == 0) { 16683082Sru ingroup = 1; 16783082Sru break; 16883082Sru } 16983082Sru } 17083082Sru } 17173255Simp } 17273255Simp if (ingroup == 0) 17373255Simp continue; 17473255Simp } 175200156Sed if ((p = ttymsg(&iov, 1, utmp->ut_line, 60*5)) != NULL) 17628695Scharnier warnx("%s", p); 1771590Srgrimes } 1781590Srgrimes exit(0); 1791590Srgrimes} 1801590Srgrimes 18128695Scharnierstatic void 182201224Sedusage(void) 18328695Scharnier{ 18473320Simp (void)fprintf(stderr, "usage: wall [-g group] [file]\n"); 18528695Scharnier exit(1); 18628695Scharnier} 18728695Scharnier 1881590Srgrimesvoid 18973255Simpmakemsg(char *fname) 1901590Srgrimes{ 19173255Simp int cnt; 19273255Simp unsigned char ch; 1931590Srgrimes struct tm *lt; 1941590Srgrimes struct passwd *pw; 1951590Srgrimes struct stat sbuf; 19629434Sache time_t now; 1971590Srgrimes FILE *fp; 1981590Srgrimes int fd; 19987675Smarkm char *p, hostname[MAXHOSTNAMELEN], lbuf[256], tmpname[64]; 20087675Smarkm const char *tty; 20169231Skris const char *whom; 20276367Skris gid_t egid; 2031590Srgrimes 20469231Skris (void)snprintf(tmpname, sizeof(tmpname), "%s/wall.XXXXXX", _PATH_TMP); 20569231Skris if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+"))) 20669231Skris err(1, "can't open temporary file"); 2071590Srgrimes (void)unlink(tmpname); 2081590Srgrimes 2091590Srgrimes if (!nobanner) { 21069231Skris tty = ttyname(STDERR_FILENO); 21169231Skris if (tty == NULL) 21266557Sn_hibma tty = "no tty"; 21366557Sn_hibma 2141590Srgrimes if (!(whom = getlogin())) 2151590Srgrimes whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 2161590Srgrimes (void)gethostname(hostname, sizeof(hostname)); 2171590Srgrimes (void)time(&now); 2181590Srgrimes lt = localtime(&now); 2191590Srgrimes 2201590Srgrimes /* 2211590Srgrimes * all this stuff is to blank out a square for the message; 2221590Srgrimes * we wrap message lines at column 79, not 80, because some 2231590Srgrimes * terminals wrap after 79, some do not, and we can't tell. 2241590Srgrimes * Which means that we may leave a non-blank character 2251590Srgrimes * in column 80, but that can't be helped. 2261590Srgrimes */ 2271590Srgrimes (void)fprintf(fp, "\r%79s\r\n", " "); 22841717Sdillon (void)snprintf(lbuf, sizeof(lbuf), 22941717Sdillon "Broadcast Message from %s@%s", 2301590Srgrimes whom, hostname); 2311590Srgrimes (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 23269231Skris (void)snprintf(lbuf, sizeof(lbuf), 23366557Sn_hibma " (%s) at %d:%02d %s...", tty, 23463909Sasmodai lt->tm_hour, lt->tm_min, lt->tm_zone); 2351590Srgrimes (void)fprintf(fp, "%-79.79s\r\n", lbuf); 2361590Srgrimes } 2371590Srgrimes (void)fprintf(fp, "%79s\r\n", " "); 2381590Srgrimes 23976367Skris if (fname) { 24076367Skris egid = getegid(); 24176367Skris setegid(getgid()); 24276367Skris if (freopen(fname, "r", stdin) == NULL) 24376367Skris err(1, "can't read %s", fname); 24476367Skris setegid(egid); 24576367Skris } 246175346Sdas while (fgets(lbuf, sizeof(lbuf), stdin)) { 2471590Srgrimes for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 24850776Sdbaker if (ch == '\r') { 249175346Sdas putc('\r', fp); 25050776Sdbaker cnt = 0; 251175346Sdas continue; 252175346Sdas } else if (ch == '\n') { 2531590Srgrimes for (; cnt < 79; ++cnt) 2541590Srgrimes putc(' ', fp); 2551590Srgrimes putc('\r', fp); 2561590Srgrimes putc('\n', fp); 257175346Sdas break; 258175346Sdas } 259175346Sdas if (cnt == 79) { 260175346Sdas putc('\r', fp); 261175346Sdas putc('\n', fp); 2621590Srgrimes cnt = 0; 263175346Sdas } 264175346Sdas if (((ch & 0x80) && ch < 0xA0) || 26529434Sache /* disable upper controls */ 26629434Sache (!isprint(ch) && !isspace(ch) && 26729434Sache ch != '\a' && ch != '\b') 26824729Sache ) { 26924729Sache if (ch & 0x80) { 27024729Sache ch &= 0x7F; 27129434Sache putc('M', fp); 27229434Sache if (++cnt == 79) { 27329434Sache putc('\r', fp); 27429434Sache putc('\n', fp); 27529434Sache cnt = 0; 27629434Sache } 27729434Sache putc('-', fp); 27829434Sache if (++cnt == 79) { 27929434Sache putc('\r', fp); 28029434Sache putc('\n', fp); 28129434Sache cnt = 0; 28229434Sache } 28324729Sache } 28429434Sache if (iscntrl(ch)) { 28529434Sache ch ^= 040; 28629434Sache putc('^', fp); 28729434Sache if (++cnt == 79) { 28829434Sache putc('\r', fp); 28929434Sache putc('\n', fp); 29029434Sache cnt = 0; 29129434Sache } 29229434Sache } 29329434Sache } 294175346Sdas putc(ch, fp); 2951590Srgrimes } 296175346Sdas } 2971590Srgrimes (void)fprintf(fp, "%79s\r\n", " "); 2981590Srgrimes rewind(fp); 2991590Srgrimes 30028695Scharnier if (fstat(fd, &sbuf)) 30169231Skris err(1, "can't stat temporary file"); 3021590Srgrimes mbufsize = sbuf.st_size; 30328695Scharnier if (!(mbuf = malloc((u_int)mbufsize))) 30469231Skris err(1, "out of memory"); 30587675Smarkm if ((int)fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) 30669231Skris err(1, "can't read temporary file"); 3071590Srgrimes (void)close(fd); 3081590Srgrimes} 309