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