1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 /* 28 * University Copyright- Copyright (c) 1982, 1986, 1988 29 * The Regents of the University of California 30 * All Rights Reserved 31 * 32 * University Acknowledgment- Portions of this document are derived from 33 * software developed by the University of California, Berkeley, and its 34 * contributors. 35 */ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 /* 40 * rwall.c 41 * The client rwall program 42 */ 43 44 #include <stdio.h> 45 #include <stdio_ext.h> 46 #include <sys/types.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <thread.h> 50 #include <string.h> 51 #include <rpc/rpc.h> 52 #include <signal.h> 53 #include <pwd.h> 54 #include <rpcsvc/rwall.h> 55 #include <netconfig.h> 56 #include <netdb.h> 57 #include <sys/time.h> 58 #include <sys/resource.h> 59 60 static void init_who(void); 61 static void doall(void); 62 static void doit(char *); 63 static void *do_one(void *); 64 static void usage(void); 65 66 #define PATIENCE 10 67 #define MAX_THREADS 1024 68 69 static mutex_t tty = DEFAULTMUTEX; 70 static char who[9] = "???"; 71 static char *path; 72 static mutex_t thr_mtx = DEFAULTMUTEX; 73 static int thread_count = 8; /* fudge factor for system threads/fds */ 74 static int qflag = 0; /* quiet: we don't care about errors */ 75 76 int 77 main(int argc, char *argv[]) 78 { 79 int msize; 80 char buf[BUFSIZ+1]; 81 int i; 82 char hostname[256]; 83 int hflag; 84 struct rlimit rl; 85 86 if (argc < 2) 87 usage(); 88 89 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 90 rl.rlim_cur = (rl.rlim_max < MAX_THREADS ? 91 rl.rlim_max : MAX_THREADS); 92 (void) setrlimit(RLIMIT_NOFILE, &rl); 93 (void) enable_extended_FILE_stdio(-1, -1); 94 } 95 96 (void) gethostname(hostname, sizeof (hostname)); 97 98 init_who(); 99 100 msize = snprintf(buf, sizeof (buf), "From %s@%s: ", who, hostname); 101 while ((i = getchar()) != EOF) { 102 if (msize >= (sizeof (buf) - 1)) { 103 (void) fprintf(stderr, "Message too long\n"); 104 exit(1); 105 } 106 buf[msize++] = i; 107 } 108 buf[msize] = '\0'; 109 path = buf; 110 hflag = 1; 111 while (argc > 1) { 112 if (argv[1][0] == '-') { 113 switch (argv[1][1]) { 114 case 'h': 115 hflag = 1; 116 break; 117 case 'n': 118 hflag = 0; 119 break; 120 case 'q': 121 qflag = 1; 122 break; 123 default: 124 usage(); 125 break; 126 } 127 argc--; 128 argv++; 129 continue; 130 } 131 if (hflag) { 132 doit(argv[1]); 133 } else { 134 char *machine, *user, *domain; 135 136 (void) setnetgrent(argv[1]); 137 while (getnetgrent(&machine, &user, &domain)) { 138 if (machine) 139 doit(machine); 140 else 141 doall(); 142 } 143 (void) endnetgrent(); 144 } 145 argc--; 146 argv++; 147 } 148 thr_exit(NULL); 149 return (0); 150 } 151 152 static void 153 init_who(void) 154 { 155 char *wp; 156 struct passwd *pwd; 157 158 wp = getlogin(); 159 160 if (wp != NULL) 161 (void) strncpy(who, wp, sizeof (who)); 162 else { 163 pwd = getpwuid(getuid()); 164 if (pwd) 165 (void) strncpy(who, pwd->pw_name, sizeof (who)); 166 } 167 168 } 169 170 /* 171 * Saw a wild card, so do everything 172 */ 173 static void 174 doall(void) 175 { 176 (void) mutex_lock(&tty); 177 (void) fprintf(stderr, "writing to everyone not supported\n"); 178 (void) mutex_unlock(&tty); 179 } 180 181 /* 182 * Fire off a detached thread for each host in the list, if the thread 183 * create fails simply run synchronously. 184 */ 185 static void 186 doit(char *hostname) 187 { 188 thread_t tid; 189 char *thread_hostname; 190 191 (void) mutex_lock(&thr_mtx); 192 while (thread_count >= MAX_THREADS) { 193 (void) mutex_unlock(&thr_mtx); 194 (void) sleep(PATIENCE/2); 195 (void) mutex_lock(&thr_mtx); 196 } 197 198 thread_count++; 199 (void) mutex_unlock(&thr_mtx); 200 201 thread_hostname = strdup(hostname); 202 if (thread_hostname == (char *)NULL) { 203 (void) mutex_lock(&tty); 204 (void) fprintf(stderr, "Ran out of memory\n"); 205 (void) mutex_unlock(&tty); 206 exit(1); 207 } 208 209 if (thr_create(NULL, 0, do_one, thread_hostname, 210 THR_DETACHED, &tid) != 0) { 211 (void) do_one(thread_hostname); 212 } 213 } 214 215 static void * 216 do_one(void *arg) 217 { 218 char *hostname = arg; 219 CLIENT *clnt; 220 struct timeval tp; 221 void *vp = NULL; 222 223 #ifdef DEBUG 224 (void) mutex_lock(&tty); 225 (void) fprintf(stderr, "sending message to %s\n%s\n", hostname, path); 226 (void) mutex_unlock(&tty); 227 return (0); 228 #endif 229 tp.tv_sec = PATIENCE; 230 tp.tv_usec = 0; 231 clnt = clnt_create_timed( 232 hostname, WALLPROG, WALLVERS, "datagram_v", &tp); 233 if (clnt == NULL) { 234 if (!qflag) { 235 (void) mutex_lock(&tty); 236 (void) fprintf(stderr, "rwall: Can't send to %s\n", 237 hostname); 238 clnt_pcreateerror(hostname); 239 (void) mutex_unlock(&tty); 240 } 241 goto errout; 242 } 243 244 if (wallproc_wall_1(&path, vp, clnt) != RPC_SUCCESS) { 245 if (!qflag) { 246 (void) mutex_lock(&tty); 247 clnt_perror(clnt, hostname); 248 (void) mutex_unlock(&tty); 249 } 250 } 251 clnt_destroy(clnt); 252 errout: 253 (void) mutex_lock(&thr_mtx); 254 thread_count--; 255 (void) mutex_unlock(&thr_mtx); 256 free(hostname); 257 return (0); 258 } 259 260 static void 261 usage(void) 262 { 263 (void) fprintf(stderr, 264 "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n"); 265 exit(1); 266 }