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 /* 38 * rwall.c 39 * The client rwall program 40 */ 41 42 #include <stdio.h> 43 #include <stdio_ext.h> 44 #include <sys/types.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include <thread.h> 48 #include <string.h> 49 #include <rpc/rpc.h> 50 #include <signal.h> 51 #include <pwd.h> 52 #include <rpcsvc/rwall.h> 53 #include <netconfig.h> 54 #include <netdb.h> 55 #include <sys/time.h> 56 #include <sys/resource.h> 57 58 static void init_who(void); 59 static void doall(void); 60 static void doit(char *); 61 static void *do_one(void *); 62 static void usage(void); 63 64 #define PATIENCE 10 65 #define MAX_THREADS 1024 66 67 static mutex_t tty = DEFAULTMUTEX; 68 static char who[9] = "???"; 69 static char *path; 70 static mutex_t thr_mtx = DEFAULTMUTEX; 71 static int thread_count = 8; /* fudge factor for system threads/fds */ 72 static int qflag = 0; /* quiet: we don't care about errors */ 73 74 int 75 main(int argc, char *argv[]) 76 { 77 int msize; 78 char buf[BUFSIZ+1]; 79 int i; 80 char hostname[256]; 81 int hflag; 82 struct rlimit rl; 83 84 if (argc < 2) 85 usage(); 86 87 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 88 rl.rlim_cur = (rl.rlim_max < MAX_THREADS ? 89 rl.rlim_max : MAX_THREADS); 90 (void) setrlimit(RLIMIT_NOFILE, &rl); 91 (void) enable_extended_FILE_stdio(-1, -1); 92 } 93 94 (void) gethostname(hostname, sizeof (hostname)); 95 96 init_who(); 97 98 msize = snprintf(buf, sizeof (buf), "From %s@%s: ", who, hostname); 99 while ((i = getchar()) != EOF) { 100 if (msize >= (sizeof (buf) - 1)) { 101 (void) fprintf(stderr, "Message too long\n"); 102 exit(1); 103 } 104 buf[msize++] = i; 105 } 106 buf[msize] = '\0'; 107 path = buf; 108 hflag = 1; 109 while (argc > 1) { 110 if (argv[1][0] == '-') { 111 switch (argv[1][1]) { 112 case 'h': 113 hflag = 1; 114 break; 115 case 'n': 116 hflag = 0; 117 break; 118 case 'q': 119 qflag = 1; 120 break; 121 default: 122 usage(); 123 break; 124 } 125 argc--; 126 argv++; 127 continue; 128 } 129 if (hflag) { 130 doit(argv[1]); 131 } else { 132 char *machine, *user, *domain; 133 134 (void) setnetgrent(argv[1]); 135 while (getnetgrent(&machine, &user, &domain)) { 136 if (machine) 137 doit(machine); 138 else 139 doall(); 140 } 141 (void) endnetgrent(); 142 } 143 argc--; 144 argv++; 145 } 146 thr_exit(NULL); 147 return (0); 148 } 149 150 static void 151 init_who(void) 152 { 153 char *wp; 154 struct passwd *pwd; 155 156 wp = getlogin(); 157 158 if (wp != NULL) 159 (void) strncpy(who, wp, sizeof (who)); 160 else { 161 pwd = getpwuid(getuid()); 162 if (pwd) 163 (void) strncpy(who, pwd->pw_name, sizeof (who)); 164 } 165 166 } 167 168 /* 169 * Saw a wild card, so do everything 170 */ 171 static void 172 doall(void) 173 { 174 (void) mutex_lock(&tty); 175 (void) fprintf(stderr, "writing to everyone not supported\n"); 176 (void) mutex_unlock(&tty); 177 } 178 179 /* 180 * Fire off a detached thread for each host in the list, if the thread 181 * create fails simply run synchronously. 182 */ 183 static void 184 doit(char *hostname) 185 { 186 thread_t tid; 187 char *thread_hostname; 188 189 (void) mutex_lock(&thr_mtx); 190 while (thread_count >= MAX_THREADS) { 191 (void) mutex_unlock(&thr_mtx); 192 (void) sleep(PATIENCE/2); 193 (void) mutex_lock(&thr_mtx); 194 } 195 196 thread_count++; 197 (void) mutex_unlock(&thr_mtx); 198 199 thread_hostname = strdup(hostname); 200 if (thread_hostname == (char *)NULL) { 201 (void) mutex_lock(&tty); 202 (void) fprintf(stderr, "Ran out of memory\n"); 203 (void) mutex_unlock(&tty); 204 exit(1); 205 } 206 207 if (thr_create(NULL, 0, do_one, thread_hostname, 208 THR_DETACHED, &tid) != 0) { 209 (void) do_one(thread_hostname); 210 } 211 } 212 213 static void * 214 do_one(void *arg) 215 { 216 char *hostname = arg; 217 CLIENT *clnt; 218 struct timeval tp; 219 void *vp = NULL; 220 221 #ifdef DEBUG 222 (void) mutex_lock(&tty); 223 (void) fprintf(stderr, "sending message to %s\n%s\n", hostname, path); 224 (void) mutex_unlock(&tty); 225 return (0); 226 #endif 227 tp.tv_sec = PATIENCE; 228 tp.tv_usec = 0; 229 clnt = clnt_create_timed( 230 hostname, WALLPROG, WALLVERS, "datagram_v", &tp); 231 if (clnt == NULL) { 232 if (!qflag) { 233 (void) mutex_lock(&tty); 234 (void) fprintf(stderr, "rwall: Can't send to %s\n", 235 hostname); 236 clnt_pcreateerror(hostname); 237 (void) mutex_unlock(&tty); 238 } 239 goto errout; 240 } 241 242 if (wallproc_wall_1(&path, vp, clnt) != RPC_SUCCESS) { 243 if (!qflag) { 244 (void) mutex_lock(&tty); 245 clnt_perror(clnt, hostname); 246 (void) mutex_unlock(&tty); 247 } 248 } 249 clnt_destroy(clnt); 250 errout: 251 (void) mutex_lock(&thr_mtx); 252 thread_count--; 253 (void) mutex_unlock(&thr_mtx); 254 free(hostname); 255 return (0); 256 } 257 258 static void 259 usage(void) 260 { 261 (void) fprintf(stderr, 262 "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n"); 263 exit(1); 264 } 265