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