xref: /titanic_52/usr/src/cmd/wall/wall.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * Copyright 1988-2003 Sun Microsystems, Inc.  All rights reserved.
29*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <signal.h>
35*7c478bd9Sstevel@tonic-gate #include <stdio.h>
36*7c478bd9Sstevel@tonic-gate #include <grp.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <unistd.h>
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <ctype.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
43*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
45*7c478bd9Sstevel@tonic-gate #include <dirent.h>
46*7c478bd9Sstevel@tonic-gate #include <pwd.h>
47*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
48*7c478bd9Sstevel@tonic-gate #include <time.h>
49*7c478bd9Sstevel@tonic-gate #include <errno.h>
50*7c478bd9Sstevel@tonic-gate #include <locale.h>
51*7c478bd9Sstevel@tonic-gate #include <syslog.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
53*7c478bd9Sstevel@tonic-gate #include <limits.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * utmpx defines wider fields for user and line.  For compatibility of output,
57*7c478bd9Sstevel@tonic-gate  * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
58*7c478bd9Sstevel@tonic-gate  * to use the full lengths.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate #ifndef UTMPX_NAMELEN
61*7c478bd9Sstevel@tonic-gate /* XXX - utmp -fix name length */
62*7c478bd9Sstevel@tonic-gate #define	NMAX	(_POSIX_LOGIN_NAME_MAX - 1)
63*7c478bd9Sstevel@tonic-gate #define	LMAX	12
64*7c478bd9Sstevel@tonic-gate #else /* UTMPX_NAMELEN */
65*7c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (((struct utmpx *)0)->ut_user)
66*7c478bd9Sstevel@tonic-gate #define	LMAX	(sizeof (((struct utmpx *)0)->ut_line)
67*7c478bd9Sstevel@tonic-gate #endif /* UTMPX_NAMELEN */
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static char	mesg[3000];
70*7c478bd9Sstevel@tonic-gate static char	*infile;
71*7c478bd9Sstevel@tonic-gate static int	gflag;
72*7c478bd9Sstevel@tonic-gate static struct	group *pgrp;
73*7c478bd9Sstevel@tonic-gate static char	*grpname;
74*7c478bd9Sstevel@tonic-gate static char	line[MAXNAMLEN+1] = "???";
75*7c478bd9Sstevel@tonic-gate static char	systm[MAXNAMLEN+1];
76*7c478bd9Sstevel@tonic-gate static time_t	tloc;
77*7c478bd9Sstevel@tonic-gate static struct	utsname utsn;
78*7c478bd9Sstevel@tonic-gate static char	who[9]	= "???";
79*7c478bd9Sstevel@tonic-gate static char	time_buf[50];
80*7c478bd9Sstevel@tonic-gate #define	DATE_FMT	"%a %b %e %H:%M:%S"
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate static void sendmes(struct utmpx *);
83*7c478bd9Sstevel@tonic-gate static int chkgrp(char *);
84*7c478bd9Sstevel@tonic-gate static char *copy_str_till(char *, char *, char, int);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate int
87*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate 	int	i = 0;
90*7c478bd9Sstevel@tonic-gate 	struct utmpx *p;
91*7c478bd9Sstevel@tonic-gate 	FILE	*f;
92*7c478bd9Sstevel@tonic-gate 	char	*ptr, *start;
93*7c478bd9Sstevel@tonic-gate 	struct	passwd *pwd;
94*7c478bd9Sstevel@tonic-gate 	char	*term_name;
95*7c478bd9Sstevel@tonic-gate 	int	c;
96*7c478bd9Sstevel@tonic-gate 	int	aflag = 0;
97*7c478bd9Sstevel@tonic-gate 	int	errflg = 0;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "g:a")) != EOF)
102*7c478bd9Sstevel@tonic-gate 		switch (c) {
103*7c478bd9Sstevel@tonic-gate 		case 'a':
104*7c478bd9Sstevel@tonic-gate 			aflag++;
105*7c478bd9Sstevel@tonic-gate 			break;
106*7c478bd9Sstevel@tonic-gate 		case 'g':
107*7c478bd9Sstevel@tonic-gate 			if (gflag) {
108*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
109*7c478bd9Sstevel@tonic-gate 				    "Only one group allowed\n");
110*7c478bd9Sstevel@tonic-gate 				exit(1);
111*7c478bd9Sstevel@tonic-gate 			}
112*7c478bd9Sstevel@tonic-gate 			if ((pgrp = getgrnam(grpname = optarg)) == NULL) {
113*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "Unknown group %s\n",
114*7c478bd9Sstevel@tonic-gate 				    grpname);
115*7c478bd9Sstevel@tonic-gate 				exit(1);
116*7c478bd9Sstevel@tonic-gate 			}
117*7c478bd9Sstevel@tonic-gate 			gflag++;
118*7c478bd9Sstevel@tonic-gate 			break;
119*7c478bd9Sstevel@tonic-gate 		case '?':
120*7c478bd9Sstevel@tonic-gate 			errflg++;
121*7c478bd9Sstevel@tonic-gate 			break;
122*7c478bd9Sstevel@tonic-gate 		}
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	if (errflg) {
125*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
126*7c478bd9Sstevel@tonic-gate 		    "Usage: wall [-a] [-g group] [files...]\n");
127*7c478bd9Sstevel@tonic-gate 		return (1);
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	if (optind < argc)
131*7c478bd9Sstevel@tonic-gate 		infile = argv[optind];
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if (uname(&utsn) == -1) {
134*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "wall: uname() failed, %s\n",
135*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
136*7c478bd9Sstevel@tonic-gate 		exit(2);
137*7c478bd9Sstevel@tonic-gate 	}
138*7c478bd9Sstevel@tonic-gate 	(void) strcpy(systm, utsn.nodename);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/*
141*7c478bd9Sstevel@tonic-gate 	 * Get the name of the terminal wall is running from.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if ((term_name = ttyname(fileno(stderr))) != NULL) {
145*7c478bd9Sstevel@tonic-gate 		/*
146*7c478bd9Sstevel@tonic-gate 		 * skip the leading "/dev/" in term_name
147*7c478bd9Sstevel@tonic-gate 		 */
148*7c478bd9Sstevel@tonic-gate 		(void) strncpy(line, &term_name[5], sizeof (line) - 1);
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (who[0] == '?') {
152*7c478bd9Sstevel@tonic-gate 		if (pwd = getpwuid(getuid()))
153*7c478bd9Sstevel@tonic-gate 			(void) strncpy(&who[0], pwd->pw_name, sizeof (who));
154*7c478bd9Sstevel@tonic-gate 	}
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	f = stdin;
157*7c478bd9Sstevel@tonic-gate 	if (infile) {
158*7c478bd9Sstevel@tonic-gate 		f = fopen(infile, "r");
159*7c478bd9Sstevel@tonic-gate 		if (f == NULL) {
160*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "Cannot open %s\n", infile);
161*7c478bd9Sstevel@tonic-gate 			exit(1);
162*7c478bd9Sstevel@tonic-gate 		}
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	start = &mesg[0];
166*7c478bd9Sstevel@tonic-gate 	ptr = start;
167*7c478bd9Sstevel@tonic-gate 	while ((ptr - start) < 3000) {
168*7c478bd9Sstevel@tonic-gate 		size_t n;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 		if (fgets(ptr, &mesg[sizeof (mesg)] - ptr, f) == NULL)
171*7c478bd9Sstevel@tonic-gate 			break;
172*7c478bd9Sstevel@tonic-gate 		if ((n = strlen(ptr)) == 0)
173*7c478bd9Sstevel@tonic-gate 			break;
174*7c478bd9Sstevel@tonic-gate 		ptr += n;
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 	(void) fclose(f);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	/*
179*7c478bd9Sstevel@tonic-gate 	 * If the request is from the rwall daemon then use the caller's
180*7c478bd9Sstevel@tonic-gate 	 * name and host.  We determine this if all of the following is true:
181*7c478bd9Sstevel@tonic-gate 	 *	1) First 5 characters are "From "
182*7c478bd9Sstevel@tonic-gate 	 *	2) Next non-white characters are of the form "name@host:"
183*7c478bd9Sstevel@tonic-gate 	 */
184*7c478bd9Sstevel@tonic-gate 	if (strcmp(line, "???") == 0) {
185*7c478bd9Sstevel@tonic-gate 		char rwho[MAXNAMLEN+1];
186*7c478bd9Sstevel@tonic-gate 		char rsystm[MAXNAMLEN+1];
187*7c478bd9Sstevel@tonic-gate 		char *cp;
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 		if (strncmp(mesg, "From ", 5) == 0) {
190*7c478bd9Sstevel@tonic-gate 			cp = &mesg[5];
191*7c478bd9Sstevel@tonic-gate 			cp = copy_str_till(rwho, cp, '@', MAXNAMLEN + 1);
192*7c478bd9Sstevel@tonic-gate 			if (rwho[0] != '\0') {
193*7c478bd9Sstevel@tonic-gate 				cp = copy_str_till(rsystm, ++cp, ':',
194*7c478bd9Sstevel@tonic-gate 				    MAXNAMLEN + 1);
195*7c478bd9Sstevel@tonic-gate 				if (rsystm[0] != '\0') {
196*7c478bd9Sstevel@tonic-gate 					(void) strcpy(systm, rsystm);
197*7c478bd9Sstevel@tonic-gate 					(void) strncpy(rwho, who, 9);
198*7c478bd9Sstevel@tonic-gate 					(void) strcpy(line, "rpc.rwalld");
199*7c478bd9Sstevel@tonic-gate 				}
200*7c478bd9Sstevel@tonic-gate 			}
201*7c478bd9Sstevel@tonic-gate 		}
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 	(void) time(&tloc);
204*7c478bd9Sstevel@tonic-gate 	(void) strftime(time_buf, sizeof (time_buf),
205*7c478bd9Sstevel@tonic-gate 			    DATE_FMT, localtime(&tloc));
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	setutxent();
208*7c478bd9Sstevel@tonic-gate 	while ((p = getutxent()) != NULL) {
209*7c478bd9Sstevel@tonic-gate 		if (p->ut_type != USER_PROCESS)
210*7c478bd9Sstevel@tonic-gate 			continue;
211*7c478bd9Sstevel@tonic-gate 		/*
212*7c478bd9Sstevel@tonic-gate 		 * if (-a option OR NOT pty window login), send the message
213*7c478bd9Sstevel@tonic-gate 		 */
214*7c478bd9Sstevel@tonic-gate 		if (aflag || !nonuser(*p))
215*7c478bd9Sstevel@tonic-gate 			sendmes(p);
216*7c478bd9Sstevel@tonic-gate 	}
217*7c478bd9Sstevel@tonic-gate 	endutxent();
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	(void) alarm(60);
220*7c478bd9Sstevel@tonic-gate 	do {
221*7c478bd9Sstevel@tonic-gate 		i = (int)wait((int *)0);
222*7c478bd9Sstevel@tonic-gate 	} while (i != -1 || errno != ECHILD);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	return (0);
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate /*
228*7c478bd9Sstevel@tonic-gate  * Copy src to destination upto but not including the delim.
229*7c478bd9Sstevel@tonic-gate  * Leave dst empty if delim not found or whitespace encountered.
230*7c478bd9Sstevel@tonic-gate  * Return pointer to next character (delim, whitespace, or '\0')
231*7c478bd9Sstevel@tonic-gate  */
232*7c478bd9Sstevel@tonic-gate static char *
233*7c478bd9Sstevel@tonic-gate copy_str_till(char *dst, char *src, char delim, int len)
234*7c478bd9Sstevel@tonic-gate {
235*7c478bd9Sstevel@tonic-gate 	int i = 0;
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	while (*src != '\0' && i < len) {
238*7c478bd9Sstevel@tonic-gate 		if (isspace(*src)) {
239*7c478bd9Sstevel@tonic-gate 			dst[0] = '\0';
240*7c478bd9Sstevel@tonic-gate 			return (src);
241*7c478bd9Sstevel@tonic-gate 		}
242*7c478bd9Sstevel@tonic-gate 		if (*src == delim) {
243*7c478bd9Sstevel@tonic-gate 			dst[i] = '\0';
244*7c478bd9Sstevel@tonic-gate 			return (src);
245*7c478bd9Sstevel@tonic-gate 		}
246*7c478bd9Sstevel@tonic-gate 		dst[i++] = *src++;
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 	dst[0] = '\0';
249*7c478bd9Sstevel@tonic-gate 	return (src);
250*7c478bd9Sstevel@tonic-gate }
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate /*
253*7c478bd9Sstevel@tonic-gate  * Note to future maintainers: with the change of wall to use the
254*7c478bd9Sstevel@tonic-gate  * getutxent() API, the forked children (created by this function)
255*7c478bd9Sstevel@tonic-gate  * must call _exit as opposed to exit. This is necessary to avoid
256*7c478bd9Sstevel@tonic-gate  * unwanted fflushing of getutxent's stdio stream (caused by atexit
257*7c478bd9Sstevel@tonic-gate  * processing).
258*7c478bd9Sstevel@tonic-gate  */
259*7c478bd9Sstevel@tonic-gate static void
260*7c478bd9Sstevel@tonic-gate sendmes(struct utmpx *p)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	int i;
263*7c478bd9Sstevel@tonic-gate 	char *s;
264*7c478bd9Sstevel@tonic-gate 	static char device[LMAX + 6];
265*7c478bd9Sstevel@tonic-gate 	char *bp;
266*7c478bd9Sstevel@tonic-gate 	int ibp;
267*7c478bd9Sstevel@tonic-gate 	FILE *f;
268*7c478bd9Sstevel@tonic-gate 	int fd;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	if (gflag)
271*7c478bd9Sstevel@tonic-gate 		if (!chkgrp(p->ut_user))
272*7c478bd9Sstevel@tonic-gate 			return;
273*7c478bd9Sstevel@tonic-gate 	while ((i = (int)fork()) == -1) {
274*7c478bd9Sstevel@tonic-gate 		(void) alarm(60);
275*7c478bd9Sstevel@tonic-gate 		(void) wait((int *)0);
276*7c478bd9Sstevel@tonic-gate 		(void) alarm(0);
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	if (i)
280*7c478bd9Sstevel@tonic-gate 		return;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGHUP, SIG_IGN);
283*7c478bd9Sstevel@tonic-gate 	(void) alarm(60);
284*7c478bd9Sstevel@tonic-gate 	s = &device[0];
285*7c478bd9Sstevel@tonic-gate 	(void) snprintf(s, sizeof (device), "/dev/%.*s", LMAX, p->ut_line);
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/* check if the device is really a tty */
288*7c478bd9Sstevel@tonic-gate 	if ((fd = open(s, O_WRONLY|O_NOCTTY|O_NONBLOCK)) == -1) {
289*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot send to %.*s on %s\n",
290*7c478bd9Sstevel@tonic-gate 		    NMAX, p->ut_user, s);
291*7c478bd9Sstevel@tonic-gate 		perror("open");
292*7c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
293*7c478bd9Sstevel@tonic-gate 		_exit(1);
294*7c478bd9Sstevel@tonic-gate 	} else {
295*7c478bd9Sstevel@tonic-gate 		if (!isatty(fd)) {
296*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
297*7c478bd9Sstevel@tonic-gate 			    "Cannot send to device %.*s %s\n",
298*7c478bd9Sstevel@tonic-gate 			    LMAX, p->ut_line,
299*7c478bd9Sstevel@tonic-gate 			    "because it's not a tty");
300*7c478bd9Sstevel@tonic-gate 			openlog("wall", 0, LOG_AUTH);
301*7c478bd9Sstevel@tonic-gate 			syslog(LOG_CRIT, "%.*s in utmpx is not a tty\n",
302*7c478bd9Sstevel@tonic-gate 			    LMAX, p->ut_line);
303*7c478bd9Sstevel@tonic-gate 			closelog();
304*7c478bd9Sstevel@tonic-gate 			(void) fflush(stderr);
305*7c478bd9Sstevel@tonic-gate 			_exit(1);
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
309*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
310*7c478bd9Sstevel@tonic-gate 	f = fopen("wall.debug", "a");
311*7c478bd9Sstevel@tonic-gate #else
312*7c478bd9Sstevel@tonic-gate 	f = fdopen(fd, "w");
313*7c478bd9Sstevel@tonic-gate #endif
314*7c478bd9Sstevel@tonic-gate 	if (f == NULL) {
315*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot send to %-.*s on %s\n",
316*7c478bd9Sstevel@tonic-gate 		    NMAX, &p->ut_user[0], s);
317*7c478bd9Sstevel@tonic-gate 		perror("open");
318*7c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
319*7c478bd9Sstevel@tonic-gate 		_exit(1);
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 	(void) fprintf(f,
322*7c478bd9Sstevel@tonic-gate 	    "\07\07\07Broadcast Message from %s (%s) on %s %19.19s",
323*7c478bd9Sstevel@tonic-gate 	    who, line, systm, time_buf);
324*7c478bd9Sstevel@tonic-gate 	if (gflag)
325*7c478bd9Sstevel@tonic-gate 		(void) fprintf(f, " to group %s", grpname);
326*7c478bd9Sstevel@tonic-gate 	(void) fprintf(f, "...\n");
327*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
328*7c478bd9Sstevel@tonic-gate 	(void) fprintf(f, "DEBUG: To %.8s on %s\n", p->ut_user, s);
329*7c478bd9Sstevel@tonic-gate #endif
330*7c478bd9Sstevel@tonic-gate 	i = strlen(mesg);
331*7c478bd9Sstevel@tonic-gate 	for (bp = mesg; --i >= 0; bp++) {
332*7c478bd9Sstevel@tonic-gate 		ibp = (unsigned int)((unsigned char) *bp);
333*7c478bd9Sstevel@tonic-gate 		if (*bp == '\n')
334*7c478bd9Sstevel@tonic-gate 			(void) putc('\r', f);
335*7c478bd9Sstevel@tonic-gate 		if (isprint(ibp) || *bp == '\r' || *bp == '\013' ||
336*7c478bd9Sstevel@tonic-gate 		    *bp == ' ' || *bp == '\t' || *bp == '\n' || *bp == '\007') {
337*7c478bd9Sstevel@tonic-gate 			(void) putc(*bp, f);
338*7c478bd9Sstevel@tonic-gate 		} else {
339*7c478bd9Sstevel@tonic-gate 			if (!isascii(*bp)) {
340*7c478bd9Sstevel@tonic-gate 				(void) fputs("M-", f);
341*7c478bd9Sstevel@tonic-gate 				*bp = toascii(*bp);
342*7c478bd9Sstevel@tonic-gate 			}
343*7c478bd9Sstevel@tonic-gate 			if (iscntrl(*bp)) {
344*7c478bd9Sstevel@tonic-gate 				(void) putc('^', f);
345*7c478bd9Sstevel@tonic-gate 				(void) putc(*bp + 0100, f);
346*7c478bd9Sstevel@tonic-gate 			}
347*7c478bd9Sstevel@tonic-gate 			else
348*7c478bd9Sstevel@tonic-gate 				(void) putc(*bp, f);
349*7c478bd9Sstevel@tonic-gate 		}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		if (*bp == '\n')
352*7c478bd9Sstevel@tonic-gate 			(void) fflush(f);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		if (ferror(f) || feof(f)) {
355*7c478bd9Sstevel@tonic-gate 			(void) printf("\n\007Write failed\n");
356*7c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
357*7c478bd9Sstevel@tonic-gate 			_exit(1);
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	(void) fclose(f);
361*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
362*7c478bd9Sstevel@tonic-gate 	_exit(0);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate static int
367*7c478bd9Sstevel@tonic-gate chkgrp(char *name)
368*7c478bd9Sstevel@tonic-gate {
369*7c478bd9Sstevel@tonic-gate 	int i;
370*7c478bd9Sstevel@tonic-gate 	char *p;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	for (i = 0; pgrp->gr_mem[i] && pgrp->gr_mem[i][0]; i++) {
373*7c478bd9Sstevel@tonic-gate 		for (p = name; *p && *p != ' '; p++);
374*7c478bd9Sstevel@tonic-gate 		*p = 0;
375*7c478bd9Sstevel@tonic-gate 		if (strncmp(name, pgrp->gr_mem[i], 8) == 0)
376*7c478bd9Sstevel@tonic-gate 			return (1);
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	return (0);
380*7c478bd9Sstevel@tonic-gate }
381