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