ruptime.c revision 149719
1249259Sdim/*
2249259Sdim * Copyright (c) 1983, 1993, 1994
3249259Sdim *	The Regents of the University of California.  All rights reserved.
4249259Sdim *
5249259Sdim * Redistribution and use in source and binary forms, with or without
6249259Sdim * modification, are permitted provided that the following conditions
7249259Sdim * are met:
8249259Sdim * 1. Redistributions of source code must retain the above copyright
9249259Sdim *    notice, this list of conditions and the following disclaimer.
10249259Sdim * 2. Redistributions in binary form must reproduce the above copyright
11249259Sdim *    notice, this list of conditions and the following disclaimer in the
12249259Sdim *    documentation and/or other materials provided with the distribution.
13249259Sdim * 3. All advertising materials mentioning features or use of this software
14249259Sdim *    must display the following acknowledgement:
15249259Sdim *	This product includes software developed by the University of
16249259Sdim *	California, Berkeley and its contributors.
17249259Sdim * 4. Neither the name of the University nor the names of its contributors
18249259Sdim *    may be used to endorse or promote products derived from this software
19249259Sdim *    without specific prior written permission.
20249259Sdim *
21249259Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22249259Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23249259Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24249259Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25249259Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26249259Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27249259Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28249259Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29249259Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30249259Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31249259Sdim * SUCH DAMAGE.
32249259Sdim */
33249259Sdim
34249259Sdim#ifndef lint
35249259Sdimstatic const char copyright[] =
36249259Sdim"@(#) Copyright (c) 1983, 1993, 1994\n\
37249259Sdim	The Regents of the University of California.  All rights reserved.\n";
38249259Sdim#endif /* not lint */
39249259Sdim
40249259Sdim#ifndef lint
41249259Sdimstatic const char sccsid[] = "@(#)ruptime.c	8.2 (Berkeley) 4/5/94";
42249259Sdim#endif /* not lint */
43249259Sdim
44249259Sdim#include <sys/cdefs.h>
45249259Sdim__FBSDID("$FreeBSD: head/usr.bin/ruptime/ruptime.c 149719 2005-09-02 14:58:26Z ssouhlal $");
46249259Sdim
47249259Sdim#include <sys/param.h>
48249259Sdim
49249259Sdim#include <protocols/rwhod.h>
50249259Sdim
51249259Sdim#include <dirent.h>
52249259Sdim#include <err.h>
53249259Sdim#include <errno.h>
54249259Sdim#include <fcntl.h>
55249259Sdim#include <stdio.h>
56249259Sdim#include <stdlib.h>
57249259Sdim#include <string.h>
58249259Sdim#include <time.h>
59249259Sdim#include <unistd.h>
60249259Sdim
61249259Sdimstruct hs {
62249259Sdim	struct	whod *hs_wd;
63249259Sdim	int	hs_nusers;
64249259Sdim} *hs;
65249259Sdimstruct	whod awhod;
66249259Sdim#define LEFTEARTH(h)		(now - (h) > 4*24*60*60)
67249259Sdim#define	ISDOWN(h)		(now - (h)->hs_wd->wd_recvtime > 11 * 60)
68249259Sdim#define	WHDRSIZE	(sizeof (awhod) - sizeof (awhod.wd_we))
69249259Sdim
70249259Sdimsize_t nhosts;
71249259Sdimtime_t now;
72249259Sdimint rflg = 1;
73249259SdimDIR *dirp;
74249259Sdim
75249259Sdimint	 hscmp(const void *, const void *);
76249259Sdimchar	*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	for (nhosts = hspace = 0; (dp = readdir(dirp)) != NULL;) {
195		if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0)
196			continue;
197		if ((fd = open(dp->d_name, O_RDONLY, 0)) < 0) {
198			warn("%s", dp->d_name);
199			continue;
200		}
201		cc = read(fd, buf, sizeof(struct whod));
202		(void)close(fd);
203		if (host != NULL) {
204			hostname = ((struct whod *)buf)->wd_hostname;
205			if (strcasecmp(hostname, host) != 0)
206				continue;
207		}
208
209		if (cc < WHDRSIZE)
210			continue;
211		if (LEFTEARTH(((struct whod *)buf)->wd_recvtime))
212			continue;
213		if (nhosts == hspace) {
214			if ((hs =
215			    realloc(hs, (hspace += 40) * sizeof(*hs))) == NULL)
216				err(1, NULL);
217			hsp = hs + nhosts;
218		}
219
220		if ((hsp->hs_wd = malloc((size_t)WHDRSIZE)) == NULL)
221			err(1, NULL);
222		memmove(hsp->hs_wd, buf, (size_t)WHDRSIZE);
223
224		for (wd = (struct whod *)buf, i = 0; i < 2; ++i)
225			if (wd->wd_loadav[i] > maxloadav)
226				maxloadav = wd->wd_loadav[i];
227
228		for (hsp->hs_nusers = 0,
229		    we = (struct whoent *)(buf + cc); --we >= wd->wd_we;)
230			if (aflg || we->we_idle < 3600)
231				++hsp->hs_nusers;
232		++hsp;
233		++nhosts;
234	}
235	if (nhosts == 0) {
236		if (host == NULL)
237			errx(1, "no hosts in %s", _PATH_RWHODIR);
238		else
239			warnx("host %s not in %s", host, _PATH_RWHODIR);
240	}
241
242	(void)time(&now);
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