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