ruptime.c revision 200462
1/*
2 * Copyright (c) 1983, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1993, 1994\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static const char sccsid[] = "@(#)ruptime.c	8.2 (Berkeley) 4/5/94";
42#endif /* not lint */
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/usr.bin/ruptime/ruptime.c 200462 2009-12-13 03:14:06Z delphij $");
46
47#include <sys/param.h>
48
49#include <protocols/rwhod.h>
50
51#include <dirent.h>
52#include <err.h>
53#include <errno.h>
54#include <fcntl.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <time.h>
59#include <unistd.h>
60
61struct hs {
62	struct	whod *hs_wd;
63	int	hs_nusers;
64} *hs;
65struct	whod awhod;
66#define LEFTEARTH(h)		(now - (h) > 4*24*60*60)
67#define	ISDOWN(h)		(now - (h)->hs_wd->wd_recvtime > 11 * 60)
68#define	WHDRSIZE	(sizeof (awhod) - sizeof (awhod.wd_we))
69
70size_t nhosts;
71time_t now;
72int rflg = 1;
73DIR *dirp;
74
75int	 hscmp(const void *, const void *);
76char	*interval(time_t, const char *);
77int	 lcmp(const void *, const void *);
78void	 morehosts(void);
79void	 ruptime(const char *, int, int (*)(const void *, const void *));
80int	 tcmp(const void *, const void *);
81int	 ucmp(const void *, const void *);
82void	 usage(void);
83
84int
85main(int argc, char *argv[])
86{
87	int (*cmp)(const void *, const void *);
88	int aflg, ch;
89
90	aflg = 0;
91	cmp = hscmp;
92	while ((ch = getopt(argc, argv, "alrut")) != -1)
93		switch (ch) {
94		case 'a':
95			aflg = 1;
96			break;
97		case 'l':
98			cmp = lcmp;
99			break;
100		case 'r':
101			rflg = -1;
102			break;
103		case 't':
104			cmp = tcmp;
105			break;
106		case 'u':
107			cmp = ucmp;
108			break;
109		default:
110			usage();
111		}
112	argc -= optind;
113	argv += optind;
114
115	if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL)
116		err(1, "%s", _PATH_RWHODIR);
117
118	ruptime(*argv, aflg, cmp);
119	while (*argv++ != NULL) {
120		if (*argv == NULL)
121			break;
122		ruptime(*argv, aflg, cmp);
123	}
124	exit(0);
125}
126
127char *
128interval(time_t tval, const char *updown)
129{
130	static char resbuf[32];
131	int days, hours, minutes;
132
133	if (tval < 0) {
134		(void)snprintf(resbuf, sizeof(resbuf), "   %s ??:??", updown);
135		return (resbuf);
136	}
137						/* round to minutes. */
138	minutes = (tval + (60 - 1)) / 60;
139	hours = minutes / 60;
140	minutes %= 60;
141	days = hours / 24;
142	hours %= 24;
143	if (days)
144		(void)snprintf(resbuf, sizeof(resbuf),
145		    "%s %3d+%02d:%02d", updown, days, hours, minutes);
146	else
147		(void)snprintf(resbuf, sizeof(resbuf),
148		    "%s     %2d:%02d", updown, hours, minutes);
149	return (resbuf);
150}
151
152#define	HS(a)	((const struct hs *)(a))
153
154/* Alphabetical comparison. */
155int
156hscmp(const void *a1, const void *a2)
157{
158	return (rflg *
159	    strcmp(HS(a1)->hs_wd->wd_hostname, HS(a2)->hs_wd->wd_hostname));
160}
161
162/* Load average comparison. */
163int
164lcmp(const void *a1, const void *a2)
165{
166	if (ISDOWN(HS(a1)))
167		if (ISDOWN(HS(a2)))
168			return (tcmp(a1, a2));
169		else
170			return (rflg);
171	else if (ISDOWN(HS(a2)))
172		return (-rflg);
173	else
174		return (rflg *
175		   (HS(a2)->hs_wd->wd_loadav[0] - HS(a1)->hs_wd->wd_loadav[0]));
176}
177
178void
179ruptime(const char *host, int aflg, int (*cmp)(const void *, const void *))
180{
181	struct hs *hsp;
182	struct whod *wd;
183	struct whoent *we;
184	struct dirent *dp;
185	const char *hostname;
186	char buf[sizeof(struct whod)];
187	int fd, i, maxloadav;
188	size_t hspace;
189	u_int cc;
190
191	rewinddir(dirp);
192	hsp = NULL;
193	maxloadav = -1;
194	(void)time(&now);
195	for (nhosts = hspace = 0; (dp = readdir(dirp)) != NULL;) {
196		if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0)
197			continue;
198		if ((fd = open(dp->d_name, O_RDONLY, 0)) < 0) {
199			warn("%s", dp->d_name);
200			continue;
201		}
202		cc = read(fd, buf, sizeof(struct whod));
203		(void)close(fd);
204		if (host != NULL) {
205			hostname = ((struct whod *)buf)->wd_hostname;
206			if (strcasecmp(hostname, host) != 0)
207				continue;
208		}
209
210		if (cc < WHDRSIZE)
211			continue;
212		if (LEFTEARTH(((struct whod *)buf)->wd_recvtime))
213			continue;
214		if (nhosts == hspace) {
215			if ((hs =
216			    realloc(hs, (hspace += 40) * sizeof(*hs))) == NULL)
217				err(1, NULL);
218			hsp = hs + nhosts;
219		}
220
221		if ((hsp->hs_wd = malloc((size_t)WHDRSIZE)) == NULL)
222			err(1, NULL);
223		memmove(hsp->hs_wd, buf, (size_t)WHDRSIZE);
224
225		for (wd = (struct whod *)buf, i = 0; i < 2; ++i)
226			if (wd->wd_loadav[i] > maxloadav)
227				maxloadav = wd->wd_loadav[i];
228
229		for (hsp->hs_nusers = 0,
230		    we = (struct whoent *)(buf + cc); --we >= wd->wd_we;)
231			if (aflg || we->we_idle < 3600)
232				++hsp->hs_nusers;
233		++hsp;
234		++nhosts;
235	}
236	if (nhosts == 0) {
237		if (host == NULL)
238			errx(1, "no hosts in %s", _PATH_RWHODIR);
239		else
240			warnx("host %s not in %s", host, _PATH_RWHODIR);
241	}
242
243	qsort(hs, nhosts, sizeof(hs[0]), cmp);
244	for (i = 0; i < (int)nhosts; i++) {
245		hsp = &hs[i];
246		if (ISDOWN(hsp)) {
247			(void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname,
248			    interval(now - hsp->hs_wd->wd_recvtime, "down"));
249			continue;
250		}
251		(void)printf(
252		    "%-12.12s%s,  %4d user%s  load %*.2f, %*.2f, %*.2f\n",
253		    hsp->hs_wd->wd_hostname,
254		    interval((time_t)hsp->hs_wd->wd_sendtime -
255			(time_t)hsp->hs_wd->wd_boottime, "  up"),
256		    hsp->hs_nusers,
257		    hsp->hs_nusers == 1 ? ", " : "s,",
258		    maxloadav >= 1000 ? 5 : 4,
259			hsp->hs_wd->wd_loadav[0] / 100.0,
260		    maxloadav >= 1000 ? 5 : 4,
261		        hsp->hs_wd->wd_loadav[1] / 100.0,
262		    maxloadav >= 1000 ? 5 : 4,
263		        hsp->hs_wd->wd_loadav[2] / 100.0);
264		free(hsp->hs_wd);
265	}
266	free(hs);
267	hs = NULL;
268}
269
270/* Number of users comparison. */
271int
272ucmp(const void *a1, const void *a2)
273{
274	if (ISDOWN(HS(a1)))
275		if (ISDOWN(HS(a2)))
276			return (tcmp(a1, a2));
277		else
278			return (rflg);
279	else if (ISDOWN(HS(a2)))
280		return (-rflg);
281	else
282		return (rflg * (HS(a2)->hs_nusers - HS(a1)->hs_nusers));
283}
284
285/* Uptime comparison. */
286int
287tcmp(const void *a1, const void *a2)
288{
289	return (rflg * (
290		(ISDOWN(HS(a2)) ? HS(a2)->hs_wd->wd_recvtime - now
291		    : HS(a2)->hs_wd->wd_sendtime - HS(a2)->hs_wd->wd_boottime)
292		-
293		(ISDOWN(HS(a1)) ? HS(a1)->hs_wd->wd_recvtime - now
294		    : HS(a1)->hs_wd->wd_sendtime - HS(a1)->hs_wd->wd_boottime)
295	));
296}
297
298void
299usage(void)
300{
301	(void)fprintf(stderr, "usage: ruptime [-alrtu] [host ...]\n");
302	exit(1);
303}
304