rwall.c revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
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
60static void init_who(void);
61static void doall(void);
62static void doit(char *);
63static void *do_one(void *);
64static void usage(void);
65
66#define	PATIENCE 10
67#define	MAX_THREADS 1024
68
69static mutex_t tty = DEFAULTMUTEX;
70static char who[9] = "???";
71static char *path;
72static mutex_t thr_mtx = DEFAULTMUTEX;
73static int thread_count = 8;	/* fudge factor for system threads/fds */
74static int qflag = 0;		/* quiet: we don't care about errors */
75
76int
77main(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
152static void
153init_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 */
173static void
174doall(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 */
185static void
186doit(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
215static void *
216do_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);
252errout:
253	(void) mutex_lock(&thr_mtx);
254	thread_count--;
255	(void) mutex_unlock(&thr_mtx);
256	free(hostname);
257	return (0);
258}
259
260static void
261usage(void)
262{
263	(void) fprintf(stderr,
264	    "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
265	exit(1);
266}
267