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