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
main(int argc,char * argv[])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
init_who(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
doall(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
doit(char * hostname)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 *
do_one(void * arg)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
usage(void)259 usage(void)
260 {
261 (void) fprintf(stderr,
262 "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
263 exit(1);
264 }
265