1f6aeec64SMatthew Dillon /*
2f8220a21SMatthew Dillon * Copyright (c) 2017-2019 The DragonFly Project. All rights reserved.
3f6aeec64SMatthew Dillon *
4f6aeec64SMatthew Dillon * This code is derived from software contributed to The DragonFly Project
5f6aeec64SMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
6f6aeec64SMatthew Dillon *
7f6aeec64SMatthew Dillon * Redistribution and use in source and binary forms, with or without
8f6aeec64SMatthew Dillon * modification, are permitted provided that the following conditions
9f6aeec64SMatthew Dillon * are met:
10f6aeec64SMatthew Dillon *
11f6aeec64SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
12f6aeec64SMatthew Dillon * notice, this list of conditions and the following disclaimer.
13f6aeec64SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
14f6aeec64SMatthew Dillon * notice, this list of conditions and the following disclaimer in
15f6aeec64SMatthew Dillon * the documentation and/or other materials provided with the
16f6aeec64SMatthew Dillon * distribution.
17f6aeec64SMatthew Dillon *
18f6aeec64SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19f6aeec64SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20f6aeec64SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21f6aeec64SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22f6aeec64SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23f6aeec64SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24f6aeec64SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25f6aeec64SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26f6aeec64SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27f6aeec64SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28f6aeec64SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f6aeec64SMatthew Dillon * SUCH DAMAGE.
30f6aeec64SMatthew Dillon */
31f6aeec64SMatthew Dillon
32f9c8e4acSMatthew Dillon #include "kcollect.h"
33fef9ed17SMatthew Dillon
34e10ffbc2SMatthew Dillon #include <ndbm.h>
35e10ffbc2SMatthew Dillon #include <fcntl.h>
36e10ffbc2SMatthew Dillon #include <errno.h>
37e10ffbc2SMatthew Dillon
38fef9ed17SMatthew Dillon #define SLEEP_INTERVAL 60 /* minimum is KCOLLECT_INTERVAL */
39f8220a21SMatthew Dillon #define DATA_BASE_INDEX 8 /* up to 8 headers */
40fef9ed17SMatthew Dillon
41e10ffbc2SMatthew Dillon #define DISPLAY_TIME_ONLY "%H:%M:%S"
42e10ffbc2SMatthew Dillon #define DISPLAY_FULL_DATE "%F %H:%M:%S"
43f8220a21SMatthew Dillon #define HDR_BASE "HEADER"
44f8220a21SMatthew Dillon #define HDR_STRLEN 6
45f8220a21SMatthew Dillon
46f8220a21SMatthew Dillon #define HDR_FMT_INDEX 0
47f8220a21SMatthew Dillon #define HDR_FMT_TITLE 1
48f8220a21SMatthew Dillon #define HDR_FMT_HOST 2
49e10ffbc2SMatthew Dillon
50f089ea9cSAntonio Huete Jimenez #define HOST_NAME_MAX sysconf(_SC_HOST_NAME_MAX)
51f089ea9cSAntonio Huete Jimenez
5268cca79dSAntonio Huete Jimenez static void format_output(uintmax_t, char, uintmax_t, char *);
5368cca79dSAntonio Huete Jimenez static void dump_text(kcollect_t *, size_t, size_t, const char *);
5468cca79dSAntonio Huete Jimenez static const char *get_influx_series(const char *);
55f089ea9cSAntonio Huete Jimenez static void dump_influxdb(kcollect_t *, size_t, size_t, const char *);
56f089ea9cSAntonio Huete Jimenez
57f089ea9cSAntonio Huete Jimenez static void (*dumpfn)(kcollect_t *, size_t, size_t, const char *);
58f089ea9cSAntonio Huete Jimenez
5968cca79dSAntonio Huete Jimenez static void dump_dbm(kcollect_t *, size_t, const char *);
6068cca79dSAntonio Huete Jimenez static void load_dbm(const char *datafile, kcollect_t **, size_t *);
6168cca79dSAntonio Huete Jimenez static int rec_comparator(const void *, const void *);
6268cca79dSAntonio Huete Jimenez static void dump_fields(kcollect_t *);
6368cca79dSAntonio Huete Jimenez static void adjust_fields(kcollect_t *, const char *);
6468cca79dSAntonio Huete Jimenez static void restore_headers(kcollect_t *, const char *);
6568cca79dSAntonio Huete Jimenez static int str2unix(const char *, const char*);
6668cca79dSAntonio Huete Jimenez static kcollect_t *load_kernel(kcollect_t *, kcollect_t *, size_t *);
6768cca79dSAntonio Huete Jimenez
68f9c8e4acSMatthew Dillon FILE *OutFP;
69f9c8e4acSMatthew Dillon int UseGMT;
70f9c8e4acSMatthew Dillon int OutputWidth = 1024;
71f9c8e4acSMatthew Dillon int OutputHeight = 1024;
72b038db3dSMatthew Dillon int SmoothOpt;
73*d50f9ae3SSascha Wildner static int LoadedFromDB;
74*d50f9ae3SSascha Wildner static int HostnameMismatch;
75*d50f9ae3SSascha Wildner static int Fflag;
76f6aeec64SMatthew Dillon
77f6aeec64SMatthew Dillon int
main(int ac,char ** av)78fef9ed17SMatthew Dillon main(int ac, char **av)
79f6aeec64SMatthew Dillon {
80f8220a21SMatthew Dillon kcollect_t *ary_base;
81f6aeec64SMatthew Dillon kcollect_t *ary;
82fef9ed17SMatthew Dillon size_t bytes = 0;
83fef9ed17SMatthew Dillon size_t count;
84fef9ed17SMatthew Dillon size_t total_count;
85fef9ed17SMatthew Dillon const char *datafile = NULL;
86f9c8e4acSMatthew Dillon const char *fields = NULL;
87fef9ed17SMatthew Dillon int cmd = 't';
88fef9ed17SMatthew Dillon int ch;
89fef9ed17SMatthew Dillon int keepalive = 0;
90fef9ed17SMatthew Dillon int last_ticks;
91fef9ed17SMatthew Dillon int loops = 0;
927849fb91SMatthew Dillon int maxtime = 0;
93e10ffbc2SMatthew Dillon const char *dbmFile = NULL;
94e10ffbc2SMatthew Dillon int fromFile = 0;
95e10ffbc2SMatthew Dillon
96f9c8e4acSMatthew Dillon OutFP = stdout;
97f089ea9cSAntonio Huete Jimenez dumpfn = dump_text;
98f9c8e4acSMatthew Dillon
99f6aeec64SMatthew Dillon sysctlbyname("kern.collect_data", NULL, &bytes, NULL, 0);
100f6aeec64SMatthew Dillon if (bytes == 0) {
101f6aeec64SMatthew Dillon fprintf(stderr, "kern.collect_data not available\n");
102f6aeec64SMatthew Dillon exit(1);
103f6aeec64SMatthew Dillon }
104fef9ed17SMatthew Dillon
105f089ea9cSAntonio Huete Jimenez while ((ch = getopt(ac, av, "o:O:b:d:r:fFlsgt:xw:GW:H:")) != -1) {
1067849fb91SMatthew Dillon char *suffix;
1077849fb91SMatthew Dillon
108fef9ed17SMatthew Dillon switch(ch) {
109fef9ed17SMatthew Dillon case 'o':
110f9c8e4acSMatthew Dillon fields = optarg;
111fef9ed17SMatthew Dillon break;
112f089ea9cSAntonio Huete Jimenez case 'O':
113f089ea9cSAntonio Huete Jimenez if ((strncasecmp("influxdb", optarg, 16) == 0)) {
114f089ea9cSAntonio Huete Jimenez dumpfn = dump_influxdb;
115f089ea9cSAntonio Huete Jimenez } else if (strncasecmp("text", optarg, 16) == 0) {
116f089ea9cSAntonio Huete Jimenez dumpfn = dump_text;
117f089ea9cSAntonio Huete Jimenez } else {
118f089ea9cSAntonio Huete Jimenez fprintf(stderr, "Bad output text format %s\n", optarg);
119f089ea9cSAntonio Huete Jimenez exit(1);
120f089ea9cSAntonio Huete Jimenez }
121f089ea9cSAntonio Huete Jimenez break;
122fef9ed17SMatthew Dillon case 'b':
123fef9ed17SMatthew Dillon datafile = optarg;
124fef9ed17SMatthew Dillon cmd = 'b';
125fef9ed17SMatthew Dillon break;
126e10ffbc2SMatthew Dillon case 'd':
127e10ffbc2SMatthew Dillon dbmFile = optarg;
128e10ffbc2SMatthew Dillon fromFile = 1;
129e10ffbc2SMatthew Dillon break;
130c5741af1SMatthew Dillon case 'r':
131c5741af1SMatthew Dillon datafile = optarg;
132c5741af1SMatthew Dillon cmd = 'r';
133c5741af1SMatthew Dillon break;
134fef9ed17SMatthew Dillon case 'f':
135fef9ed17SMatthew Dillon keepalive = 1;
136fef9ed17SMatthew Dillon break;
1371a5888d3SAntonio Huete Jimenez case 'F':
1381a5888d3SAntonio Huete Jimenez Fflag = 1;
1391a5888d3SAntonio Huete Jimenez keepalive = 1;
1401a5888d3SAntonio Huete Jimenez break;
141fef9ed17SMatthew Dillon case 'l':
142fef9ed17SMatthew Dillon cmd = 'l';
143fef9ed17SMatthew Dillon break;
144b038db3dSMatthew Dillon case 's':
145b038db3dSMatthew Dillon SmoothOpt = 1;
146b038db3dSMatthew Dillon break;
147f9c8e4acSMatthew Dillon case 'w':
148f9c8e4acSMatthew Dillon datafile = optarg;
149f9c8e4acSMatthew Dillon cmd = 'w';
150f9c8e4acSMatthew Dillon break;
151fef9ed17SMatthew Dillon case 'g':
152fef9ed17SMatthew Dillon cmd = 'g';
153fef9ed17SMatthew Dillon break;
154fef9ed17SMatthew Dillon case 'x':
155fef9ed17SMatthew Dillon cmd = 'x';
156fef9ed17SMatthew Dillon break;
1577849fb91SMatthew Dillon case 't':
1587849fb91SMatthew Dillon maxtime = strtol(optarg, &suffix, 0);
1597849fb91SMatthew Dillon switch(*suffix) {
1607849fb91SMatthew Dillon case 'd':
1617849fb91SMatthew Dillon maxtime *= 24;
1627849fb91SMatthew Dillon /* fall through */
1637849fb91SMatthew Dillon case 'h':
1647849fb91SMatthew Dillon maxtime *= 60;
1657849fb91SMatthew Dillon /* fall through */
1667849fb91SMatthew Dillon case 'm':
1677849fb91SMatthew Dillon maxtime *= 60;
1687849fb91SMatthew Dillon break;
1697849fb91SMatthew Dillon case 0:
1707849fb91SMatthew Dillon break;
1717849fb91SMatthew Dillon default:
1727849fb91SMatthew Dillon fprintf(stderr,
1737849fb91SMatthew Dillon "Illegal suffix in -t option\n");
1747849fb91SMatthew Dillon exit(1);
1757849fb91SMatthew Dillon }
1767849fb91SMatthew Dillon break;
177fef9ed17SMatthew Dillon case 'G':
178f9c8e4acSMatthew Dillon UseGMT = 1;
179f9c8e4acSMatthew Dillon break;
180f9c8e4acSMatthew Dillon case 'W':
181f9c8e4acSMatthew Dillon OutputWidth = strtol(optarg, NULL, 0);
182f9c8e4acSMatthew Dillon break;
183f9c8e4acSMatthew Dillon case 'H':
184f9c8e4acSMatthew Dillon OutputHeight = strtol(optarg, NULL, 0);
185fef9ed17SMatthew Dillon break;
186fef9ed17SMatthew Dillon default:
187fef9ed17SMatthew Dillon fprintf(stderr, "Unknown option %c\n", ch);
188fef9ed17SMatthew Dillon exit(1);
189fef9ed17SMatthew Dillon /* NOT REACHED */
190fef9ed17SMatthew Dillon }
191fef9ed17SMatthew Dillon }
192fef9ed17SMatthew Dillon if (cmd != 'x' && ac != optind) {
193fef9ed17SMatthew Dillon fprintf(stderr, "Unknown argument %s\n", av[optind]);
194fef9ed17SMatthew Dillon exit(1);
195fef9ed17SMatthew Dillon /* NOT REACHED */
196fef9ed17SMatthew Dillon }
197fef9ed17SMatthew Dillon
198fef9ed17SMatthew Dillon total_count = 0;
199f9c8e4acSMatthew Dillon last_ticks = 0;
200fef9ed17SMatthew Dillon
201f9c8e4acSMatthew Dillon if (cmd == 'x' || cmd == 'w')
20256160b9cSMatthew Dillon start_gnuplot(ac - optind, av + optind, datafile);
203f9c8e4acSMatthew Dillon
204fef9ed17SMatthew Dillon do {
205fef9ed17SMatthew Dillon /*
206a657b521SAntonio Huete Jimenez * We do not allow keepalive if there is a hostname
207a657b521SAntonio Huete Jimenez * mismatch, there is no point in showing data for the
208a657b521SAntonio Huete Jimenez * current host after dumping the data from another one.
209a657b521SAntonio Huete Jimenez */
210a657b521SAntonio Huete Jimenez if (HostnameMismatch) {
211a657b521SAntonio Huete Jimenez fprintf(stderr,
212a657b521SAntonio Huete Jimenez "Hostname mismatch, can't show live data\n");
213a657b521SAntonio Huete Jimenez exit(1);
214a657b521SAntonio Huete Jimenez }
215a657b521SAntonio Huete Jimenez
216a657b521SAntonio Huete Jimenez /*
217fef9ed17SMatthew Dillon * Snarf as much data as we can. If we are looping,
218fef9ed17SMatthew Dillon * snarf less (no point snarfing stuff we already have).
219fef9ed17SMatthew Dillon */
220fef9ed17SMatthew Dillon bytes = 0;
221fef9ed17SMatthew Dillon sysctlbyname("kern.collect_data", NULL, &bytes, NULL, 0);
222fef9ed17SMatthew Dillon if (cmd == 'l')
223fef9ed17SMatthew Dillon bytes = sizeof(kcollect_t) * 2;
224fef9ed17SMatthew Dillon
225a657b521SAntonio Huete Jimenez /* Skip to the newest entries */
2261a5888d3SAntonio Huete Jimenez if (Fflag && loops == 0)
2271a5888d3SAntonio Huete Jimenez loops++;
2281a5888d3SAntonio Huete Jimenez
229fef9ed17SMatthew Dillon if (loops) {
230fef9ed17SMatthew Dillon size_t loop_bytes;
231fef9ed17SMatthew Dillon
232fef9ed17SMatthew Dillon loop_bytes = sizeof(kcollect_t) *
233fef9ed17SMatthew Dillon (4 + SLEEP_INTERVAL / KCOLLECT_INTERVAL);
234fef9ed17SMatthew Dillon if (bytes > loop_bytes)
235fef9ed17SMatthew Dillon bytes = loop_bytes;
236fef9ed17SMatthew Dillon }
237fef9ed17SMatthew Dillon
238e10ffbc2SMatthew Dillon /*
239e10ffbc2SMatthew Dillon * If we got specified a file to load from: replace the data
240e10ffbc2SMatthew Dillon * array and counter
241e10ffbc2SMatthew Dillon */
242e10ffbc2SMatthew Dillon if (fromFile) {
243f8220a21SMatthew Dillon kcollect_t *dbmAry = NULL;
244e10ffbc2SMatthew Dillon
245f8220a21SMatthew Dillon load_dbm(dbmFile, &dbmAry, &count);
246f8220a21SMatthew Dillon ary = ary_base = dbmAry;
247f8220a21SMatthew Dillon } else {
248f8220a21SMatthew Dillon kcollect_t scaleid[2];
249f8220a21SMatthew Dillon
250f8220a21SMatthew Dillon ary_base = malloc(bytes +
251f8220a21SMatthew Dillon DATA_BASE_INDEX * sizeof(kcollect_t));
252f8220a21SMatthew Dillon ary = ary_base + DATA_BASE_INDEX;
253f8220a21SMatthew Dillon sysctlbyname("kern.collect_data", ary, &bytes, NULL, 0);
254f8220a21SMatthew Dillon count = bytes / sizeof(kcollect_t);
255f8220a21SMatthew Dillon if (count < 2) {
256f8220a21SMatthew Dillon fprintf(stderr,
257f8220a21SMatthew Dillon "[ERR] kern.collect_data failed\n");
258f8220a21SMatthew Dillon exit(1);
259f8220a21SMatthew Dillon }
260f8220a21SMatthew Dillon scaleid[0] = ary[0];
261f8220a21SMatthew Dillon scaleid[1] = ary[1];
262f8220a21SMatthew Dillon count -= 2;
263f8220a21SMatthew Dillon ary = load_kernel(scaleid, ary + 2, &count);
264e10ffbc2SMatthew Dillon }
265f9c8e4acSMatthew Dillon if (fields)
266f9c8e4acSMatthew Dillon adjust_fields(&ary[1], fields);
267f9c8e4acSMatthew Dillon
2687849fb91SMatthew Dillon
2697849fb91SMatthew Dillon /*
2707849fb91SMatthew Dillon * Delete duplicate entries when looping
2717849fb91SMatthew Dillon */
272fef9ed17SMatthew Dillon if (loops) {
273f8220a21SMatthew Dillon while (count > DATA_BASE_INDEX) {
274fef9ed17SMatthew Dillon if ((int)(ary[count-1].ticks - last_ticks) > 0)
275fef9ed17SMatthew Dillon break;
276fef9ed17SMatthew Dillon --count;
277fef9ed17SMatthew Dillon }
278fef9ed17SMatthew Dillon }
279fef9ed17SMatthew Dillon
2807849fb91SMatthew Dillon /*
2817849fb91SMatthew Dillon * Delete any entries beyond the time limit
2827849fb91SMatthew Dillon */
2837849fb91SMatthew Dillon if (maxtime) {
2847849fb91SMatthew Dillon maxtime *= ary[0].hz;
285f8220a21SMatthew Dillon while (count > DATA_BASE_INDEX) {
2867849fb91SMatthew Dillon if ((int)(ary[0].ticks - ary[count-1].ticks) <
2877849fb91SMatthew Dillon maxtime) {
2887849fb91SMatthew Dillon break;
2897849fb91SMatthew Dillon }
2907849fb91SMatthew Dillon --count;
2917849fb91SMatthew Dillon }
2927849fb91SMatthew Dillon }
2937849fb91SMatthew Dillon
294fef9ed17SMatthew Dillon switch(cmd) {
295fef9ed17SMatthew Dillon case 't':
296f8220a21SMatthew Dillon if (count > DATA_BASE_INDEX) {
297f089ea9cSAntonio Huete Jimenez dumpfn(ary, count, total_count,
298e10ffbc2SMatthew Dillon (fromFile ? DISPLAY_FULL_DATE :
299e10ffbc2SMatthew Dillon DISPLAY_TIME_ONLY));
300e10ffbc2SMatthew Dillon }
301fef9ed17SMatthew Dillon break;
302fef9ed17SMatthew Dillon case 'b':
303a657b521SAntonio Huete Jimenez if (HostnameMismatch) {
304a657b521SAntonio Huete Jimenez fprintf(stderr,
305a657b521SAntonio Huete Jimenez "Hostname mismatch, cannot save to DB\n");
306a657b521SAntonio Huete Jimenez exit(1);
307a657b521SAntonio Huete Jimenez } else {
308f8220a21SMatthew Dillon if (count > DATA_BASE_INDEX)
309fef9ed17SMatthew Dillon dump_dbm(ary, count, datafile);
310a657b521SAntonio Huete Jimenez }
311fef9ed17SMatthew Dillon break;
312c5741af1SMatthew Dillon case 'r':
313f8220a21SMatthew Dillon if (count >= DATA_BASE_INDEX)
314c5741af1SMatthew Dillon restore_headers(ary, datafile);
315c5741af1SMatthew Dillon break;
316fef9ed17SMatthew Dillon case 'l':
317fef9ed17SMatthew Dillon dump_fields(ary);
318fef9ed17SMatthew Dillon exit(0);
319fef9ed17SMatthew Dillon break; /* NOT REACHED */
320fef9ed17SMatthew Dillon case 'g':
321f8220a21SMatthew Dillon if (count > DATA_BASE_INDEX)
32256160b9cSMatthew Dillon dump_gnuplot(ary, count);
323f9c8e4acSMatthew Dillon break;
324f9c8e4acSMatthew Dillon case 'w':
325f8220a21SMatthew Dillon if (count >= DATA_BASE_INDEX)
32656160b9cSMatthew Dillon dump_gnuplot(ary, count);
327fef9ed17SMatthew Dillon break;
328fef9ed17SMatthew Dillon case 'x':
329f8220a21SMatthew Dillon if (count > DATA_BASE_INDEX)
33056160b9cSMatthew Dillon dump_gnuplot(ary, count);
331fef9ed17SMatthew Dillon break;
332fef9ed17SMatthew Dillon }
333e10ffbc2SMatthew Dillon if (keepalive && !fromFile) {
334f9c8e4acSMatthew Dillon fflush(OutFP);
335fef9ed17SMatthew Dillon fflush(stdout);
336f9c8e4acSMatthew Dillon switch(cmd) {
337f9c8e4acSMatthew Dillon case 't':
338fef9ed17SMatthew Dillon sleep(1);
339f9c8e4acSMatthew Dillon break;
340f9c8e4acSMatthew Dillon case 'x':
341f9c8e4acSMatthew Dillon case 'g':
342f9c8e4acSMatthew Dillon case 'w':
343f9c8e4acSMatthew Dillon sleep(60);
344f9c8e4acSMatthew Dillon break;
345f9c8e4acSMatthew Dillon default:
346f9c8e4acSMatthew Dillon sleep(10);
347f9c8e4acSMatthew Dillon break;
348f9c8e4acSMatthew Dillon }
349fef9ed17SMatthew Dillon }
350f8220a21SMatthew Dillon last_ticks = ary[DATA_BASE_INDEX].ticks;
351f8220a21SMatthew Dillon if (count >= DATA_BASE_INDEX)
352f8220a21SMatthew Dillon total_count += count - DATA_BASE_INDEX;
353f9c8e4acSMatthew Dillon
354f9c8e4acSMatthew Dillon /*
355f9c8e4acSMatthew Dillon * Loop for incremental aquisition. When outputting to
356f9c8e4acSMatthew Dillon * gunplot, we have to send the whole data-set again so
357f9c8e4acSMatthew Dillon * do not increment loops in that case.
358f9c8e4acSMatthew Dillon */
359f9c8e4acSMatthew Dillon if (cmd != 'g' && cmd != 'x' && cmd != 'w')
360fef9ed17SMatthew Dillon ++loops;
361f9c8e4acSMatthew Dillon
362f8220a21SMatthew Dillon free(ary_base);
363fef9ed17SMatthew Dillon } while (keepalive);
364fef9ed17SMatthew Dillon
365fef9ed17SMatthew Dillon if (cmd == 'x')
366f9c8e4acSMatthew Dillon pclose(OutFP);
367fef9ed17SMatthew Dillon }
368fef9ed17SMatthew Dillon
369fef9ed17SMatthew Dillon static
370fef9ed17SMatthew Dillon void
format_output(uintmax_t value,char fmt,uintmax_t scale,char * ret)371e10ffbc2SMatthew Dillon format_output(uintmax_t value,char fmt,uintmax_t scale, char* ret)
372e10ffbc2SMatthew Dillon {
373e10ffbc2SMatthew Dillon char buf[9];
374e10ffbc2SMatthew Dillon
375e10ffbc2SMatthew Dillon switch(fmt) {
376e10ffbc2SMatthew Dillon case '2':
377e10ffbc2SMatthew Dillon /*
378e10ffbc2SMatthew Dillon * fractional x100
379e10ffbc2SMatthew Dillon */
380e10ffbc2SMatthew Dillon sprintf(ret, "%5ju.%02ju",
381e10ffbc2SMatthew Dillon value / 100, value % 100);
382e10ffbc2SMatthew Dillon break;
383e10ffbc2SMatthew Dillon case 'p':
384e10ffbc2SMatthew Dillon /*
385e10ffbc2SMatthew Dillon * Percentage fractional x100 (100% = 10000)
386e10ffbc2SMatthew Dillon */
387e10ffbc2SMatthew Dillon sprintf(ret,"%4ju.%02ju%%",
388e10ffbc2SMatthew Dillon value / 100, value % 100);
389e10ffbc2SMatthew Dillon break;
390e10ffbc2SMatthew Dillon case 'm':
391e10ffbc2SMatthew Dillon /*
392e10ffbc2SMatthew Dillon * Megabytes
393e10ffbc2SMatthew Dillon */
394e10ffbc2SMatthew Dillon humanize_number(buf, sizeof(buf), value, "",
395e10ffbc2SMatthew Dillon 2,
396e10ffbc2SMatthew Dillon HN_FRACTIONAL |
397e10ffbc2SMatthew Dillon HN_NOSPACE);
398e10ffbc2SMatthew Dillon sprintf(ret,"%8.8s", buf);
399e10ffbc2SMatthew Dillon break;
400e10ffbc2SMatthew Dillon case 'c':
401e10ffbc2SMatthew Dillon /*
402e10ffbc2SMatthew Dillon * Raw count over period (this is not total)
403e10ffbc2SMatthew Dillon */
404e10ffbc2SMatthew Dillon humanize_number(buf, sizeof(buf), value, "",
405e10ffbc2SMatthew Dillon HN_AUTOSCALE,
406e10ffbc2SMatthew Dillon HN_FRACTIONAL |
407e10ffbc2SMatthew Dillon HN_NOSPACE |
408e10ffbc2SMatthew Dillon HN_DIVISOR_1000);
409e10ffbc2SMatthew Dillon sprintf(ret,"%8.8s", buf);
410e10ffbc2SMatthew Dillon break;
411e10ffbc2SMatthew Dillon case 'b':
412e10ffbc2SMatthew Dillon /*
413e10ffbc2SMatthew Dillon * Total bytes (this is a total), output
414e10ffbc2SMatthew Dillon * in megabytes.
415e10ffbc2SMatthew Dillon */
416e10ffbc2SMatthew Dillon if (scale > 100000000) {
417e10ffbc2SMatthew Dillon humanize_number(buf, sizeof(buf),
418e10ffbc2SMatthew Dillon value, "",
419e10ffbc2SMatthew Dillon 3,
420e10ffbc2SMatthew Dillon HN_FRACTIONAL |
421e10ffbc2SMatthew Dillon HN_NOSPACE);
422e10ffbc2SMatthew Dillon } else {
423e10ffbc2SMatthew Dillon humanize_number(buf, sizeof(buf),
424e10ffbc2SMatthew Dillon value, "",
425e10ffbc2SMatthew Dillon 2,
426e10ffbc2SMatthew Dillon HN_FRACTIONAL |
427e10ffbc2SMatthew Dillon HN_NOSPACE);
428e10ffbc2SMatthew Dillon }
429e10ffbc2SMatthew Dillon sprintf(ret,"%8.8s", buf);
430e10ffbc2SMatthew Dillon break;
431e10ffbc2SMatthew Dillon default:
432e10ffbc2SMatthew Dillon sprintf(ret,"%s"," ");
433e10ffbc2SMatthew Dillon break;
434e10ffbc2SMatthew Dillon }
435e10ffbc2SMatthew Dillon }
436e10ffbc2SMatthew Dillon
437e10ffbc2SMatthew Dillon static
438f089ea9cSAntonio Huete Jimenez const char *
get_influx_series(const char * val)439f089ea9cSAntonio Huete Jimenez get_influx_series(const char *val)
440f089ea9cSAntonio Huete Jimenez {
441f089ea9cSAntonio Huete Jimenez /* cpu values (user, idle, syst) */
442f089ea9cSAntonio Huete Jimenez if ((strncmp("user", val, 8) == 0) ||
443f089ea9cSAntonio Huete Jimenez (strncmp("idle", val, 8) == 0 ) ||
444f089ea9cSAntonio Huete Jimenez (strncmp("syst", val, 8) == 0))
445f089ea9cSAntonio Huete Jimenez return "cpu_value";
446f089ea9cSAntonio Huete Jimenez
447f089ea9cSAntonio Huete Jimenez /* load value (load) */
448f089ea9cSAntonio Huete Jimenez if (strncmp("load", val, 8) == 0)
449f089ea9cSAntonio Huete Jimenez return "load_value";
450f089ea9cSAntonio Huete Jimenez
451f089ea9cSAntonio Huete Jimenez /* swap values (swapuse, swapano, swapcac) */
452f089ea9cSAntonio Huete Jimenez if ((strncmp("swapuse", val, 8) == 0) ||
453f089ea9cSAntonio Huete Jimenez (strncmp("swapano", val, 8) == 0 ) ||
454f089ea9cSAntonio Huete Jimenez (strncmp("swapcac", val, 8) == 0))
455f089ea9cSAntonio Huete Jimenez return "swap_value";
456f089ea9cSAntonio Huete Jimenez
457f089ea9cSAntonio Huete Jimenez /* vm values (fault, cow, zfill) */
458f089ea9cSAntonio Huete Jimenez if ((strncmp("fault", val, 8) == 0) ||
459f089ea9cSAntonio Huete Jimenez (strncmp("cow", val, 8) == 0 ) ||
460f089ea9cSAntonio Huete Jimenez (strncmp("zfill", val, 8) == 0))
461f089ea9cSAntonio Huete Jimenez return "vm_value";
462f089ea9cSAntonio Huete Jimenez
463f089ea9cSAntonio Huete Jimenez /* memory values (fault, cow, zfill) */
464f089ea9cSAntonio Huete Jimenez if ((strncmp("cache", val, 8) == 0) ||
465f089ea9cSAntonio Huete Jimenez (strncmp("inact", val, 8) == 0 ) ||
466f089ea9cSAntonio Huete Jimenez (strncmp("act", val, 8) == 0) ||
467f089ea9cSAntonio Huete Jimenez (strncmp("wired", val, 8) == 0) ||
468f089ea9cSAntonio Huete Jimenez (strncmp("free", val, 8) == 0))
469f089ea9cSAntonio Huete Jimenez return "memory_value";
470f089ea9cSAntonio Huete Jimenez
471f089ea9cSAntonio Huete Jimenez /* misc values (syscalls, nlookup, intr, ipi, timer) */
472f089ea9cSAntonio Huete Jimenez if ((strncmp("syscalls", val, 8) == 0) ||
473f089ea9cSAntonio Huete Jimenez (strncmp("nlookup", val, 8) == 0 ) ||
474f089ea9cSAntonio Huete Jimenez (strncmp("intr", val, 8) == 0) ||
475f089ea9cSAntonio Huete Jimenez (strncmp("ipi", val, 8) == 0) ||
476f089ea9cSAntonio Huete Jimenez (strncmp("timer", val, 8) == 0))
477f089ea9cSAntonio Huete Jimenez return "misc_value";
478f089ea9cSAntonio Huete Jimenez
479f089ea9cSAntonio Huete Jimenez return "misc_value";
480f089ea9cSAntonio Huete Jimenez
481f089ea9cSAntonio Huete Jimenez }
482f089ea9cSAntonio Huete Jimenez
483f089ea9cSAntonio Huete Jimenez static
484f089ea9cSAntonio Huete Jimenez void
dump_influxdb(kcollect_t * ary,size_t count,size_t total_count,__unused const char * display_fmt)485f089ea9cSAntonio Huete Jimenez dump_influxdb(kcollect_t *ary, size_t count, size_t total_count,
486f089ea9cSAntonio Huete Jimenez __unused const char* display_fmt)
487f089ea9cSAntonio Huete Jimenez {
488f089ea9cSAntonio Huete Jimenez int j;
489f089ea9cSAntonio Huete Jimenez int i;
490f089ea9cSAntonio Huete Jimenez uintmax_t value;
491f089ea9cSAntonio Huete Jimenez size_t ts_nsec;
492f089ea9cSAntonio Huete Jimenez char hostname[HOST_NAME_MAX];
493f089ea9cSAntonio Huete Jimenez char *colname;
494f089ea9cSAntonio Huete Jimenez
495a657b521SAntonio Huete Jimenez if (LoadedFromDB) {
496a657b521SAntonio Huete Jimenez snprintf(hostname, HOST_NAME_MAX, "%s", (char *)ary[2].data);
497a657b521SAntonio Huete Jimenez } else {
498f089ea9cSAntonio Huete Jimenez if (gethostname(hostname, HOST_NAME_MAX) != 0) {
499f089ea9cSAntonio Huete Jimenez fprintf(stderr, "Failed to get hostname\n");
500f089ea9cSAntonio Huete Jimenez exit(1);
501f089ea9cSAntonio Huete Jimenez }
502a657b521SAntonio Huete Jimenez }
503f089ea9cSAntonio Huete Jimenez
504f8220a21SMatthew Dillon for (i = count - 1; i >= DATA_BASE_INDEX; --i) {
505f089ea9cSAntonio Huete Jimenez /*
506f089ea9cSAntonio Huete Jimenez * Timestamp
507f089ea9cSAntonio Huete Jimenez */
508f089ea9cSAntonio Huete Jimenez ts_nsec = (ary[i].realtime.tv_sec
509f089ea9cSAntonio Huete Jimenez * 1000 /* ms */
510f089ea9cSAntonio Huete Jimenez * 1000 /* usec */
511f089ea9cSAntonio Huete Jimenez * 1000 /* nsec */
512f089ea9cSAntonio Huete Jimenez + 123 /* add a few ns since due to missing precision */);
513f089ea9cSAntonio Huete Jimenez ts_nsec += (ary[i].realtime.tv_usec * 1000);
514f089ea9cSAntonio Huete Jimenez
515f089ea9cSAntonio Huete Jimenez for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
516f089ea9cSAntonio Huete Jimenez if (ary[1].data[j] == 0)
517f089ea9cSAntonio Huete Jimenez continue;
518f089ea9cSAntonio Huete Jimenez
519f089ea9cSAntonio Huete Jimenez /*
520f089ea9cSAntonio Huete Jimenez * NOTE: kernel does not have to provide the scale
521f089ea9cSAntonio Huete Jimenez * (that is, the highest likely value), nor
522f089ea9cSAntonio Huete Jimenez * does it make sense in all cases.
523f089ea9cSAntonio Huete Jimenez *
524f089ea9cSAntonio Huete Jimenez * But should we since we're using raw values?
525f089ea9cSAntonio Huete Jimenez */
526f089ea9cSAntonio Huete Jimenez value = ary[i].data[j];
527f089ea9cSAntonio Huete Jimenez colname = (char *)&ary[1].data[j];
528f089ea9cSAntonio Huete Jimenez
529f089ea9cSAntonio Huete Jimenez printf("%s,host=%s,type=%.8s value=%jd %jd\n",
530f089ea9cSAntonio Huete Jimenez get_influx_series(colname),
531f089ea9cSAntonio Huete Jimenez hostname, colname, value, ts_nsec);
532f089ea9cSAntonio Huete Jimenez }
533f089ea9cSAntonio Huete Jimenez printf("\n");
534f089ea9cSAntonio Huete Jimenez ++total_count;
535f089ea9cSAntonio Huete Jimenez }
536f089ea9cSAntonio Huete Jimenez
537f089ea9cSAntonio Huete Jimenez }
538f089ea9cSAntonio Huete Jimenez
539f089ea9cSAntonio Huete Jimenez static
540e10ffbc2SMatthew Dillon void
dump_text(kcollect_t * ary,size_t count,size_t total_count,const char * display_fmt)541e10ffbc2SMatthew Dillon dump_text(kcollect_t *ary, size_t count, size_t total_count,
542e10ffbc2SMatthew Dillon const char* display_fmt)
543fef9ed17SMatthew Dillon {
544fef9ed17SMatthew Dillon int j;
545fef9ed17SMatthew Dillon int i;
546fef9ed17SMatthew Dillon uintmax_t scale;
547fef9ed17SMatthew Dillon uintmax_t value;
548fef9ed17SMatthew Dillon char fmt;
549e10ffbc2SMatthew Dillon char sbuf[20];
550fef9ed17SMatthew Dillon struct tm *tmv;
551fef9ed17SMatthew Dillon time_t t;
552fef9ed17SMatthew Dillon
553f8220a21SMatthew Dillon for (i = count - 1; i >= DATA_BASE_INDEX; --i) {
554fef9ed17SMatthew Dillon if ((total_count & 15) == 0) {
555e10ffbc2SMatthew Dillon if (!strcmp(display_fmt, DISPLAY_FULL_DATE)) {
556e10ffbc2SMatthew Dillon printf("%20s", "timestamp ");
557c5741af1SMatthew Dillon } else {
558fef9ed17SMatthew Dillon printf("%8.8s", "time");
559e10ffbc2SMatthew Dillon }
560f6aeec64SMatthew Dillon for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
561f6aeec64SMatthew Dillon if (ary[1].data[j]) {
562fef9ed17SMatthew Dillon printf(" %8.8s",
563fef9ed17SMatthew Dillon (char *)&ary[1].data[j]);
564f6aeec64SMatthew Dillon }
565f6aeec64SMatthew Dillon }
566f6aeec64SMatthew Dillon printf("\n");
567fef9ed17SMatthew Dillon }
568f6aeec64SMatthew Dillon
569fef9ed17SMatthew Dillon /*
570fef9ed17SMatthew Dillon * Timestamp
571fef9ed17SMatthew Dillon */
572fef9ed17SMatthew Dillon t = ary[i].realtime.tv_sec;
573f9c8e4acSMatthew Dillon if (UseGMT)
574fef9ed17SMatthew Dillon tmv = gmtime(&t);
575fef9ed17SMatthew Dillon else
576fef9ed17SMatthew Dillon tmv = localtime(&t);
577e10ffbc2SMatthew Dillon strftime(sbuf, sizeof(sbuf), display_fmt, tmv);
578e10ffbc2SMatthew Dillon printf("%8s", sbuf);
579fef9ed17SMatthew Dillon
580f6aeec64SMatthew Dillon for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
581f6aeec64SMatthew Dillon if (ary[1].data[j] == 0)
582f6aeec64SMatthew Dillon continue;
583fef9ed17SMatthew Dillon
584fef9ed17SMatthew Dillon /*
585fef9ed17SMatthew Dillon * NOTE: kernel does not have to provide the scale
586fef9ed17SMatthew Dillon * (that is, the highest likely value), nor
587fef9ed17SMatthew Dillon * does it make sense in all cases.
588fef9ed17SMatthew Dillon *
589fef9ed17SMatthew Dillon * Example scale - kernel provides total amount
590fef9ed17SMatthew Dillon * of memory available for memory related
591fef9ed17SMatthew Dillon * statistics in the scale field.
592fef9ed17SMatthew Dillon */
593f6aeec64SMatthew Dillon value = ary[i].data[j];
594f6aeec64SMatthew Dillon scale = KCOLLECT_GETSCALE(ary[0].data[j]);
595f6aeec64SMatthew Dillon fmt = KCOLLECT_GETFMT(ary[0].data[j]);
596fef9ed17SMatthew Dillon
597fef9ed17SMatthew Dillon printf(" ");
598fef9ed17SMatthew Dillon
599e10ffbc2SMatthew Dillon format_output(value, fmt, scale, sbuf);
600e10ffbc2SMatthew Dillon printf("%s",sbuf);
601f6aeec64SMatthew Dillon }
602c5741af1SMatthew Dillon
603f6aeec64SMatthew Dillon printf("\n");
604fef9ed17SMatthew Dillon ++total_count;
605f6aeec64SMatthew Dillon }
606fef9ed17SMatthew Dillon }
607fef9ed17SMatthew Dillon
608c5741af1SMatthew Dillon /* restores the DBM database header records to current machine */
609c5741af1SMatthew Dillon static
610c5741af1SMatthew Dillon void
restore_headers(kcollect_t * ary,const char * datafile)611c5741af1SMatthew Dillon restore_headers(kcollect_t *ary, const char *datafile)
612c5741af1SMatthew Dillon {
613c5741af1SMatthew Dillon DBM *db;
614f8220a21SMatthew Dillon char hdr[32];
615c5741af1SMatthew Dillon datum key, value;
616f8220a21SMatthew Dillon int i;
617c5741af1SMatthew Dillon
618c5741af1SMatthew Dillon db = dbm_open(datafile, (O_RDWR),
619c5741af1SMatthew Dillon (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP));
620c5741af1SMatthew Dillon
621c5741af1SMatthew Dillon if (db == NULL) {
622c5741af1SMatthew Dillon switch (errno) {
623c5741af1SMatthew Dillon case EACCES:
624c5741af1SMatthew Dillon fprintf(stderr,
625c5741af1SMatthew Dillon "[ERR] database file \"%s\" is read-only, "
626c5741af1SMatthew Dillon "check permissions. (%i)\n",
627c5741af1SMatthew Dillon datafile, errno);
628c5741af1SMatthew Dillon break;
629c5741af1SMatthew Dillon default:
630c5741af1SMatthew Dillon fprintf(stderr,
631c5741af1SMatthew Dillon "[ERR] opening our database file \"%s\" "
632c5741af1SMatthew Dillon "produced an error. (%i)\n",
633c5741af1SMatthew Dillon datafile, errno);
634c5741af1SMatthew Dillon }
635c5741af1SMatthew Dillon exit(EXIT_FAILURE);
636c5741af1SMatthew Dillon } else {
637f8220a21SMatthew Dillon for (i = 0; i < DATA_BASE_INDEX; ++i) {
638f8220a21SMatthew Dillon snprintf(hdr, sizeof(hdr), "%s%d", HDR_BASE, i);
639f8220a21SMatthew Dillon key.dptr = hdr;
640f8220a21SMatthew Dillon key.dsize = strlen(key.dptr) + 1;
641f8220a21SMatthew Dillon value.dptr = &ary[i].data;
642c5741af1SMatthew Dillon value.dsize = sizeof(uint64_t) * KCOLLECT_ENTRIES;
643c5741af1SMatthew Dillon if (dbm_store(db,key,value,DBM_REPLACE) == -1) {
644c5741af1SMatthew Dillon fprintf(stderr,
645c5741af1SMatthew Dillon "[ERR] error storing the value in "
646c5741af1SMatthew Dillon "the database file \"%s\" (%i)\n",
647c5741af1SMatthew Dillon datafile, errno);
648c5741af1SMatthew Dillon dbm_close(db);
649c5741af1SMatthew Dillon exit(EXIT_FAILURE);
650c5741af1SMatthew Dillon }
651c5741af1SMatthew Dillon }
652c5741af1SMatthew Dillon }
653c5741af1SMatthew Dillon dbm_close(db);
654c5741af1SMatthew Dillon }
655c5741af1SMatthew Dillon
656c5741af1SMatthew Dillon
657e10ffbc2SMatthew Dillon /*
658e10ffbc2SMatthew Dillon * Store the array of kcollect_t records in a dbm db database,
659e10ffbc2SMatthew Dillon * path passed in datafile
660e10ffbc2SMatthew Dillon */
661e10ffbc2SMatthew Dillon static
662e10ffbc2SMatthew Dillon void
dump_dbm(kcollect_t * ary,size_t count,const char * datafile)663e10ffbc2SMatthew Dillon dump_dbm(kcollect_t *ary, size_t count, const char *datafile)
664fef9ed17SMatthew Dillon {
665e10ffbc2SMatthew Dillon DBM * db;
666e10ffbc2SMatthew Dillon
667e10ffbc2SMatthew Dillon db = dbm_open(datafile, (O_RDWR | O_CREAT),
668e10ffbc2SMatthew Dillon (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP));
669e10ffbc2SMatthew Dillon if (db == NULL) {
670e10ffbc2SMatthew Dillon switch (errno) {
671e10ffbc2SMatthew Dillon case EACCES:
672e10ffbc2SMatthew Dillon fprintf(stderr,
673e10ffbc2SMatthew Dillon "[ERR] database file \"%s\" is read-only, "
674e10ffbc2SMatthew Dillon "check permissions. (%i)\n",
675e10ffbc2SMatthew Dillon datafile, errno);
676e10ffbc2SMatthew Dillon break;
677e10ffbc2SMatthew Dillon default:
678e10ffbc2SMatthew Dillon fprintf(stderr,
679e10ffbc2SMatthew Dillon "[ERR] opening our database file \"%s\" "
680e10ffbc2SMatthew Dillon "produced an error. (%i)\n",
681e10ffbc2SMatthew Dillon datafile, errno);
682e10ffbc2SMatthew Dillon }
683e10ffbc2SMatthew Dillon exit(EXIT_FAILURE);
684e10ffbc2SMatthew Dillon } else {
685e10ffbc2SMatthew Dillon struct tm *tmv;
686e10ffbc2SMatthew Dillon char buf[20];
687e10ffbc2SMatthew Dillon datum key;
688e10ffbc2SMatthew Dillon datum value;
689e10ffbc2SMatthew Dillon time_t t;
690e10ffbc2SMatthew Dillon uint i;
691f8220a21SMatthew Dillon int cmd;
692f8220a21SMatthew Dillon char hdr[32];
693e10ffbc2SMatthew Dillon
694f8220a21SMatthew Dillon for (i = 0; i < count; ++i) {
695f8220a21SMatthew Dillon /*
696f8220a21SMatthew Dillon * The first DATA_BASE_INDEX records are special.
697f8220a21SMatthew Dillon */
698f8220a21SMatthew Dillon cmd = DBM_INSERT;
699f8220a21SMatthew Dillon if (i < DATA_BASE_INDEX) {
700f8220a21SMatthew Dillon snprintf(hdr, sizeof(hdr), "%s%d", HDR_BASE, i);
701f8220a21SMatthew Dillon key.dptr = hdr;
702f8220a21SMatthew Dillon key.dsize = strlen(hdr) + 1;
703c5741af1SMatthew Dillon
704f8220a21SMatthew Dillon value = dbm_fetch(db, key);
705f8220a21SMatthew Dillon if (value.dptr == NULL ||
706f8220a21SMatthew Dillon bcmp(ary[i].data, value.dptr,
707f8220a21SMatthew Dillon sizeof(uint64_t) * KCOLLECT_ENTRIES)) {
708f8220a21SMatthew Dillon cmd = DBM_REPLACE;
709f8220a21SMatthew Dillon if (value.dptr != NULL) {
710f8220a21SMatthew Dillon fprintf(stderr,
711f8220a21SMatthew Dillon "Header %d changed "
712f8220a21SMatthew Dillon "in database, "
713f8220a21SMatthew Dillon "updating\n",
714f8220a21SMatthew Dillon i);
715f8220a21SMatthew Dillon }
716f8220a21SMatthew Dillon }
717c5741af1SMatthew Dillon } else {
718e10ffbc2SMatthew Dillon t = ary[i].realtime.tv_sec;
719c5741af1SMatthew Dillon if (LoadedFromDB)
720c5741af1SMatthew Dillon tmv = localtime(&t);
721c5741af1SMatthew Dillon else
722e10ffbc2SMatthew Dillon tmv = gmtime(&t);
723c5741af1SMatthew Dillon strftime(buf, sizeof(buf),
724c5741af1SMatthew Dillon DISPLAY_FULL_DATE, tmv);
725e10ffbc2SMatthew Dillon key.dptr = buf;
726e10ffbc2SMatthew Dillon key.dsize = sizeof(buf);
727c5741af1SMatthew Dillon }
728e10ffbc2SMatthew Dillon value.dptr = ary[i].data;
729c5741af1SMatthew Dillon value.dsize = sizeof(uint64_t) * KCOLLECT_ENTRIES;
730f8220a21SMatthew Dillon if (dbm_store(db, key, value, cmd) == -1) {
731e10ffbc2SMatthew Dillon fprintf(stderr,
732e10ffbc2SMatthew Dillon "[ERR] error storing the value in "
733e10ffbc2SMatthew Dillon "the database file \"%s\" (%i)\n",
734e10ffbc2SMatthew Dillon datafile, errno);
735e10ffbc2SMatthew Dillon dbm_close(db);
736e10ffbc2SMatthew Dillon exit(EXIT_FAILURE);
737e10ffbc2SMatthew Dillon }
738e10ffbc2SMatthew Dillon
739e10ffbc2SMatthew Dillon }
740e10ffbc2SMatthew Dillon dbm_close(db);
741e10ffbc2SMatthew Dillon }
742e10ffbc2SMatthew Dillon }
743e10ffbc2SMatthew Dillon
744e10ffbc2SMatthew Dillon /*
745e10ffbc2SMatthew Dillon * Transform a string (str) matching a format string (fmt) into a unix
746e10ffbc2SMatthew Dillon * timestamp and return it used by load_dbm()
747e10ffbc2SMatthew Dillon */
748e10ffbc2SMatthew Dillon static
749e10ffbc2SMatthew Dillon int
str2unix(const char * str,const char * fmt)750e10ffbc2SMatthew Dillon str2unix(const char* str, const char* fmt){
751e10ffbc2SMatthew Dillon struct tm tm;
752e10ffbc2SMatthew Dillon time_t ts;
753e10ffbc2SMatthew Dillon
754e10ffbc2SMatthew Dillon /*
755e10ffbc2SMatthew Dillon * Reset all the fields because strptime only sets what it
756e10ffbc2SMatthew Dillon * finds, which may lead to undefined members
757e10ffbc2SMatthew Dillon */
758e10ffbc2SMatthew Dillon memset(&tm, 0, sizeof(struct tm));
759e10ffbc2SMatthew Dillon strptime(str, fmt, &tm);
760c5741af1SMatthew Dillon ts = timegm(&tm);
761e10ffbc2SMatthew Dillon
762e10ffbc2SMatthew Dillon return (int)ts;
763e10ffbc2SMatthew Dillon }
764e10ffbc2SMatthew Dillon
765e10ffbc2SMatthew Dillon /*
766e10ffbc2SMatthew Dillon * Sorts the ckollect_t records by time, to put youngest first,
767e10ffbc2SMatthew Dillon * so desc by timestamp used by load_dbm()
768e10ffbc2SMatthew Dillon */
769e10ffbc2SMatthew Dillon static
770e10ffbc2SMatthew Dillon int
rec_comparator(const void * c1,const void * c2)771e10ffbc2SMatthew Dillon rec_comparator(const void *c1, const void *c2)
772e10ffbc2SMatthew Dillon {
773e10ffbc2SMatthew Dillon const kcollect_t *k1 = (const kcollect_t*)c1;
774e10ffbc2SMatthew Dillon const kcollect_t *k2 = (const kcollect_t*)c2;
775e10ffbc2SMatthew Dillon
776e10ffbc2SMatthew Dillon if (k1->realtime.tv_sec < k2->realtime.tv_sec)
777e10ffbc2SMatthew Dillon return -1;
778e10ffbc2SMatthew Dillon if (k1->realtime.tv_sec > k2->realtime.tv_sec)
779e10ffbc2SMatthew Dillon return 1;
780e10ffbc2SMatthew Dillon return 0;
781e10ffbc2SMatthew Dillon }
782e10ffbc2SMatthew Dillon
783e10ffbc2SMatthew Dillon /*
784f8220a21SMatthew Dillon * Normalizes kcollect records from the kernel. We reserve the first
785f8220a21SMatthew Dillon * DATA_BASE_INDEX elements for specific headers.
786f8220a21SMatthew Dillon */
787f8220a21SMatthew Dillon static
788f8220a21SMatthew Dillon kcollect_t *
load_kernel(kcollect_t * scaleid,kcollect_t * ary,size_t * counter)789f8220a21SMatthew Dillon load_kernel(kcollect_t *scaleid, kcollect_t *ary, size_t *counter)
790f8220a21SMatthew Dillon {
791f8220a21SMatthew Dillon ary -= DATA_BASE_INDEX;
792f8220a21SMatthew Dillon bzero(ary, sizeof(*ary) * DATA_BASE_INDEX);
793f8220a21SMatthew Dillon ary[0] = scaleid[0];
794f8220a21SMatthew Dillon ary[1] = scaleid[1];
795f8220a21SMatthew Dillon
796f8220a21SMatthew Dillon /*
797f8220a21SMatthew Dillon * Add host field
798f8220a21SMatthew Dillon */
799f8220a21SMatthew Dillon gethostname((char *)ary[2].data,
800f8220a21SMatthew Dillon sizeof(uint64_t) * KCOLLECT_ENTRIES - 1);
801f8220a21SMatthew Dillon
802f8220a21SMatthew Dillon *counter += DATA_BASE_INDEX;
803f8220a21SMatthew Dillon
804f8220a21SMatthew Dillon return ary;
805f8220a21SMatthew Dillon }
806f8220a21SMatthew Dillon
807f8220a21SMatthew Dillon /*
808f8220a21SMatthew Dillon * Loads the kcollect records from a dbm DB database specified in datafile.
809e10ffbc2SMatthew Dillon * returns the resulting array in ret_ary and the array counter in counter
810e10ffbc2SMatthew Dillon */
811e10ffbc2SMatthew Dillon static
812e10ffbc2SMatthew Dillon void
load_dbm(const char * datafile,kcollect_t ** ret_ary,size_t * counter)813c5741af1SMatthew Dillon load_dbm(const char* datafile, kcollect_t **ret_ary,
814e10ffbc2SMatthew Dillon size_t *counter)
815e10ffbc2SMatthew Dillon {
816f8220a21SMatthew Dillon char hostname[sizeof(uint64_t) * KCOLLECT_ENTRIES];
817e10ffbc2SMatthew Dillon DBM *db = dbm_open(datafile,(O_RDONLY),(S_IRUSR|S_IRGRP));
818e10ffbc2SMatthew Dillon datum key;
819e10ffbc2SMatthew Dillon datum value;
820f8220a21SMatthew Dillon size_t recCounter = DATA_BASE_INDEX;
821c5741af1SMatthew Dillon int headersFound = 0;
822f8220a21SMatthew Dillon uint c;
823f8220a21SMatthew Dillon uint sc;
824e10ffbc2SMatthew Dillon
825e10ffbc2SMatthew Dillon if (db == NULL) {
826e10ffbc2SMatthew Dillon fprintf(stderr,
827e10ffbc2SMatthew Dillon "[ERR] opening our database \"%s\" produced "
828e10ffbc2SMatthew Dillon "an error! (%i)\n",
829e10ffbc2SMatthew Dillon datafile, errno);
830e10ffbc2SMatthew Dillon exit(EXIT_FAILURE);
831f8220a21SMatthew Dillon }
832f8220a21SMatthew Dillon
833e10ffbc2SMatthew Dillon /* counting loop */
834e10ffbc2SMatthew Dillon for (key = dbm_firstkey(db); key.dptr; key = dbm_nextkey(db)) {
835e10ffbc2SMatthew Dillon value = dbm_fetch(db, key);
836f8220a21SMatthew Dillon if (value.dptr == NULL)
837f8220a21SMatthew Dillon continue;
838f8220a21SMatthew Dillon if (strncmp(key.dptr, HDR_BASE, HDR_STRLEN) == 0)
839f8220a21SMatthew Dillon continue;
840e10ffbc2SMatthew Dillon recCounter++;
841e10ffbc2SMatthew Dillon }
842e10ffbc2SMatthew Dillon
843e10ffbc2SMatthew Dillon /* with the count allocate enough memory */
844e10ffbc2SMatthew Dillon if (*ret_ary)
845e10ffbc2SMatthew Dillon free(*ret_ary);
846f8220a21SMatthew Dillon
847c5741af1SMatthew Dillon *ret_ary = malloc(sizeof(kcollect_t) * recCounter);
848f8220a21SMatthew Dillon
849e10ffbc2SMatthew Dillon if (*ret_ary == NULL) {
850e10ffbc2SMatthew Dillon fprintf(stderr,
851e10ffbc2SMatthew Dillon "[ERR] failed to allocate enough memory to "
852e10ffbc2SMatthew Dillon "hold the database! Aborting.\n");
853e10ffbc2SMatthew Dillon dbm_close(db);
854e10ffbc2SMatthew Dillon exit(EXIT_FAILURE);
855f8220a21SMatthew Dillon }
856f8220a21SMatthew Dillon bzero(*ret_ary, sizeof(kcollect_t) * recCounter);
857f8220a21SMatthew Dillon
858e10ffbc2SMatthew Dillon /*
859e10ffbc2SMatthew Dillon * Actual data retrieval but only of recCounter
860e10ffbc2SMatthew Dillon * records
861e10ffbc2SMatthew Dillon */
862f8220a21SMatthew Dillon c = DATA_BASE_INDEX;
863e10ffbc2SMatthew Dillon key = dbm_firstkey(db);
864e10ffbc2SMatthew Dillon while (key.dptr && c < recCounter) {
865e10ffbc2SMatthew Dillon value = dbm_fetch(db, key);
866f8220a21SMatthew Dillon if (value.dptr == NULL) {
867f8220a21SMatthew Dillon key = dbm_nextkey(db);
868f8220a21SMatthew Dillon continue;
869c5741af1SMatthew Dillon }
870f8220a21SMatthew Dillon if (!strncmp(key.dptr, HDR_BASE, HDR_STRLEN)) {
871f8220a21SMatthew Dillon /*
872f8220a21SMatthew Dillon * Ignore unsupported header indices
873f8220a21SMatthew Dillon */
874f8220a21SMatthew Dillon sc = strtoul((char *)key.dptr +
875f8220a21SMatthew Dillon HDR_STRLEN, NULL, 10);
876f8220a21SMatthew Dillon if (sc >= DATA_BASE_INDEX) {
877f8220a21SMatthew Dillon key = dbm_nextkey(db);
878f8220a21SMatthew Dillon continue;
879c5741af1SMatthew Dillon }
880f8220a21SMatthew Dillon headersFound |= 1 << sc;
881f8220a21SMatthew Dillon } else {
882f8220a21SMatthew Dillon sc = c++;
883c5741af1SMatthew Dillon (*ret_ary)[sc].realtime.tv_sec =
884e10ffbc2SMatthew Dillon str2unix(key.dptr,
885e10ffbc2SMatthew Dillon DISPLAY_FULL_DATE);
886e10ffbc2SMatthew Dillon }
887f8220a21SMatthew Dillon memcpy((*ret_ary)[sc].data,
888f8220a21SMatthew Dillon value.dptr,
889f8220a21SMatthew Dillon sizeof(uint64_t) * KCOLLECT_ENTRIES);
890f8220a21SMatthew Dillon
891e10ffbc2SMatthew Dillon key = dbm_nextkey(db);
892e10ffbc2SMatthew Dillon }
893f8220a21SMatthew Dillon
894f8220a21SMatthew Dillon /*
895f8220a21SMatthew Dillon * HEADER2 - hostname (must match)
896f8220a21SMatthew Dillon */
897f8220a21SMatthew Dillon if ((headersFound & 4) && *(char *)(*ret_ary)[2].data == 0)
898f8220a21SMatthew Dillon headersFound &= ~4;
899f8220a21SMatthew Dillon
900f8220a21SMatthew Dillon bzero(hostname, sizeof(hostname));
901f8220a21SMatthew Dillon gethostname(hostname, sizeof(hostname) - 1);
902f8220a21SMatthew Dillon
903f8220a21SMatthew Dillon if (headersFound & 0x0004) {
904f8220a21SMatthew Dillon if (*(char *)(*ret_ary)[2].data &&
905f8220a21SMatthew Dillon strcmp(hostname, (char *)(*ret_ary)[2].data) != 0) {
906a657b521SAntonio Huete Jimenez HostnameMismatch = 1; /* Disable certain options */
907e10ffbc2SMatthew Dillon }
908e10ffbc2SMatthew Dillon }
909e10ffbc2SMatthew Dillon
910e10ffbc2SMatthew Dillon /*
911c5741af1SMatthew Dillon * Set the counter,
912e10ffbc2SMatthew Dillon * and sort the non-header records.
913e10ffbc2SMatthew Dillon */
914c5741af1SMatthew Dillon *counter = recCounter;
915f8220a21SMatthew Dillon qsort(&(*ret_ary)[DATA_BASE_INDEX], recCounter - DATA_BASE_INDEX,
916f8220a21SMatthew Dillon sizeof(kcollect_t), rec_comparator);
917e10ffbc2SMatthew Dillon dbm_close(db);
918c5741af1SMatthew Dillon
919f8220a21SMatthew Dillon if ((headersFound & 3) != 3) {
920f8220a21SMatthew Dillon fprintf(stderr, "We could not retrieve all necessary headers, "
921f8220a21SMatthew Dillon "might be the database file is corrupted? (%i)\n",
922f8220a21SMatthew Dillon headersFound);
923c5741af1SMatthew Dillon exit(EXIT_FAILURE);
924c5741af1SMatthew Dillon }
925c5741af1SMatthew Dillon LoadedFromDB = 1;
926fef9ed17SMatthew Dillon }
927fef9ed17SMatthew Dillon
928fef9ed17SMatthew Dillon static void
dump_fields(kcollect_t * ary)929fef9ed17SMatthew Dillon dump_fields(kcollect_t *ary)
930fef9ed17SMatthew Dillon {
931fef9ed17SMatthew Dillon int j;
932fef9ed17SMatthew Dillon
933fef9ed17SMatthew Dillon for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
934fef9ed17SMatthew Dillon if (ary[1].data[j] == 0)
935fef9ed17SMatthew Dillon continue;
936fef9ed17SMatthew Dillon printf("%8.8s %c\n",
937fef9ed17SMatthew Dillon (char *)&ary[1].data[j],
938fef9ed17SMatthew Dillon KCOLLECT_GETFMT(ary[0].data[j]));
939fef9ed17SMatthew Dillon }
940f6aeec64SMatthew Dillon }
941f9c8e4acSMatthew Dillon
942f9c8e4acSMatthew Dillon static void
adjust_fields(kcollect_t * ent,const char * fields)943f9c8e4acSMatthew Dillon adjust_fields(kcollect_t *ent, const char *fields)
944f9c8e4acSMatthew Dillon {
945f9c8e4acSMatthew Dillon char *copy = strdup(fields);
946f9c8e4acSMatthew Dillon char *word;
947f9c8e4acSMatthew Dillon int selected[KCOLLECT_ENTRIES];
948f9c8e4acSMatthew Dillon int j;
949f9c8e4acSMatthew Dillon
950f9c8e4acSMatthew Dillon bzero(selected, sizeof(selected));
951f9c8e4acSMatthew Dillon
952f9c8e4acSMatthew Dillon word = strtok(copy, ", \t");
953f9c8e4acSMatthew Dillon while (word) {
954f9c8e4acSMatthew Dillon for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
955f9c8e4acSMatthew Dillon if (strncmp(word, (char *)&ent->data[j], 8) == 0) {
956f9c8e4acSMatthew Dillon selected[j] = 1;
957f9c8e4acSMatthew Dillon break;
958f9c8e4acSMatthew Dillon }
959f9c8e4acSMatthew Dillon }
960f9c8e4acSMatthew Dillon word = strtok(NULL, ", \t");
961f9c8e4acSMatthew Dillon }
962f9c8e4acSMatthew Dillon free(copy);
963f9c8e4acSMatthew Dillon for (j = 0; j < KCOLLECT_ENTRIES; ++j) {
964f9c8e4acSMatthew Dillon if (!selected[j])
965f9c8e4acSMatthew Dillon ent->data[j] = 0;
966f9c8e4acSMatthew Dillon }
967f9c8e4acSMatthew Dillon }
968