xref: /illumos-gate/usr/src/cmd/rpcsvc/rwall.c (revision 34a0f871d192b33b865455a8812a3d34c1866315)
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 }
267