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