Annotation of embedaddon/strongswan/src/sw-collector/sw-collector.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2017 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE
! 17: #include <stdio.h>
! 18: #include <string.h>
! 19: #include <errno.h>
! 20: #include <getopt.h>
! 21: #include <unistd.h>
! 22: #ifdef HAVE_SYSLOG
! 23: # include <syslog.h>
! 24: #endif
! 25:
! 26: #include "sw_collector_db.h"
! 27: #include "sw_collector_history.h"
! 28: #include "sw_collector_rest_api.h"
! 29: #include "sw_collector_dpkg.h"
! 30:
! 31: #include <library.h>
! 32: #include <utils/debug.h>
! 33: #include <utils/lexparser.h>
! 34: #include <collections/hashtable.h>
! 35:
! 36: #include <swid_gen/swid_gen.h>
! 37: #include <swid_gen/swid_gen_info.h>
! 38: /**
! 39: * global debug output variables
! 40: */
! 41: static int debug_level = 2;
! 42: static bool stderr_quiet = FALSE;
! 43: static int max_count = 0;
! 44:
! 45: typedef enum collector_op_t collector_op_t;
! 46:
! 47: enum collector_op_t {
! 48: COLLECTOR_OP_EXTRACT,
! 49: COLLECTOR_OP_LIST,
! 50: COLLECTOR_OP_UNREGISTERED,
! 51: COLLECTOR_OP_GENERATE,
! 52: COLLECTOR_OP_MIGRATE,
! 53: COLLECTOR_OP_CHECK
! 54: };
! 55:
! 56: /**
! 57: * sw_collector dbg function
! 58: */
! 59: static void sw_collector_dbg(debug_t group, level_t level, char *fmt, ...)
! 60: {
! 61: va_list args;
! 62:
! 63: if (level <= debug_level)
! 64: {
! 65: if (!stderr_quiet)
! 66: {
! 67: va_start(args, fmt);
! 68: vfprintf(stderr, fmt, args);
! 69: fprintf(stderr, "\n");
! 70: va_end(args);
! 71: }
! 72:
! 73: #ifdef HAVE_SYSLOG
! 74: {
! 75: int priority = LOG_INFO;
! 76: char buffer[8192];
! 77: char *current = buffer, *next;
! 78:
! 79: /* write in memory buffer first */
! 80: va_start(args, fmt);
! 81: vsnprintf(buffer, sizeof(buffer), fmt, args);
! 82: va_end(args);
! 83:
! 84: /* do a syslog with every line */
! 85: while (current)
! 86: {
! 87: next = strchr(current, '\n');
! 88: if (next)
! 89: {
! 90: *(next++) = '\0';
! 91: }
! 92: syslog(priority, "%s\n", current);
! 93: current = next;
! 94: }
! 95: }
! 96: #endif /* HAVE_SYSLOG */
! 97: }
! 98: }
! 99:
! 100: /**
! 101: * atexit handler
! 102: */
! 103: static void cleanup(void)
! 104: {
! 105: library_deinit();
! 106: #ifdef HAVE_SYSLOG
! 107: closelog();
! 108: #endif
! 109: }
! 110:
! 111: /**
! 112: * Display usage of sw-collector command
! 113: */
! 114: static void usage(void)
! 115: {
! 116: printf("\
! 117: Usage:\n\
! 118: sw-collector --help\n\
! 119: sw-collector [--debug <level>] [--quiet] [--count <event count>]\n\
! 120: sw-collector [--debug <level>] [--quiet] [--installed|--removed] \
! 121: --list|-unregistered\n\
! 122: sw-collector [--debug <level>] [--quiet] [--installed|--removed] \
! 123: [--full] --generate\n\
! 124: sw-collector [--debug <level>] [--quiet] --migrate\n\
! 125: sw-collector [--debug <level>] [--quiet] --check\n");
! 126: }
! 127:
! 128: /**
! 129: * Parse command line options
! 130: */
! 131: static collector_op_t do_args(int argc, char *argv[], bool *full_tags,
! 132: sw_collector_db_query_t *query_type)
! 133: {
! 134: collector_op_t op = COLLECTOR_OP_EXTRACT;
! 135: bool installed = FALSE, removed = FALSE, full = FALSE;
! 136:
! 137: /* reinit getopt state */
! 138: optind = 0;
! 139:
! 140: while (TRUE)
! 141: {
! 142: int c;
! 143:
! 144: struct option long_opts[] = {
! 145: { "help", no_argument, NULL, 'h' },
! 146: { "check", no_argument, NULL, 'C' },
! 147: { "count", required_argument, NULL, 'c' },
! 148: { "debug", required_argument, NULL, 'd' },
! 149: { "full", no_argument, NULL, 'f' },
! 150: { "generate", no_argument, NULL, 'g' },
! 151: { "installed", no_argument, NULL, 'i' },
! 152: { "list", no_argument, NULL, 'l' },
! 153: { "migrate", no_argument, NULL, 'm' },
! 154: { "quiet", no_argument, NULL, 'q' },
! 155: { "removed", no_argument, NULL, 'r' },
! 156: { "unregistered", no_argument, NULL, 'u' },
! 157: { 0,0,0,0 }
! 158: };
! 159:
! 160: c = getopt_long(argc, argv, "hCc:d:fgilmqru", long_opts, NULL);
! 161: switch (c)
! 162: {
! 163: case EOF:
! 164: break;
! 165: case 'h':
! 166: usage();
! 167: exit(SUCCESS);
! 168: case 'C':
! 169: op = COLLECTOR_OP_CHECK;
! 170: continue;
! 171: case 'c':
! 172: max_count = atoi(optarg);
! 173: continue;
! 174: case 'd':
! 175: debug_level = atoi(optarg);
! 176: continue;
! 177: case 'f':
! 178: full = TRUE;
! 179: continue;
! 180: case 'g':
! 181: op = COLLECTOR_OP_GENERATE;
! 182: continue;
! 183: case 'i':
! 184: installed = TRUE;
! 185: continue;
! 186: case 'l':
! 187: op = COLLECTOR_OP_LIST;
! 188: continue;
! 189: case 'm':
! 190: op = COLLECTOR_OP_MIGRATE;
! 191: continue;
! 192: case 'q':
! 193: stderr_quiet = TRUE;
! 194: continue;
! 195: case 'r':
! 196: removed = TRUE;
! 197: continue;
! 198: case 'u':
! 199: op = COLLECTOR_OP_UNREGISTERED;
! 200: continue;
! 201: default:
! 202: usage();
! 203: exit(EXIT_FAILURE);
! 204: }
! 205: break;
! 206: }
! 207:
! 208: if ((!installed && !removed) || (installed && removed))
! 209: {
! 210: *query_type = SW_QUERY_ALL;
! 211: }
! 212: else if (installed)
! 213: {
! 214: *query_type = SW_QUERY_INSTALLED;
! 215: }
! 216: else
! 217: {
! 218: *query_type = SW_QUERY_REMOVED;
! 219: }
! 220: *full_tags = full;
! 221:
! 222: return op;
! 223: }
! 224:
! 225: /**
! 226: * Extract software events from apt history log files
! 227: */
! 228: static int extract_history(sw_collector_db_t *db)
! 229: {
! 230: sw_collector_history_t *history = NULL;
! 231: uint32_t epoch, last_eid, eid = 0;
! 232: char *history_path, *last_time = NULL, rfc_time[21];
! 233: chunk_t *h, history_chunk, line, cmd;
! 234: int status = EXIT_FAILURE;
! 235: bool skip = TRUE;
! 236:
! 237: /* open history file for reading */
! 238: history_path = lib->settings->get_str(lib->settings, "%s.history", NULL,
! 239: lib->ns);
! 240: if (!history_path)
! 241: {
! 242: fprintf(stderr, "sw-collector.history path not set.\n");
! 243: return EXIT_FAILURE;
! 244: }
! 245: h = chunk_map(history_path, FALSE);
! 246: if (!h)
! 247: {
! 248: fprintf(stderr, "opening '%s' failed: %s", history_path,
! 249: strerror(errno));
! 250: return EXIT_FAILURE;
! 251: }
! 252: history_chunk = *h;
! 253:
! 254: /* Instantiate history extractor */
! 255: history = sw_collector_history_create(db, 1);
! 256: if (!history)
! 257: {
! 258: chunk_unmap(h);
! 259: return EXIT_FAILURE;
! 260: }
! 261:
! 262: /* retrieve last event in database */
! 263: if (!db->get_last_event(db, &last_eid, &epoch, &last_time) || !last_eid)
! 264: {
! 265: goto end;
! 266: }
! 267: DBG0(DBG_IMC, "Last-Event: %s, eid = %u, epoch = %u",
! 268: last_time, last_eid, epoch);
! 269:
! 270: /* parse history file */
! 271: while (fetchline(&history_chunk, &line))
! 272: {
! 273: if (line.len == 0)
! 274: {
! 275: continue;
! 276: }
! 277: if (!extract_token(&cmd, ':', &line))
! 278: {
! 279: fprintf(stderr, "terminator symbol ':' not found.\n");
! 280: goto end;
! 281: }
! 282: if (match("Start-Date", &cmd))
! 283: {
! 284: if (!history->extract_timestamp(history, line, rfc_time))
! 285: {
! 286: goto end;
! 287: }
! 288:
! 289: /* have we reached new history entries? */
! 290: if (skip && strcmp(rfc_time, last_time) > 0)
! 291: {
! 292: skip = FALSE;
! 293: }
! 294: if (skip)
! 295: {
! 296: continue;
! 297: }
! 298:
! 299: /* insert new event into database */
! 300: eid = db->add_event(db, rfc_time);
! 301: if (!eid)
! 302: {
! 303: goto end;
! 304: }
! 305: DBG1(DBG_IMC, "Start-Date: %s, eid = %u, epoch = %u",
! 306: rfc_time, eid, epoch);
! 307: }
! 308: else if (skip)
! 309: {
! 310: /* skip old history entries which have already been processed */
! 311: continue;
! 312: }
! 313: else if (match("Install", &cmd))
! 314: {
! 315: DBG1(DBG_IMC, " Install:");
! 316: if (!history->extract_packages(history, line, eid, SW_OP_INSTALL))
! 317: {
! 318: goto end;
! 319: }
! 320: }
! 321: else if (match("Upgrade", &cmd))
! 322: {
! 323: DBG1(DBG_IMC, " Upgrade:");
! 324: if (!history->extract_packages(history, line, eid, SW_OP_UPGRADE))
! 325: {
! 326: goto end;
! 327: }
! 328: }
! 329: else if (match("Remove", &cmd))
! 330: {
! 331: DBG1(DBG_IMC, " Remove:");
! 332: if (!history->extract_packages(history, line, eid, SW_OP_REMOVE))
! 333: {
! 334: goto end;
! 335: }
! 336: }
! 337: else if (match("Purge", &cmd))
! 338: {
! 339: DBG1(DBG_IMC, " Purge:");
! 340: if (!history->extract_packages(history, line, eid, SW_OP_REMOVE))
! 341: {
! 342: goto end;
! 343: }
! 344: }
! 345: else if (match("End-Date", &cmd))
! 346: {
! 347: /* Process 'max_count' events at a time */
! 348: if (max_count > 0 && eid - last_eid == max_count)
! 349: {
! 350: fprintf(stderr, "added %d events\n", max_count);
! 351: goto end;
! 352: }
! 353: }
! 354: }
! 355:
! 356: if (history->merge_installed_packages(history))
! 357: {
! 358: status = EXIT_SUCCESS;
! 359: }
! 360:
! 361: end:
! 362: free(last_time);
! 363: history->destroy(history);
! 364: chunk_unmap(h);
! 365:
! 366: return status;
! 367: }
! 368:
! 369: /**
! 370: * List all endpoint software identifiers stored in local collector database
! 371: */
! 372: static int list_identifiers(sw_collector_db_t *db, sw_collector_db_query_t type)
! 373: {
! 374: enumerator_t *e;
! 375: char *name, *package, *version;
! 376: uint32_t sw_id, count = 0, installed_count = 0, removed_count, installed;
! 377:
! 378: e = db->create_sw_enumerator(db, type, NULL);
! 379: if (!e)
! 380: {
! 381: return EXIT_FAILURE;
! 382: }
! 383: while (e->enumerate(e, &sw_id, &name, &package, &version, &installed))
! 384: {
! 385: printf("%s,%s,%s,%d\n", name, package, version, installed);
! 386: if (installed)
! 387: {
! 388: installed_count++;
! 389: }
! 390: count++;
! 391: }
! 392: removed_count = count - installed_count;
! 393: e->destroy(e);
! 394:
! 395: switch (type)
! 396: {
! 397: case SW_QUERY_ALL:
! 398: DBG1(DBG_IMC, "retrieved %u software identities with %u installed "
! 399: "and %u removed", count, installed_count, removed_count);
! 400: break;
! 401: case SW_QUERY_INSTALLED:
! 402: DBG1(DBG_IMC, "retrieved %u installed software identities", count);
! 403: break;
! 404: case SW_QUERY_REMOVED:
! 405: DBG1(DBG_IMC, "retrieved %u removed software identities", count);
! 406: break;
! 407: }
! 408:
! 409: return EXIT_SUCCESS;
! 410: }
! 411:
! 412: static bool query_registry(sw_collector_rest_api_t *rest_api, bool installed)
! 413: {
! 414: sw_collector_db_query_t type;
! 415: enumerator_t *enumerator;
! 416: char *sw_id;
! 417: int count = 0;
! 418:
! 419: type = installed ? SW_QUERY_INSTALLED : SW_QUERY_REMOVED;
! 420: enumerator = rest_api->create_sw_enumerator(rest_api, type);
! 421: if (!enumerator)
! 422: {
! 423: return FALSE;
! 424: }
! 425: while (enumerator->enumerate(enumerator, &sw_id))
! 426: {
! 427: printf("%s,%s\n", sw_id, installed ? "1" : "0");
! 428: count++;
! 429: }
! 430: enumerator->destroy(enumerator);
! 431: DBG1(DBG_IMC, "%d %s software identifiers not registered", count,
! 432: installed ? "installed" : "removed");
! 433: return TRUE;
! 434: }
! 435:
! 436:
! 437: /**
! 438: * List all endpoint software identifiers stored in local collector database
! 439: * that are not registered yet in central collector database
! 440: */
! 441: static int unregistered_identifiers(sw_collector_db_t *db,
! 442: sw_collector_db_query_t type)
! 443: {
! 444: sw_collector_rest_api_t *rest_api;
! 445: int status = EXIT_SUCCESS;
! 446:
! 447: rest_api = sw_collector_rest_api_create(db);
! 448: if (!rest_api)
! 449: {
! 450: return EXIT_FAILURE;
! 451: }
! 452:
! 453: /* List installed software identifiers not registered centrally */
! 454: if (type != SW_QUERY_REMOVED && !query_registry(rest_api, TRUE))
! 455: {
! 456: status = EXIT_FAILURE;
! 457: }
! 458:
! 459: /* List removed software identifiers not registered centrally */
! 460: if (type != SW_QUERY_INSTALLED && !query_registry(rest_api, FALSE))
! 461: {
! 462: status = EXIT_FAILURE;
! 463: }
! 464: rest_api->destroy(rest_api);
! 465:
! 466: return status;
! 467: }
! 468:
! 469: /**
! 470: * Generate ISO 19770-2:2015 SWID tags for [installed|removed|all]
! 471: * SW identifiers that are not registered centrally
! 472: */
! 473: static int generate_tags(sw_collector_db_t *db, bool full_tags,
! 474: sw_collector_db_query_t type)
! 475: {
! 476: swid_gen_t * swid_gen;
! 477: sw_collector_rest_api_t *rest_api;
! 478: char *name, *package, *version, *tag;
! 479: enumerator_t *enumerator;
! 480: uint32_t sw_id;
! 481: bool installed;
! 482: int count = 0, installed_count = 0, status = EXIT_FAILURE;
! 483:
! 484: swid_gen = swid_gen_create();
! 485: rest_api = sw_collector_rest_api_create(db);
! 486: if (!rest_api)
! 487: {
! 488: goto end;
! 489: }
! 490:
! 491: enumerator = rest_api->create_sw_enumerator(rest_api, type);
! 492: if (!enumerator)
! 493: {
! 494: goto end;
! 495: }
! 496: while (enumerator->enumerate(enumerator, &name))
! 497: {
! 498: sw_id = db->get_sw_id(db, name, &package, &version, NULL, &installed);
! 499: if (sw_id)
! 500: {
! 501: tag = swid_gen->generate_tag(swid_gen, name, package, version,
! 502: full_tags && installed, FALSE);
! 503: if (tag)
! 504: {
! 505: DBG2(DBG_IMC, " creating %s", name);
! 506: printf("%s\n", tag);
! 507: free(tag);
! 508: count++;
! 509: if (installed)
! 510: {
! 511: installed_count++;
! 512: }
! 513: }
! 514: free(package);
! 515: free(version);
! 516: }
! 517: }
! 518: enumerator->destroy(enumerator);
! 519: status = EXIT_SUCCESS;
! 520:
! 521: switch (type)
! 522: {
! 523: case SW_QUERY_ALL:
! 524: DBG1(DBG_IMC, "created %d tags for unregistered software "
! 525: "identifiers with %d installed and %d removed", count,
! 526: installed_count, count - installed_count);
! 527: break;
! 528: case SW_QUERY_INSTALLED:
! 529: DBG1(DBG_IMC, "created %d tags for unregistered installed software "
! 530: "identifiers", count);
! 531: break;
! 532: case SW_QUERY_REMOVED:
! 533: DBG1(DBG_IMC, "created %d tags for unregistered removed software "
! 534: "identifiers", count);
! 535: break;
! 536: }
! 537:
! 538: end:
! 539: swid_gen->destroy(swid_gen);
! 540: DESTROY_IF(rest_api);
! 541:
! 542: return status;
! 543: }
! 544:
! 545: /**
! 546: * Remove architecture suffix from package entries in the database
! 547: */
! 548: static int migrate(sw_collector_db_t *db)
! 549: {
! 550: sw_collector_dpkg_t *dpkg;
! 551:
! 552: char *package, *arch, *version;
! 553: char package_filter[BUF_LEN];
! 554: int res, count = 0;
! 555: int status = EXIT_SUCCESS;
! 556: enumerator_t *enumerator;
! 557:
! 558: dpkg = sw_collector_dpkg_create();
! 559: if (!dpkg)
! 560: {
! 561: return FAILED;
! 562: }
! 563:
! 564: enumerator = dpkg->create_sw_enumerator(dpkg);
! 565: while (enumerator->enumerate(enumerator, &package, &arch, &version))
! 566: {
! 567:
! 568: /* Look for package names with architecture suffix */
! 569: snprintf(package_filter, BUF_LEN, "%s:%%", package);
! 570:
! 571: res = db->update_package(db, package_filter, package);
! 572: if (res < 0)
! 573: {
! 574: status = EXIT_FAILURE;
! 575: break;
! 576: }
! 577: else if (res > 0)
! 578: {
! 579: count += res;
! 580: DBG2(DBG_IMC, "%s: removed arch suffix %d times", package, res);
! 581: }
! 582: }
! 583: enumerator->destroy(enumerator);
! 584: dpkg->destroy(dpkg);
! 585:
! 586: DBG1(DBG_IMC, "migrated %d sw identifier records", count);
! 587:
! 588: return status;
! 589: }
! 590:
! 591: /**
! 592: * Free hashtable entry
! 593: */
! 594: static void free_entry(void *value, void *key)
! 595: {
! 596: free(value);
! 597: free(key);
! 598: }
! 599:
! 600: /**
! 601: * Check consistency of installed software identifiers in collector database
! 602: */
! 603: static int check(sw_collector_db_t *db)
! 604: {
! 605: sw_collector_dpkg_t *dpkg;
! 606: swid_gen_info_t *info;
! 607: hashtable_t *table;
! 608: enumerator_t *e;
! 609: char *dpkg_name, *name, *package, *arch, *version;
! 610: uint32_t sw_id, count = 0, installed;
! 611:
! 612: dpkg = sw_collector_dpkg_create();
! 613: if (!dpkg)
! 614: {
! 615: return EXIT_FAILURE;
! 616: }
! 617: info = swid_gen_info_create();
! 618: table = hashtable_create(hashtable_hash_str, hashtable_equals_str, 4096);
! 619:
! 620: /* Store all installed sw identifiers (according to dpkg) in hashtable */
! 621: e = dpkg->create_sw_enumerator(dpkg);
! 622: while (e->enumerate(e, &package, &arch, &version))
! 623: {
! 624: dpkg_name = info->create_sw_id(info, package, version);
! 625: table->put(table, strdup(package), dpkg_name);
! 626: }
! 627: e->destroy(e);
! 628:
! 629: info->destroy(info);
! 630: dpkg->destroy(dpkg);
! 631:
! 632: e = db->create_sw_enumerator(db, SW_QUERY_ALL, NULL);
! 633: if (!e)
! 634: {
! 635: table->destroy_function(table, (void*)free_entry);
! 636: return EXIT_FAILURE;
! 637: }
! 638: while (e->enumerate(e, &sw_id, &name, &package, &version, &installed))
! 639: {
! 640: dpkg_name = table->get(table, package);
! 641: if (installed)
! 642: {
! 643: if (!dpkg_name)
! 644: {
! 645: printf("%4d %s erroneously noted as installed\n", sw_id, name);
! 646: }
! 647: else if (!streq(name, dpkg_name))
! 648: {
! 649: printf("%4d %s erroneously noted as installed instead of\n "
! 650: " %s\n", sw_id, name, dpkg_name);
! 651: }
! 652: }
! 653: else
! 654: {
! 655: if (dpkg_name && streq(name, dpkg_name))
! 656: {
! 657: printf("%4d %s erroneously noted as removed\n", sw_id, name);
! 658: }
! 659: }
! 660: count++;
! 661: }
! 662: e->destroy(e);
! 663:
! 664: table->destroy_function(table, (void*)free_entry);
! 665: printf("checked %d software identifiers\n", count);
! 666:
! 667: return EXIT_SUCCESS;
! 668: }
! 669:
! 670: int main(int argc, char *argv[])
! 671: {
! 672: sw_collector_db_t *db = NULL;
! 673: sw_collector_db_query_t query_type;
! 674: collector_op_t op;
! 675: bool full_tags;
! 676: char *uri;
! 677: int status = EXIT_FAILURE;
! 678:
! 679: op = do_args(argc, argv, &full_tags, &query_type);
! 680:
! 681: /* enable sw_collector debugging hook */
! 682: dbg = sw_collector_dbg;
! 683: #ifdef HAVE_SYSLOG
! 684: openlog("sw-collector", 0, LOG_DEBUG);
! 685: #endif
! 686:
! 687: atexit(cleanup);
! 688:
! 689: /* initialize library */
! 690: if (!library_init(NULL, "sw-collector"))
! 691: {
! 692: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
! 693: }
! 694:
! 695: /* load sw-collector plugins */
! 696: if (!lib->plugins->load(lib->plugins,
! 697: lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns)))
! 698: {
! 699: exit(SS_RC_INITIALIZATION_FAILED);
! 700: }
! 701:
! 702: /* connect to sw-collector database */
! 703: uri = lib->settings->get_str(lib->settings, "%s.database", NULL, lib->ns);
! 704: if (!uri)
! 705: {
! 706: fprintf(stderr, "sw-collector.database URI not set.\n");
! 707: exit(EXIT_FAILURE);
! 708: }
! 709: db = sw_collector_db_create(uri);
! 710: if (!db)
! 711: {
! 712: fprintf(stderr, "connection to sw-collector database failed.\n");
! 713: exit(EXIT_FAILURE);
! 714: }
! 715:
! 716: switch (op)
! 717: {
! 718: case COLLECTOR_OP_EXTRACT:
! 719: status = extract_history(db);
! 720: break;
! 721: case COLLECTOR_OP_LIST:
! 722: status = list_identifiers(db, query_type);
! 723: break;
! 724: case COLLECTOR_OP_UNREGISTERED:
! 725: status = unregistered_identifiers(db, query_type);
! 726: break;
! 727: case COLLECTOR_OP_GENERATE:
! 728: status = generate_tags(db, full_tags, query_type);
! 729: break;
! 730: case COLLECTOR_OP_MIGRATE:
! 731: status = migrate(db);
! 732: break;
! 733: case COLLECTOR_OP_CHECK:
! 734: status = check(db);
! 735: break;
! 736: }
! 737: db->destroy(db);
! 738:
! 739: exit(status);
! 740: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>