rwall.c revision 49e7ca4919cec3229f6fab9730bafc7cf24dab23
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
59static void init_who(void);
60static void doall(void);
61static void doit(char *);
62static void *do_one(void *);
63static void usage(void);
64
65#define	PATIENCE 10
66#define	MAX_THREADS 1024
67
68static mutex_t tty = DEFAULTMUTEX;
69static char who[9] = "???";
70static char *path;
71static mutex_t thr_mtx = DEFAULTMUTEX;
72static int thread_count = 8;	/* fudge factor for system threads/fds */
73static int qflag = 0;		/* quiet: we don't care about errors */
74
75int
76main(int argc, char *argv[])
77{
78	int msize;
79	char buf[BUFSIZ+1];
80	int i;
81	char hostname[256];
82	int hflag;
83	struct rlimit rl;
84
85	if (argc < 2)
86		usage();
87
88	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
89		rl.rlim_cur = (rl.rlim_max < MAX_THREADS ?
90		    rl.rlim_max : MAX_THREADS);
91		(void) setrlimit(RLIMIT_NOFILE, &rl);
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
150static void
151init_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 */
171static void
172doall(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 */
183static void
184doit(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
213static void *
214do_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);
250errout:
251	(void) mutex_lock(&thr_mtx);
252	thread_count--;
253	(void) mutex_unlock(&thr_mtx);
254	free(hostname);
255	return (0);
256}
257
258static void
259usage(void)
260{
261	(void) fprintf(stderr,
262	    "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
263	exit(1);
264}
265