gdp / apps / gdp-log-view.c @ master
History | View | Annotate | Download (11.9 KB)
1 |
/* vim: set ai sw=4 sts=4 ts=4 : */
|
---|---|
2 |
|
3 |
/***********************************************************************
|
4 |
** ----- BEGIN LICENSE BLOCK -----
|
5 |
** Applications for the Global Data Plane
|
6 |
** From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
|
7 |
**
|
8 |
** Copyright (c) 2015-2019, Regents of the University of California.
|
9 |
** All rights reserved.
|
10 |
**
|
11 |
** Permission is hereby granted, without written agreement and without
|
12 |
** license or royalty fees, to use, copy, modify, and distribute this
|
13 |
** software and its documentation for any purpose, provided that the above
|
14 |
** copyright notice and the following two paragraphs appear in all copies
|
15 |
** of this software.
|
16 |
**
|
17 |
** IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
18 |
** SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
|
19 |
** PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
|
20 |
** EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21 |
**
|
22 |
** REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
23 |
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
24 |
** FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
|
25 |
** IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
|
26 |
** OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
27 |
** OR MODIFICATIONS.
|
28 |
** ----- END LICENSE BLOCK -----
|
29 |
***********************************************************************/
|
30 |
|
31 |
#include <ep/ep.h> |
32 |
#include <ep/ep_dbg.h> |
33 |
#include <ep/ep_hash.h> |
34 |
#include <ep/ep_hexdump.h> |
35 |
#include <ep/ep_net.h> |
36 |
#include <ep/ep_prflags.h> |
37 |
#include <ep/ep_string.h> |
38 |
#include <ep/ep_time.h> |
39 |
#include <ep/ep_xlate.h> |
40 |
#include <gdp/gdp.h> |
41 |
|
42 |
#include <dirent.h> |
43 |
#include <errno.h> |
44 |
#include <getopt.h> |
45 |
#include <inttypes.h> |
46 |
#include <stddef.h> |
47 |
#include <stdint.h> |
48 |
#include <stdio.h> |
49 |
#include <string.h> |
50 |
#include <sysexits.h> |
51 |
#include <time.h> |
52 |
#include <sys/stat.h> |
53 |
|
54 |
// leverage existing code (this is a hack!)
|
55 |
#define GDP_LOG_VIEW 1 |
56 |
#define Dbg DbgLogdSqlite
|
57 |
#include "../gdplogd/logd_sqlite.c" |
58 |
#undef Dbg
|
59 |
#include "../gdp/gdp_hongd.h" |
60 |
|
61 |
|
62 |
/*
|
63 |
** GDP-LOG-VIEW --- display raw on-disk storage
|
64 |
**
|
65 |
** Not for user consumption.
|
66 |
** This does peek into private header files.
|
67 |
*/
|
68 |
|
69 |
static EP_DBG Dbg = EP_DBG_INIT("gdp-log-view", "Dump GDP logs for debugging"); |
70 |
|
71 |
|
72 |
#define LIST_NO_METADATA 0x00000001 // only list logs with no metadata |
73 |
|
74 |
|
75 |
void
|
76 |
pr_pubkey(uint32_t md_id, uint32_t md_len, uint8_t *mdata, int plev)
|
77 |
{ |
78 |
{ |
79 |
int keylen = mdata[2] << 8 | mdata[3]; |
80 |
printf("\tmd_alg %s (%d), keytype %s (%d), keylen %d\n",
|
81 |
ep_crypto_md_alg_name(mdata[0]), mdata[0], |
82 |
ep_crypto_keytype_name(mdata[1]), mdata[1], |
83 |
keylen); |
84 |
} |
85 |
if (plev > 1) |
86 |
{ |
87 |
EP_CRYPTO_KEY *key; |
88 |
|
89 |
key = ep_crypto_key_read_mem(mdata + 4,
|
90 |
md_len - 4,
|
91 |
EP_CRYPTO_KEYFORM_DER, |
92 |
EP_CRYPTO_F_PUBLIC); |
93 |
ep_crypto_key_print(key, stdout, EP_CRYPTO_F_PUBLIC); |
94 |
ep_crypto_key_free(key); |
95 |
} |
96 |
if (plev >= 4) |
97 |
ep_hexdump(mdata + 4, md_len - 4, stdout, EP_HEXDUMP_HEX, 0); |
98 |
} |
99 |
|
100 |
|
101 |
EP_STAT |
102 |
pr_verbose_metadata(gdp_gob_t *gob, int plev)
|
103 |
{ |
104 |
gdp_md_t *md = gob->gob_md; |
105 |
|
106 |
printf("\n --------------- Metadata ---------------\n");
|
107 |
if (md == NULL) |
108 |
{ |
109 |
fprintf(stderr, "%s: no metadata\n", gob->pname);
|
110 |
return EP_STAT_ERROR; //XXX something more specific? |
111 |
} |
112 |
|
113 |
int mdx = 0; |
114 |
for (;; ++mdx)
|
115 |
{ |
116 |
gdp_md_id_t md_id; |
117 |
size_t md_len; |
118 |
const uint8_t *md_data;
|
119 |
EP_STAT estat; |
120 |
|
121 |
estat = gdp_md_get(md, mdx, &md_id, &md_len, (const void **) &md_data); |
122 |
EP_STAT_CHECK(estat, break);
|
123 |
|
124 |
uint8_t mdata[md_len + 1]; // +1 for null-terminator |
125 |
memcpy(mdata, md_data, md_len); |
126 |
mdata[md_len] = '\0';
|
127 |
|
128 |
if (plev > 1) |
129 |
{ |
130 |
int printtype = 0; |
131 |
fprintf(stdout, |
132 |
"\nMetadata entry %d: name 0x%08" PRIx32
|
133 |
", len %zd",
|
134 |
mdx, md_id, md_len); |
135 |
switch (md_id)
|
136 |
{ |
137 |
case GDP_MD_XID:
|
138 |
printf(" (external id)\n");
|
139 |
printtype = 1;
|
140 |
break;
|
141 |
|
142 |
case GDP_MD_NONCE:
|
143 |
printf(" (nonce)\n ");
|
144 |
ep_hexdump(mdata, md_len, stdout, EP_HEXDUMP_TERSE, 0);
|
145 |
printtype = 0;
|
146 |
break;
|
147 |
|
148 |
case GDP_MD_CTIME:
|
149 |
printf(" (creation time)\n");
|
150 |
printtype = 1;
|
151 |
break;
|
152 |
|
153 |
case GDP_MD_EXPIRE:
|
154 |
printf(" (expiration time)\n");
|
155 |
printtype = 1;
|
156 |
break;
|
157 |
|
158 |
case GDP_MD_CREATOR:
|
159 |
printf(" (creator)\n");
|
160 |
printtype = 1;
|
161 |
break;
|
162 |
|
163 |
case GDP_MD_PUBKEY:
|
164 |
printf(" (public key, deprecated)\n");
|
165 |
pr_pubkey(md_id, md_len, mdata, plev); |
166 |
break;
|
167 |
|
168 |
case GDP_MD_OWNERPUBKEY:
|
169 |
printf(" (owner public key)\n");
|
170 |
pr_pubkey(md_id, md_len, mdata, plev); |
171 |
break;
|
172 |
|
173 |
case GDP_MD_WRITERPUBKEY:
|
174 |
printf(" (writer public key)\n");
|
175 |
pr_pubkey(md_id, md_len, mdata, plev); |
176 |
break;
|
177 |
|
178 |
case GDP_MD_SYNTAX:
|
179 |
printf(" (syntax)\n");
|
180 |
printtype = 1;
|
181 |
break;
|
182 |
|
183 |
case GDP_MD_LOCATION:
|
184 |
printf(" (location)\n");
|
185 |
printtype = 1;
|
186 |
break;
|
187 |
|
188 |
default:
|
189 |
printf("\n");
|
190 |
printtype = 1;
|
191 |
break;
|
192 |
} |
193 |
if (printtype == 1) |
194 |
{ |
195 |
printf("\t%s", EpChar->lquote);
|
196 |
ep_xlate_out(mdata, md_len, |
197 |
stdout, "", EP_XLATE_PLUS | EP_XLATE_NPRINT);
|
198 |
fprintf(stdout, "%s\n", EpChar->rquote);
|
199 |
} |
200 |
else if (printtype == 2) |
201 |
{ |
202 |
ep_hexdump(mdata, md_len, stdout, EP_HEXDUMP_HEX, 0);
|
203 |
} |
204 |
else if (printtype == 3) |
205 |
{ |
206 |
ep_hexdump(mdata, md_len, stdout, EP_HEXDUMP_ASCII, 0);
|
207 |
} |
208 |
} |
209 |
else if (md_id == GDP_MD_XID) |
210 |
{ |
211 |
fprintf(stdout, "\tExternal name: %s\n", mdata);
|
212 |
} |
213 |
else if (md_id == GDP_MD_CREATOR) |
214 |
{ |
215 |
fprintf(stdout, "\tCreator: %s\n", mdata);
|
216 |
} |
217 |
else if (md_id == GDP_MD_CTIME) |
218 |
{ |
219 |
fprintf(stdout, "\tCreation Time: %s\n", mdata);
|
220 |
} |
221 |
|
222 |
if (plev >= 4) |
223 |
{ |
224 |
ep_hexdump(mdata, md_len, stdout, EP_HEXDUMP_ASCII, 0);
|
225 |
} |
226 |
} |
227 |
return EP_STAT_OK;
|
228 |
} |
229 |
|
230 |
|
231 |
static EP_STAT
|
232 |
show_rec(EP_STAT estat, gdp_datum_t *datum, gdp_result_ctx_t *ctx) |
233 |
{ |
234 |
uintptr_t ptrint = (uintptr_t) ctx; |
235 |
uint32_t pflags = (uint32_t) ptrint; |
236 |
if (EP_STAT_IS_SAME(estat, GDP_STAT_ACK_CONTENT))
|
237 |
gdp_datum_print(datum, stdout, pflags); |
238 |
else
|
239 |
ep_app_message(estat, "show_rec: unknown estat");
|
240 |
return EP_STAT_OK;
|
241 |
} |
242 |
|
243 |
|
244 |
EP_STAT |
245 |
show_log(gdp_name_t log_name, int plev)
|
246 |
{ |
247 |
gdp_pname_t log_pname; |
248 |
gdp_gob_t *gob = NULL;
|
249 |
EP_STAT estat; |
250 |
|
251 |
(void) gdp_printable_name(log_name, log_pname);
|
252 |
if (plev <= 0) |
253 |
{ |
254 |
printf("%s\n", log_pname);
|
255 |
return EP_STAT_OK;
|
256 |
} |
257 |
|
258 |
// create a GOB data structure for this log
|
259 |
estat = _gdp_gob_new(log_name, &gob); |
260 |
EP_STAT_CHECK(estat, return estat);
|
261 |
gob->x = (struct gdp_gob_xtra *) ep_mem_zalloc(sizeof *gob->x); |
262 |
_gdp_gob_lock(gob); |
263 |
|
264 |
// open the on-disk database
|
265 |
estat = sqlite_open(gob); |
266 |
EP_STAT_CHECK(estat, goto fail0);
|
267 |
|
268 |
// figure out what we want to actually print
|
269 |
if (plev == 1) |
270 |
{ |
271 |
// show log name, number of records, external name if known
|
272 |
size_t md_len; |
273 |
const void *md_data; |
274 |
|
275 |
estat = gdp_md_find(gob->gob_md, GDP_MD_XID, &md_len, &md_data); |
276 |
if (!EP_STAT_ISOK(estat))
|
277 |
{ |
278 |
md_data = (void *) "-"; |
279 |
md_len = 1;
|
280 |
} |
281 |
printf("%s %" PRIgdp_recno " %.*s\n", |
282 |
log_pname, gob->nrecs, (int) md_len, (const char *) md_data); |
283 |
goto done;
|
284 |
} |
285 |
if (plev == 2) |
286 |
{ |
287 |
// show log name, nrecs, brief metadata overview
|
288 |
printf("%s %" PRIgdp_recno "\n", log_pname, gob->nrecs); |
289 |
gdp_md_t *md = gob->gob_md; |
290 |
if (md == NULL) |
291 |
goto done;
|
292 |
int mdx = 0; |
293 |
for (;; mdx++)
|
294 |
{ |
295 |
gdp_md_id_t md_id; |
296 |
size_t md_len; |
297 |
const uint8_t *md_data;
|
298 |
|
299 |
estat = gdp_md_get(md, mdx, &md_id, &md_len, (const void **) &md_data); |
300 |
EP_STAT_CHECK(estat, break);
|
301 |
|
302 |
int ptype = 0; |
303 |
const char *ptag = NULL; |
304 |
switch (md_id)
|
305 |
{ |
306 |
case GDP_MD_XID:
|
307 |
ptag = "external id";
|
308 |
ptype = 1;
|
309 |
break;
|
310 |
case GDP_MD_NONCE:
|
311 |
ptag = "nonce";
|
312 |
ptype = 2;
|
313 |
break;
|
314 |
case GDP_MD_CTIME:
|
315 |
ptag = "creation time";
|
316 |
ptype = 1;
|
317 |
break;
|
318 |
case GDP_MD_EXPIRE:
|
319 |
ptag = "expiration time";
|
320 |
ptype = 1;
|
321 |
break;
|
322 |
case GDP_MD_CREATOR:
|
323 |
ptag = "creator";
|
324 |
ptype = 1;
|
325 |
break;
|
326 |
case GDP_MD_PUBKEY:
|
327 |
ptag = "public key, deprecated";
|
328 |
break;
|
329 |
case GDP_MD_OWNERPUBKEY:
|
330 |
ptag = "owner public key";
|
331 |
break;
|
332 |
case GDP_MD_WRITERPUBKEY:
|
333 |
ptag = "writer public key";
|
334 |
break;
|
335 |
default:
|
336 |
printf(" 0x%08x len %zd ", md_id, md_len);
|
337 |
break;
|
338 |
} |
339 |
printf(" %22s ", ptag == NULL ? "" : ptag); |
340 |
switch (ptype)
|
341 |
{ |
342 |
case 1: |
343 |
// print as string
|
344 |
printf("%s", EpChar->lquote);
|
345 |
ep_xlate_out(md_data, md_len, stdout, "",
|
346 |
EP_XLATE_PLUS | EP_XLATE_NPRINT); |
347 |
printf("%s\n", EpChar->rquote);
|
348 |
break;
|
349 |
|
350 |
case 2: |
351 |
// print as hex
|
352 |
ep_hexdump(md_data, md_len, stdout, EP_HEXDUMP_TERSE, 0);
|
353 |
break;
|
354 |
|
355 |
default:
|
356 |
printf("(omitted)\n");
|
357 |
break;
|
358 |
} |
359 |
} |
360 |
goto done;
|
361 |
} |
362 |
|
363 |
if (plev >= 3) |
364 |
printf("\n\n----------------------------------------------------------\n");
|
365 |
printf("%s: %" PRIgdp_recno " recs\n", log_pname, gob->nrecs); |
366 |
uint32_t pflags = GDP_DATUM_PRMETAONLY; |
367 |
if (plev >= 3) |
368 |
{ |
369 |
pflags |= GDP_DATUM_PRSIG; |
370 |
pr_verbose_metadata(gob, plev); |
371 |
} |
372 |
if (plev >= 5) |
373 |
pflags &= ~GDP_DATUM_PRMETAONLY; |
374 |
|
375 |
// now dump the contents
|
376 |
if (plev >= 4) |
377 |
{ |
378 |
printf("\n --------------- Data ---------------\n");
|
379 |
uintptr_t intptrpflags = pflags; |
380 |
estat = sqlite_read_by_recno(gob, 1, UINT32_MAX, show_rec,
|
381 |
(void *) intptrpflags);
|
382 |
} |
383 |
|
384 |
if (false) |
385 |
{ |
386 |
char ebuf[60]; |
387 |
fail0:
|
388 |
fprintf(stderr, "%s: %s\n",
|
389 |
log_pname, ep_stat_tostr(estat, ebuf, sizeof ebuf));
|
390 |
} |
391 |
done:
|
392 |
if (gob != NULL) |
393 |
_gdp_gob_free(&gob); |
394 |
return estat;
|
395 |
} |
396 |
|
397 |
|
398 |
int
|
399 |
list_logs(const char *gcl_dir_name, int plev) |
400 |
{ |
401 |
DIR *dir; |
402 |
int subdir;
|
403 |
gdp_name_t gcl_iname; |
404 |
|
405 |
ep_dbg_cprintf(Dbg, 11, "list_logs(%s)\n", gcl_dir_name); |
406 |
dir = opendir(gcl_dir_name); |
407 |
if (dir == NULL) |
408 |
{ |
409 |
fprintf(stderr, "Could not open %s, errno = %d\n",
|
410 |
gcl_dir_name, errno); |
411 |
return EX_NOINPUT;
|
412 |
} |
413 |
closedir(dir); |
414 |
|
415 |
for (subdir = 0; subdir < 0x100; subdir++) |
416 |
{ |
417 |
char dbuf[400]; |
418 |
|
419 |
snprintf(dbuf, sizeof dbuf, "%s/_%02x", gcl_dir_name, subdir); |
420 |
dir = opendir(dbuf); |
421 |
if (dir == NULL) |
422 |
continue;
|
423 |
|
424 |
for (;;)
|
425 |
{ |
426 |
struct dirent *dent;
|
427 |
|
428 |
// read the next directory entry
|
429 |
dent = readdir(dir); |
430 |
if (dent == NULL) |
431 |
break;
|
432 |
|
433 |
// we're only interested in .data files
|
434 |
char *p = strrchr(dent->d_name, '.'); |
435 |
if (p == NULL || strcmp(p, GLOG_SUFFIX) != 0) |
436 |
continue;
|
437 |
|
438 |
// save the full pathname in case we need it
|
439 |
snprintf(dbuf, sizeof dbuf, "%s/_%02x/%s", |
440 |
gcl_dir_name, subdir, dent->d_name); |
441 |
|
442 |
// strip off the ".db"
|
443 |
*p = '\0';
|
444 |
|
445 |
// print the name and maybe other info
|
446 |
gdp_parse_name(dent->d_name, gcl_iname); |
447 |
show_log(gcl_iname, plev); |
448 |
} |
449 |
closedir(dir); |
450 |
} |
451 |
|
452 |
return EX_OK;
|
453 |
} |
454 |
|
455 |
|
456 |
void
|
457 |
usage(const char *msg) |
458 |
{ |
459 |
fprintf(stderr, |
460 |
"Usage error: %s\n"
|
461 |
"Usage: log-view [-d dir] [-D dbgspec ] [-l] [-r] [-v] [log_name ...]\n"
|
462 |
"\t-d dir -- set log database root directory\n"
|
463 |
"\t-D spec -- set debug flags\n"
|
464 |
"\t-l -- list all local logs\n"
|
465 |
"\t-n -- only list logs with no metadata\n"
|
466 |
"\t-v -- print verbose information (-vv for more detail)\n",
|
467 |
msg); |
468 |
|
469 |
exit(EX_USAGE); |
470 |
} |
471 |
|
472 |
int
|
473 |
main(int argc, char *argv[]) |
474 |
{ |
475 |
int opt;
|
476 |
int verbosity = 0; |
477 |
bool ls_logs = false; |
478 |
char *log_xname = NULL; |
479 |
const char *log_dir_name = NULL; |
480 |
EP_STAT estat; |
481 |
|
482 |
// ep_lib_init(0);
|
483 |
|
484 |
while ((opt = getopt(argc, argv, "d:D:lnv")) > 0) |
485 |
{ |
486 |
switch (opt)
|
487 |
{ |
488 |
case 'd': |
489 |
log_dir_name = optarg; |
490 |
break;
|
491 |
|
492 |
case 'D': |
493 |
ep_dbg_set(optarg); |
494 |
break;
|
495 |
|
496 |
case 'l': |
497 |
ls_logs = true;
|
498 |
break;
|
499 |
|
500 |
case 'v': |
501 |
verbosity++; |
502 |
break;
|
503 |
|
504 |
default:
|
505 |
usage("unknown flag");
|
506 |
} |
507 |
} |
508 |
argc -= optind; |
509 |
argv += optind; |
510 |
|
511 |
// initialization
|
512 |
estat = gdp_init_phase_0(NULL, 0); |
513 |
EP_STAT_CHECK(estat, goto fail0);
|
514 |
ep_adm_readparams("gdplogd");
|
515 |
_gdp_name_init(NULL);
|
516 |
|
517 |
// initialize logd_sqlite
|
518 |
estat = sqlite_init(log_dir_name); |
519 |
EP_STAT_CHECK(estat, goto fail0);
|
520 |
|
521 |
if (ls_logs)
|
522 |
{ |
523 |
if (argc > 0) |
524 |
usage("cannot use a log name with -l");
|
525 |
return list_logs(LogDir, verbosity);
|
526 |
} |
527 |
|
528 |
if (argc <= 0) |
529 |
usage("log name required");
|
530 |
for (; argc > 0; argc--, argv++) |
531 |
{ |
532 |
gdp_name_t log_name; |
533 |
log_xname = argv[0];
|
534 |
|
535 |
estat = gdp_parse_name(log_xname, log_name); |
536 |
if (!EP_STAT_ISOK(estat))
|
537 |
{ |
538 |
ep_app_message(estat, "unparsable log name");
|
539 |
continue;
|
540 |
} |
541 |
estat = show_log(log_name, verbosity); |
542 |
} |
543 |
fail0:
|
544 |
if (EP_STAT_ISFAIL(estat))
|
545 |
exit(EX_UNAVAILABLE); |
546 |
exit(EX_OK); |
547 |
} |