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
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
75main(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
151static void
152init_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 */
172static void
173doall(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 */
184static void
185doit(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
214static void *
215do_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);
251errout:
252	(void) mutex_lock(&thr_mtx);
253	thread_count--;
254	(void) mutex_unlock(&thr_mtx);
255	free(hostname);
256	return (0);
257}
258
259static void
260usage(void)
261{
262	(void) fprintf(stderr,
263	    "Usage: rwall [-q] host .... [-n netgroup ....] [-h host ...]\n");
264	exit(1);
265}
266