1 /*	$OpenBSD: ruptime.c,v 1.14 2004/10/10 03:50:40 mickey Exp $	*/
2 
3 /*
4  * Copyright (c) 1983 The Regents of the University of California.
5  * 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 #ifndef lint
33 const char copyright[] =
34 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
35  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 /*static const char sccsid[] = "from: @(#)ruptime.c	5.8 (Berkeley) 7/21/90";*/
40 static const char rcsid[] = "$OpenBSD: ruptime.c,v 1.14 2004/10/10 03:50:40 mickey Exp $";
41 #endif /* not lint */
42 
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <dirent.h>
46 #include <protocols/rwhod.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <errno.h>
52 #include <err.h>
53 
54 size_t	nhosts, hspace = 20;
55 struct hs {
56 	struct	whod *hs_wd;
57 	int	hs_nusers;
58 } *hs;
59 struct	whod awhod;
60 
61 #define	ISDOWN(h)		(now - (h)->hs_wd->wd_recvtime > 11 * 60)
62 #define	WHDRSIZE	(sizeof (awhod) - sizeof (awhod.wd_we))
63 
64 time_t now;
65 int rflg = 1;
66 int	hscmp(const void *, const void *);
67 int	ucmp(const void *, const void *);
68 int	lcmp(const void *, const void *);
69 int	tcmp(const void *, const void *);
70 char	*interval(time_t, char *);
71 
72 void morehosts(void);
73 
74 int
main(int argc,char * argv[])75 main(int argc, char *argv[])
76 {
77 	extern char *__progname;
78 	struct hs *hsp;
79 	struct whod *wd;
80 	struct whoent *we;
81 	DIR *dirp;
82 	struct dirent *dp;
83 	int aflg, cc, ch, f, i, maxloadav;
84 	char buf[sizeof(struct whod)];
85 	int (*cmp)(const void *, const void *) = hscmp;
86 
87 	aflg = 0;
88 	while ((ch = getopt(argc, argv, "alrut")) != -1)
89 		switch((char)ch) {
90 		case 'a':
91 			aflg = 1;
92 			break;
93 		case 'l':
94 			cmp = lcmp;
95 			break;
96 		case 'r':
97 			rflg = -1;
98 			break;
99 		case 't':
100 			cmp = tcmp;
101 			break;
102 		case 'u':
103 			cmp = ucmp;
104 			break;
105 		default:
106 			fprintf(stderr, "usage: %s [-alrut]\n", __progname);
107 			exit(1);
108 		}
109 
110 	if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL)
111 		err(1, "%s", _PATH_RWHODIR);
112 	morehosts();
113 	hsp = hs;
114 	maxloadav = -1;
115 	while ((dp = readdir(dirp))) {
116 		if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5))
117 			continue;
118 		if ((f = open(dp->d_name, O_RDONLY, 0)) < 0) {
119 			warn("%s", dp->d_name);
120 			continue;
121 		}
122 		cc = read(f, buf, sizeof(struct whod));
123 		(void)close(f);
124 		if (cc < WHDRSIZE)
125 			continue;
126 		if (nhosts == hspace) {
127 			morehosts();
128 			hsp = hs + nhosts;
129 		}
130 		/* NOSTRICT */
131 		hsp->hs_wd = malloc((size_t)WHDRSIZE);
132 		wd = (struct whod *)buf;
133 		memmove((char *)hsp->hs_wd, (char *)wd, (size_t)WHDRSIZE);
134 		hsp->hs_nusers = 0;
135 		for (i = 0; i < 2; i++)
136 			if (wd->wd_loadav[i] > maxloadav)
137 				maxloadav = wd->wd_loadav[i];
138 		we = (struct whoent *)(buf+cc);
139 		while (--we >= wd->wd_we)
140 			if (aflg || we->we_idle < 3600)
141 				hsp->hs_nusers++;
142 		nhosts++;
143 		hsp++;
144 	}
145 	if (!nhosts)
146 		errx(1, "no hosts in %s.", _PATH_RWHODIR);
147 	(void)time(&now);
148 	qsort((char *)hs, nhosts, sizeof (hs[0]), cmp);
149 	for (i = 0; i < nhosts; i++) {
150 		hsp = &hs[i];
151 		if (ISDOWN(hsp)) {
152 			(void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname,
153 			    interval(now - hsp->hs_wd->wd_recvtime, "down"));
154 			continue;
155 		}
156 		(void)printf(
157 		    "%-12.12s%s,  %4d user%s  load %*.2f, %*.2f, %*.2f\n",
158 		    hsp->hs_wd->wd_hostname,
159 		    interval((time_t)hsp->hs_wd->wd_sendtime -
160 			(time_t)hsp->hs_wd->wd_boottime, "  up"),
161 		    hsp->hs_nusers,
162 		    hsp->hs_nusers == 1 ? ", " : "s,",
163 		    maxloadav >= 1000 ? 5 : 4,
164 			hsp->hs_wd->wd_loadav[0] / 100.0,
165 		    maxloadav >= 1000 ? 5 : 4,
166 		        hsp->hs_wd->wd_loadav[1] / 100.0,
167 		    maxloadav >= 1000 ? 5 : 4,
168 		        hsp->hs_wd->wd_loadav[2] / 100.0);
169 		free((void *)hsp->hs_wd);
170 	}
171 	exit(0);
172 }
173 
174 char *
interval(time_t tval,char * updown)175 interval(time_t tval, char *updown)
176 {
177 	static char resbuf[32];
178 	int days, hours, minutes;
179 
180 	if (tval < 0 || tval > 999*24*60*60) {
181 		(void)snprintf(resbuf, sizeof resbuf, "%s     ??:??", updown);
182 		return(resbuf);
183 	}
184 	minutes = (tval + 59) / 60;		/* round to minutes */
185 	hours = minutes / 60; minutes %= 60;
186 	days = hours / 24; hours %= 24;
187 	if (days)
188 		(void)snprintf(resbuf, sizeof resbuf, "%s %3d+%02d:%02d",
189 		    updown, days, hours, minutes);
190 	else
191 		(void)snprintf(resbuf, sizeof resbuf, "%s     %2d:%02d",
192 		    updown, hours, minutes);
193 	return(resbuf);
194 }
195 
196 /* alphabetical comparison */
197 int
hscmp(const void * a1,const void * a2)198 hscmp(const void *a1, const void *a2)
199 {
200 	const struct hs *h1 = a1, *h2 = a2;
201 
202 	return(rflg * strcmp(h1->hs_wd->wd_hostname, h2->hs_wd->wd_hostname));
203 }
204 
205 /* load average comparison */
206 int
lcmp(const void * a1,const void * a2)207 lcmp(const void *a1, const void *a2)
208 {
209 	const struct hs *h1 = a1, *h2 = a2;
210 
211 	if (ISDOWN(h1))
212 		if (ISDOWN(h2))
213 			return(tcmp(a1, a2));
214 		else
215 			return(rflg);
216 	else if (ISDOWN(h2))
217 		return(-rflg);
218 	else
219 		return(rflg *
220 			(h2->hs_wd->wd_loadav[0] - h1->hs_wd->wd_loadav[0]));
221 }
222 
223 /* number of users comparison */
224 int
ucmp(const void * a1,const void * a2)225 ucmp(const void *a1, const void *a2)
226 {
227 	const struct hs *h1 = a1, *h2 = a2;
228 
229 	if (ISDOWN(h1))
230 		if (ISDOWN(h2))
231 			return(tcmp(a1, a2));
232 		else
233 			return(rflg);
234 	else if (ISDOWN(h2))
235 		return(-rflg);
236 	else
237 		return(rflg * (h2->hs_nusers - h1->hs_nusers));
238 }
239 
240 /* uptime comparison */
241 int
tcmp(const void * a1,const void * a2)242 tcmp(const void *a1, const void *a2)
243 {
244 	const struct hs *h1 = a1, *h2 = a2;
245 
246 	return(rflg * (
247 		(ISDOWN(h2) ? h2->hs_wd->wd_recvtime - now
248 			  : h2->hs_wd->wd_sendtime - h2->hs_wd->wd_boottime)
249 		-
250 		(ISDOWN(h1) ? h1->hs_wd->wd_recvtime - now
251 			  : h1->hs_wd->wd_sendtime - h1->hs_wd->wd_boottime)
252 	));
253 }
254 
255 void
morehosts(void)256 morehosts(void)
257 {
258 	hs = realloc((char *)hs, (hspace *= 2) * sizeof(*hs));
259 	if (hs == NULL)
260 		err(1, "realloc");
261 }
262