sw-collector: Added --check option
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 26 Apr 2018 14:24:59 +0000 (16:24 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 27 Apr 2018 09:42:34 +0000 (11:42 +0200)
src/sw-collector/sw-collector.8.in
src/sw-collector/sw-collector.c

index b9041c7..5c8d256 100644 (file)
@@ -34,6 +34,12 @@ sw-collector \- Extracts software installation events from dpkg history log
 .YS
 .
 .SY "sw-collector"
 .YS
 .
 .SY "sw-collector"
+.OP \-\-debug level
+.OP \-\-quiet
+.BR \-\-check
+.YS
+.
+.SY "sw-collector"
 .B \-h
 |
 .B \-\-help
 .B \-h
 |
 .B \-\-help
@@ -76,7 +82,7 @@ installation status.
 .B "\-u, \-\-unregistered"
 Lists all software packages residing in the local collector database but for
 which no SWID tags exist yet in a central collector database reachable via a
 .B "\-u, \-\-unregistered"
 Lists all software packages residing in the local collector database but for
 which no SWID tags exist yet in a central collector database reachable via a
-REST interface. 
+REST interface.
 .TP
 .B "\-g, \-\-generate"
 Generates ISO 19770-2:2015 SWID tags for all software packages residing in the
 .TP
 .B "\-g, \-\-generate"
 Generates ISO 19770-2:2015 SWID tags for all software packages residing in the
@@ -86,6 +92,10 @@ database reachable via a REST interface.
 .B "\-m, \-\-migrate"
 Can be used to migrate collector database versions. Currently all architecture
 suffixes are removed from dpkg package names.
 .B "\-m, \-\-migrate"
 Can be used to migrate collector database versions. Currently all architecture
 suffixes are removed from dpkg package names.
+.TP
+.B "\-C, \-\-check"
+Checks the integrity of the collector database against the actual list of
+installed packages obtained with dpkg-query.
 .
 .SH "CONFIGURATION"
 .
 .
 .SH "CONFIGURATION"
 .
index a42f106..2b1783e 100644 (file)
 #include <library.h>
 #include <utils/debug.h>
 #include <utils/lexparser.h>
 #include <library.h>
 #include <utils/debug.h>
 #include <utils/lexparser.h>
+#include <collections/hashtable.h>
 
 #include <swid_gen/swid_gen.h>
 
 #include <swid_gen/swid_gen.h>
-
+#include <swid_gen/swid_gen_info.h>
 /**
  * global debug output variables
  */
 /**
  * global debug output variables
  */
@@ -48,7 +49,8 @@ enum collector_op_t {
        COLLECTOR_OP_LIST,
        COLLECTOR_OP_UNREGISTERED,
        COLLECTOR_OP_GENERATE,
        COLLECTOR_OP_LIST,
        COLLECTOR_OP_UNREGISTERED,
        COLLECTOR_OP_GENERATE,
-       COLLECTOR_OP_MIGRATE
+       COLLECTOR_OP_MIGRATE,
+       COLLECTOR_OP_CHECK
 };
 
 /**
 };
 
 /**
@@ -119,7 +121,8 @@ Usage:\n\
 --list|-unregistered\n\
   sw-collector [--debug <level>] [--quiet] [--installed|--removed] \
 [--full] --generate\n\
 --list|-unregistered\n\
   sw-collector [--debug <level>] [--quiet] [--installed|--removed] \
 [--full] --generate\n\
-  sw-collector [--debug <level>] [--quiet] --migrate\n");
+  sw-collector [--debug <level>] [--quiet] --migrate\n\
+  sw-collector [--debug <level>] [--quiet] --check\n");
 }
 
 /**
 }
 
 /**
@@ -140,6 +143,7 @@ static collector_op_t do_args(int argc, char *argv[], bool *full_tags,
 
                struct option long_opts[] = {
                        { "help", no_argument, NULL, 'h' },
 
                struct option long_opts[] = {
                        { "help", no_argument, NULL, 'h' },
+                       { "check", no_argument, NULL, 'C' },
                        { "count", required_argument, NULL, 'c' },
                        { "debug", required_argument, NULL, 'd' },
                        { "full", no_argument, NULL, 'f' },
                        { "count", required_argument, NULL, 'c' },
                        { "debug", required_argument, NULL, 'd' },
                        { "full", no_argument, NULL, 'f' },
@@ -153,7 +157,7 @@ static collector_op_t do_args(int argc, char *argv[], bool *full_tags,
                        { 0,0,0,0 }
                };
 
                        { 0,0,0,0 }
                };
 
-               c = getopt_long(argc, argv, "hc:d:fgilmqru", long_opts, NULL);
+               c = getopt_long(argc, argv, "hCc:d:fgilmqru", long_opts, NULL);
                switch (c)
                {
                        case EOF:
                switch (c)
                {
                        case EOF:
@@ -162,6 +166,9 @@ static collector_op_t do_args(int argc, char *argv[], bool *full_tags,
                                usage();
                                exit(SUCCESS);
                                break;
                                usage();
                                exit(SUCCESS);
                                break;
+                       case 'C':
+                               op = COLLECTOR_OP_CHECK;
+                               continue;
                        case 'c':
                                count = atoi(optarg);
                                continue;
                        case 'c':
                                count = atoi(optarg);
                                continue;
@@ -537,7 +544,7 @@ end:
 }
 
 /**
 }
 
 /**
- * Append missing architecture suffix to package entries in the database
+ * Remove architecture suffix from package entries in the database
  */
 static int migrate(sw_collector_db_t *db)
 {
  */
 static int migrate(sw_collector_db_t *db)
 {
@@ -582,6 +589,83 @@ static int migrate(sw_collector_db_t *db)
        return status;
 }
 
        return status;
 }
 
+/**
+ * Free hashtable entry
+ */
+static void free_entry(void *value, void *key)
+{
+       free(value);
+       free(key);
+}
+
+/**
+ * Check consistency of installed software identifiers in collector database
+ */
+static int check(sw_collector_db_t *db)
+{
+       sw_collector_dpkg_t *dpkg;
+       swid_gen_info_t *info;
+       hashtable_t *table;
+       enumerator_t *e;
+       char *dpkg_name, *name, *package, *arch, *version;
+       uint32_t sw_id, count = 0, installed;
+
+       dpkg = sw_collector_dpkg_create();
+       if (!dpkg)
+       {
+               return EXIT_FAILURE;
+       }
+       info = swid_gen_info_create();
+       table = hashtable_create(hashtable_hash_str, hashtable_equals_str, 4096);
+
+       /* Store all installed sw identifiers (according to dpkg) in hashtable */
+       e = dpkg->create_sw_enumerator(dpkg);
+       while (e->enumerate(e, &package, &arch, &version))
+       {
+               dpkg_name = info->create_sw_id(info, package, version);
+               table->put(table, strdup(package), dpkg_name);
+       }
+       e->destroy(e);
+
+       info->destroy(info);
+       dpkg->destroy(dpkg);
+
+       e = db->create_sw_enumerator(db, SW_QUERY_ALL, NULL);
+       if (!e)
+       {
+               return EXIT_FAILURE;
+       }
+       while (e->enumerate(e, &sw_id, &name, &package, &version, &installed))
+       {
+               dpkg_name = table->get(table, package);
+               if (installed)
+               {
+                       if (!dpkg_name)
+                       {
+                               printf("%4d %s erroneously noted as installed\n", sw_id, name);
+                       }
+                       else if (!streq(name, dpkg_name))
+                       {
+                               printf("%4d %s erroneously noted as installed instead of\n "
+                                          "    %s\n", sw_id, name, dpkg_name);
+                       }
+               }
+               else
+               {
+                       if (dpkg_name && streq(name, dpkg_name))
+                       {
+                               printf("%4d %s erroneously noted as removed\n", sw_id, name);
+                       }
+               }
+               count++;
+       }
+       e->destroy(e);
+
+       table->destroy_function(table, (void*)free_entry);
+       printf("checked %d software identifiers\n", count);
+
+       return EXIT_SUCCESS;
+}
 
 int main(int argc, char *argv[])
 {
 
 int main(int argc, char *argv[])
 {
@@ -646,6 +730,9 @@ int main(int argc, char *argv[])
                case COLLECTOR_OP_MIGRATE:
                        status = migrate(db);
                        break;
                case COLLECTOR_OP_MIGRATE:
                        status = migrate(db);
                        break;
+               case COLLECTOR_OP_CHECK:
+                       status = check(db);
+                       break;
        }
        db->destroy(db);
 
        }
        db->destroy(db);