1 /*	$OpenBSD: output-json.c,v 1.22 2021/11/04 11:32:55 claudio Exp $ */
2 /*
3  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <time.h>
21 #include <netdb.h>
22 
23 #include "extern.h"
24 
25 static int
26 outputheader_json(FILE *out, struct stats *st)
27 {
28 	char		hn[NI_MAXHOST], tbuf[26];
29 	struct tm	*tp;
30 	time_t		t;
31 	size_t		i;
32 
33 	time(&t);
34 	setenv("TZ", "UTC", 1);
35 	tp = localtime(&t);
36 	strftime(tbuf, sizeof tbuf, "%FT%TZ", tp);
37 
38 	gethostname(hn, sizeof hn);
39 
40 	if (fprintf(out,
41 	    "{\n\t\"metadata\": {\n"
42 	    "\t\t\"buildmachine\": \"%s\",\n"
43 	    "\t\t\"buildtime\": \"%s\",\n"
44 	    "\t\t\"elapsedtime\": \"%lld\",\n"
45 	    "\t\t\"usertime\": \"%lld\",\n"
46 	    "\t\t\"systemtime\": \"%lld\",\n"
47 	    "\t\t\"roas\": %zu,\n"
48 	    "\t\t\"failedroas\": %zu,\n"
49 	    "\t\t\"invalidroas\": %zu,\n"
50 	    "\t\t\"bgpsec_pubkeys\": %zu,\n"
51 	    "\t\t\"certificates\": %zu,\n"
52 	    "\t\t\"invalidcertificates\": %zu,\n"
53 	    "\t\t\"tals\": %zu,\n"
54 	    "\t\t\"invalidtals\": %zu,\n"
55 	    "\t\t\"talfiles\": [\n",
56 	    hn, tbuf, (long long)st->elapsed_time.tv_sec,
57 	    (long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec,
58 	    st->roas, st->roas_fail, st->roas_invalid,
59 	    st->brks, st->certs, st->certs_fail,
60 	    st->tals, talsz - st->tals) < 0)
61 		return -1;
62 
63 	for (i = 0; i < talsz; i++) {
64 		if (fprintf(out,
65 		    "\t\t\t\"%s\"%s\n",
66 		    tals[i], i == talsz - 1 ? "" : ",") < 0)
67 			return -1;
68 	}
69 
70 	if (fprintf(out,
71 	    "\t\t],\n"
72 	    "\t\t\"manifests\": %zu,\n"
73 	    "\t\t\"failedmanifests\": %zu,\n"
74 	    "\t\t\"stalemanifests\": %zu,\n"
75 	    "\t\t\"crls\": %zu,\n"
76 	    "\t\t\"gbrs\": %zu,\n"
77 	    "\t\t\"repositories\": %zu,\n"
78 	    "\t\t\"vrps\": %zu,\n"
79 	    "\t\t\"uniquevrps\": %zu,\n"
80 	    "\t\t\"cachedir_del_files\": %zu,\n"
81 	    "\t\t\"cachedir_del_dirs\": %zu\n"
82 	    "\t},\n\n",
83 	    st->mfts, st->mfts_fail, st->mfts_stale,
84 	    st->crls,
85 	    st->gbrs,
86 	    st->repos,
87 	    st->vrps, st->uniqs,
88 	    st->del_files, st->del_dirs) < 0)
89 		return -1;
90 	return 0;
91 }
92 
93 int
94 output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
95     struct stats *st)
96 {
97 	char		 buf[64];
98 	struct vrp	*v;
99 	struct brk	*b;
100 	int		 first = 1;
101 
102 	if (outputheader_json(out, st) < 0)
103 		return -1;
104 
105 	if (fprintf(out, "\t\"roas\": [\n") < 0)
106 		return -1;
107 
108 	RB_FOREACH(v, vrp_tree, vrps) {
109 		if (!first) {
110 			if (fprintf(out, ",\n") < 0)
111 				return -1;
112 		}
113 		first = 0;
114 
115 		ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
116 
117 		if (fprintf(out, "\t\t{ \"asn\": %u, \"prefix\": \"%s\", "
118 		    "\"maxLength\": %u, \"ta\": \"%s\", \"expires\": %lld }",
119 		    v->asid, buf, v->maxlength, taldescs[v->talid],
120 		    (long long)v->expires)
121 		    < 0)
122 			return -1;
123 	}
124 
125 	if (fprintf(out, "\n\t],\n\n\t\"bgpsec_keys\": [\n") < 0)
126 		return -1;
127 
128 	first = 1;
129 	RB_FOREACH(b, brk_tree, brks) {
130 		if (!first) {
131 			if (fprintf(out, ",\n") < 0)
132 				return -1;
133 		}
134 		first = 0;
135 
136 		if (fprintf(out, "\t\t{ \"asn\": %u, \"ski\": \"%s\", "
137 		    "\"pubkey\": \"%s\", \"ta\": \"%s\", \"expires\": %lld }",
138 		    b->asid, b->ski, b->pubkey, taldescs[b->talid],
139 		    (long long)b->expires) < 0)
140 			return -1;
141 	}
142 
143 	if (fprintf(out, "\n\t]\n}\n") < 0)
144 		return -1;
145 	return 0;
146 }
147