xref: /dragonfly/usr.bin/kcollect/kcollect.c (revision d50f9ae3)
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