/usr.bin/ruptime/ruptime.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 295 lines · 233 code · 29 blank · 33 comment · 49 complexity · 3733d56f71539b358a4cea95687f6501 MD5 · raw file

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