11159Sbill /* 2*35531Sbostic * Copyright (c) 1988 Regents of the University of California. 3*35531Sbostic * All rights reserved. 4*35531Sbostic * 5*35531Sbostic * Redistribution and use in source and binary forms are permitted 6*35531Sbostic * provided that the above copyright notice and this paragraph are 7*35531Sbostic * duplicated in all such forms and that any documentation, 8*35531Sbostic * advertising materials, and other materials related to such 9*35531Sbostic * distribution and use acknowledge that the software was developed 10*35531Sbostic * by the University of California, Berkeley. The name of the 11*35531Sbostic * University may not be used to endorse or promote products derived 12*35531Sbostic * from this software without specific prior written permission. 13*35531Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35531Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35531Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1619909Sdist */ 1719909Sdist 1819909Sdist #ifndef lint 1919909Sdist char copyright[] = 20*35531Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 2119909Sdist All rights reserved.\n"; 22*35531Sbostic #endif /* not lint */ 2319909Sdist 2419909Sdist #ifndef lint 25*35531Sbostic static char sccsid[] = "@(#)wall.c 5.5 (Berkeley) 09/18/88"; 26*35531Sbostic #endif /* not lint */ 2719909Sdist 2819909Sdist /* 291159Sbill * This program is not related to David Wall, whose Stanford Ph.D. thesis 301159Sbill * is entitled "Mechanisms for Broadcast and Selective Broadcast". 311159Sbill */ 321159Sbill 33*35531Sbostic #include <sys/param.h> 34*35531Sbostic #include <sys/time.h> 35*35531Sbostic #include <sys/signal.h> 36*35531Sbostic #include <sys/stat.h> 37*35531Sbostic #include <sys/dir.h> 38*35531Sbostic #include <fcntl.h> 391159Sbill #include <utmp.h> 40*35531Sbostic #include <pwd.h> 4116256Sralph #include <errno.h> 42*35531Sbostic #include <stdio.h> 4316256Sralph 44*35531Sbostic #define IGNOREUSER "sleeper" 45*35531Sbostic #define UTMP "/etc/utmp" 461159Sbill 47*35531Sbostic static int mbufsize; 48*35531Sbostic static char *mbuf; 491159Sbill 50*35531Sbostic /* ARGSUSED */ 511159Sbill main(argc, argv) 52*35531Sbostic int argc; 53*35531Sbostic char **argv; 541159Sbill { 55*35531Sbostic struct utmp utmp; 56*35531Sbostic FILE *fp; 571159Sbill 58*35531Sbostic if (argc > 2) { 59*35531Sbostic fprintf(stderr, "usage: wall [file]\n"); 601159Sbill exit(1); 611159Sbill } 62*35531Sbostic makemsg(argv); 63*35531Sbostic 64*35531Sbostic if (!(fp = fopen(UTMP, "r"))) { 65*35531Sbostic fprintf(stderr, "wall: cannot read /etc/utmp.\n"); 66*35531Sbostic exit(1); 671159Sbill } 68*35531Sbostic /* NOSTRICT */ 69*35531Sbostic while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) { 70*35531Sbostic if (!utmp.ut_name[0] || 71*35531Sbostic !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) 721159Sbill continue; 73*35531Sbostic sendmsg(utmp.ut_line); 741159Sbill } 751159Sbill exit(0); 761159Sbill } 771159Sbill 78*35531Sbostic makemsg(argv) 79*35531Sbostic char **argv; 801159Sbill { 81*35531Sbostic register int ch, cnt; 82*35531Sbostic struct tm *lt; 83*35531Sbostic struct passwd *pw, *getpwuid(); 84*35531Sbostic struct stat sbuf; 85*35531Sbostic time_t now, time(); 86*35531Sbostic FILE *fp; 87*35531Sbostic int fd; 88*35531Sbostic char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15]; 89*35531Sbostic char *getlogin(), *malloc(), *strcpy(), *ttyname(); 901159Sbill 91*35531Sbostic (void)strcpy(tmpname, "/tmp/wall.XXX"); 92*35531Sbostic if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) { 93*35531Sbostic fprintf(stderr, "wall: can't open temporary file.\n"); 94*35531Sbostic exit(1); 95*35531Sbostic } 96*35531Sbostic (void)unlink(tmpname); 9716256Sralph 98*35531Sbostic if (!(whom = getlogin())) 99*35531Sbostic whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 100*35531Sbostic (void)gethostname(hostname, sizeof(hostname)); 101*35531Sbostic (void)time(&now); 102*35531Sbostic lt = localtime(&now); 103*35531Sbostic 104*35531Sbostic /* 105*35531Sbostic * all this stuff is to blank out a square for the message; we 106*35531Sbostic * limit message lines to 75 characters, and blank out to 79. 107*35531Sbostic * Not 80 'cause some terminals do weird stuff then. 108*35531Sbostic */ 109*35531Sbostic fprintf(fp, "\r%79s\r\n", " "); 110*35531Sbostic (void)sprintf(lbuf, "Broadcast Message from %s@%s", whom, hostname); 111*35531Sbostic fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 112*35531Sbostic (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2), 113*35531Sbostic lt->tm_hour, lt->tm_min); 114*35531Sbostic fprintf(fp, "%-79.79s\r\n", lbuf); 115*35531Sbostic fprintf(fp, "%79s\r\n", " "); 116*35531Sbostic 117*35531Sbostic if (*++argv && !(freopen(*argv, "r", stdin))) { 118*35531Sbostic fprintf(stderr, "wall: can't read %s.\n", *argv); 119*35531Sbostic exit(1); 12016256Sralph } 121*35531Sbostic while (fgets(lbuf, sizeof(lbuf), stdin)) 122*35531Sbostic for (cnt = 0, p = lbuf; ch = *p; ++p, ++cnt) 123*35531Sbostic if (cnt == 75 || ch == '\n') { 124*35531Sbostic for (; cnt < 79; ++cnt) 125*35531Sbostic putc(' ', fp); 126*35531Sbostic putc('\r', fp); 127*35531Sbostic putc('\n', fp); 128*35531Sbostic cnt = 1; 129*35531Sbostic } else 130*35531Sbostic putc(ch, fp); 131*35531Sbostic fprintf(fp, "%79s\r\n", " "); 132*35531Sbostic rewind(fp); 133*35531Sbostic 134*35531Sbostic if (fstat(fd, &sbuf)) { 135*35531Sbostic fprintf(stderr, "wall: can't stat temporary file.\n"); 136*35531Sbostic exit(1); 13716256Sralph } 138*35531Sbostic mbufsize = sbuf.st_size; 139*35531Sbostic if (!(mbuf = malloc((u_int)mbufsize))) { 140*35531Sbostic fprintf(stderr, "wall: out of memory.\n"); 141*35531Sbostic exit(1); 14216256Sralph } 143*35531Sbostic (void)fread(mbuf, sizeof(*mbuf), mbufsize, fp); 144*35531Sbostic (void)close(fd); 145*35531Sbostic } 146*35531Sbostic 147*35531Sbostic sendmsg(line) 148*35531Sbostic char *line; 149*35531Sbostic { 150*35531Sbostic extern int errno; 151*35531Sbostic static char device[MAXNAMLEN] = "/dev/"; 152*35531Sbostic register int fd, flags, nread; 153*35531Sbostic char *lp, *strcpy(); 154*35531Sbostic 155*35531Sbostic (void)strcpy(device + 5, line); 156*35531Sbostic if ((fd = open(device, O_WRONLY, 0)) < 0) { 157*35531Sbostic fprintf(stderr, "wall: %s: ", device); 158*35531Sbostic perror((char *)NULL); 15916256Sralph } 160*35531Sbostic flags = fcntl(fd, F_GETFL, 0); 161*35531Sbostic if (!(flags & FNDELAY)) { 162*35531Sbostic /* NDELAY bit not set; if can't set, fork instead */ 163*35531Sbostic if (fcntl(fd, F_SETFL, flags|FNDELAY) == -1) { 164*35531Sbostic flags = 0; 165*35531Sbostic goto forkit; 1663176Swnj } 1671159Sbill } 168*35531Sbostic else 169*35531Sbostic flags = 0; 170*35531Sbostic lp = mbuf; 171*35531Sbostic while ((nread = write(fd, lp, mbufsize)) != mbufsize) { 172*35531Sbostic if (mbufsize > 0) { 173*35531Sbostic mbufsize -= nread; 174*35531Sbostic lp += nread; 175*35531Sbostic } else if (errno == EWOULDBLOCK) { 176*35531Sbostic /* child resets FNDELAY if necessary; parent leaves */ 177*35531Sbostic forkit: if (fork()) { 178*35531Sbostic (void)close(fd); 179*35531Sbostic return; 180*35531Sbostic } 181*35531Sbostic if (flags) 182*35531Sbostic (void)fcntl(fd, F_SETFL, flags); 183*35531Sbostic /* wait 5 minutes and then quit */ 184*35531Sbostic (void)alarm((u_int)(60 * 5)); 185*35531Sbostic (void)write(fd, mbuf, mbufsize); 186*35531Sbostic exit(0); 187*35531Sbostic } else { 188*35531Sbostic fprintf(stderr, "wall: %s: ", device); 189*35531Sbostic perror((char *)NULL); 190*35531Sbostic break; 191*35531Sbostic } 192*35531Sbostic } 193*35531Sbostic /* write was successful, or error != EWOULDBLOCK; cleanup */ 194*35531Sbostic if (flags) 195*35531Sbostic (void)fcntl(fd, F_SETFL, flags); 196*35531Sbostic (void)close(fd); 1971159Sbill } 198