xref: /illumos-gate/usr/src/cmd/rpcsvc/rwall.c (revision 012e6ce759c490003aed29439cc47d3d73a99ad3)
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
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
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
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
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 *
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
259 usage(void)
260 {
261 	(void) fprintf(stderr,
262 	    "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
263 	exit(1);
264 }
265