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