sw-collector: Check for epoch-less Debian package versions
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 9 Jul 2017 21:17:22 +0000 (23:17 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 12 Jul 2017 17:12:22 +0000 (19:12 +0200)
12 files changed:
src/libimcv/plugins/imc_swima/Makefile.am
src/libimcv/plugins/imc_swima/sw_collector/sw-collector.c
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.c
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.h
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.c [new file with mode: 0644]
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.h [new file with mode: 0644]
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.c
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.h
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.c [new file with mode: 0644]
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.h [new file with mode: 0644]
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.c
src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.h

index cde2098..e14556c 100644 (file)
@@ -37,7 +37,9 @@ ipsec_PROGRAMS = sw-collector
 sw_collector_SOURCES = \
        sw_collector/sw-collector.c \
        sw_collector/sw_collector_db.h sw_collector/sw_collector_db.c \
+       sw_collector/sw_collector_dpkg.h sw_collector/sw_collector_dpkg.c \
        sw_collector/sw_collector_history.h sw_collector/sw_collector_history.c \
+       sw_collector/sw_collector_info.h sw_collector/sw_collector_info.c \
        sw_collector/sw_collector_rest_api.h sw_collector/sw_collector_rest_api.c
 
 sw_collector_LDADD = \
index bb72349..2f4df18 100644 (file)
 # include <syslog.h>
 #endif
 
+#include "sw_collector_info.h"
 #include "sw_collector_db.h"
 #include "sw_collector_history.h"
 #include "sw_collector_rest_api.h"
-
+#include "sw_collector_dpkg.h"
+#
 #include <library.h>
 #include <utils/debug.h>
 #include <utils/lexparser.h>
 
+#include <imv/imv_os_info.h>
+
 /**
  * global debug output variables
  */
@@ -44,7 +48,8 @@ enum collector_op_t {
        COLLECTOR_OP_EXTRACT,
        COLLECTOR_OP_LIST,
        COLLECTOR_OP_UNREGISTERED,
-       COLLECTOR_OP_GENERATE
+       COLLECTOR_OP_GENERATE,
+       COLLECTOR_OP_MIGRATE
 };
 
 /**
@@ -110,9 +115,9 @@ static void usage(void)
        printf("\
 Usage:\n\
   sw-collector --help\n\
-  sw-collector [--debug <level>] [--quiet] --list\n\
-  sw-collector [--debug <level>] [--quiet] --unregistered|--generate\n\
-  sw-collector [--debug <level>] [--quiet] [--count <event count>]\n");
+  sw-collector [--debug <level>] [--quiet] [--count <event count>]\n\
+  sw-collector [--debug <level>] [--quiet] --list|-unregistered\n\
+  sw-collector [--debug <level>] [--quiet] ---generate|--migrate\n");
 }
 
 /**
@@ -135,12 +140,13 @@ static collector_op_t do_args(int argc, char *argv[])
                        { "debug", required_argument, NULL, 'd' },
                        { "generate", no_argument, NULL, 'g' },
                        { "list", no_argument, NULL, 'l' },
+                       { "migrate", no_argument, NULL, 'm' },
                        { "quiet", no_argument, NULL, 'q' },
                        { "unregistered", no_argument, NULL, 'u' },
                        { 0,0,0,0 }
                };
 
-               c = getopt_long(argc, argv, "hc:d:lqu", long_opts, NULL);
+               c = getopt_long(argc, argv, "hc:d:lmqu", long_opts, NULL);
                switch (c)
                {
                        case EOF:
@@ -161,6 +167,9 @@ static collector_op_t do_args(int argc, char *argv[])
                        case 'l':
                                op = COLLECTOR_OP_LIST;
                                continue;
+                       case 'm':
+                               op = COLLECTOR_OP_MIGRATE;
+                               continue;
                        case 'q':
                                stderr_quiet = TRUE;
                                continue;
@@ -179,38 +188,44 @@ static collector_op_t do_args(int argc, char *argv[])
 /**
  * Extract software events from apt history log files
  */
-static int extract_history(sw_collector_db_t *db)
+static int extract_history(sw_collector_info_t *info, sw_collector_db_t *db)
 {
        sw_collector_history_t *history = NULL;
        uint32_t epoch, last_eid, eid = 0;
-       char *history_path, *last_time = NULL, rfc_time[21];
+       char *history_path, *os, *last_time = NULL, rfc_time[21];
        chunk_t *h, history_chunk, line, cmd;
+       os_type_t os_type;
        int status = EXIT_FAILURE;
        bool skip = TRUE;
 
+       /* check if OS supports apg/dpkg history logs */
+       info->get_os(info, &os);
+       os_type = info->get_os_type(info);
+
+       if (os_type !=  OS_TYPE_DEBIAN && os_type != OS_TYPE_UBUNTU)
+       {
+               DBG1(DBG_IMC, "%.*s not supported", os);
+               return EXIT_FAILURE;
+       }
+
        /* open history file for reading */
        history_path= lib->settings->get_str(lib->settings, "%s.history", NULL,
                                                                                 lib->ns);
        if (!history_path)
        {
                fprintf(stderr, "sw-collector.history path not set.\n");
-               return FALSE;
+               return EXIT_FAILURE;
        }
        h = chunk_map(history_path, FALSE);
        if (!h)
        {
                fprintf(stderr, "opening '%s' failed: %s", history, strerror(errno));
-               return FALSE;
+               return EXIT_FAILURE;
        }
        history_chunk = *h;
 
        /* Instantiate history extractor */
-       history = sw_collector_history_create(db, 1);
-       if (!history)
-       {
-               /* OS is not supported */
-               goto end;
-       }
+       history = sw_collector_history_create(info, db, 1);
 
        /* retrieve last event in database */
        if (!db->get_last_event(db, &last_eid, &epoch, &last_time) || !last_eid)
@@ -313,7 +328,7 @@ static int extract_history(sw_collector_db_t *db)
 
 end:
        free(last_time);
-       DESTROY_IF(history);
+       history->destroy(history);
        chunk_unmap(h);
 
        return status;
@@ -326,14 +341,14 @@ static int list_identifiers(sw_collector_db_t *db)
 {
        enumerator_t *e;
        char *name, *package, *version;
-       uint32_t count = 0, installed_count = 0, installed;
+       uint32_t sw_id, count = 0, installed_count = 0, installed;
 
-       e = db->create_sw_enumerator(db, SW_QUERY_ALL);
+       e = db->create_sw_enumerator(db, SW_QUERY_ALL, NULL);
        if (!e)
        {
                return EXIT_FAILURE;
        }
-       while (e->enumerate(e, &name, &package, &version, &installed))
+       while (e->enumerate(e, &sw_id, &name, &package, &version, &installed))
        {
                printf("%s,%s,%s,%d\n", name, package, version, installed);
                if (installed)
@@ -433,9 +448,12 @@ static char* generate_tag(char *name, char *package, char *version,
        return (res == -1) ? NULL : tag;
 }
 
-static int generate_tags(sw_collector_db_t *db)
+/**
+ * Generate a minimalistic ISO 19770-2:2015 SWID tag for
+ * all deleted SW identifiers that are not registered centrally
+ */
+static int generate_tags(sw_collector_info_t *info, sw_collector_db_t *db)
 {
-       sw_collector_history_t *os_info;
        sw_collector_rest_api_t *rest_api;
        char *pos, *name, *package, *version, *entity, *regid, *product, *tag;
        enumerator_t *enumerator;
@@ -446,13 +464,7 @@ static int generate_tags(sw_collector_db_t *db)
                                                                        "strongSwan Project", lib->ns);
        regid  = lib->settings->get_str(lib->settings, "%s.tag_creator.regid",
                                                                        "strongswan.org", lib->ns);
-
-       os_info = sw_collector_history_create(db, 0);
-       if (!os_info)
-       {
-               return EXIT_FAILURE;
-       }
-       os_info->get_os(os_info, &product);
+       info->get_os(info, &product);
 
        rest_api = sw_collector_rest_api_create(db);
        if (!rest_api)
@@ -493,18 +505,69 @@ static int generate_tags(sw_collector_db_t *db)
                                   count);
 
 end:
-       os_info->destroy(os_info);
        DESTROY_IF(rest_api);
 
        return status;
 }
 
+/**
+ * Append missing architecture suffix to package entries in the database
+ */
+static int migrate(sw_collector_info_t *info, sw_collector_db_t *db)
+{
+       sw_collector_dpkg_t *dpkg;
+
+       char *package, *arch, *version;
+       char package_arch[BUF_LEN];
+       int res, count = 0;
+       int status = EXIT_SUCCESS;
+       enumerator_t *enumerator;
+
+       dpkg = sw_collector_dpkg_create();
+       if (!dpkg)
+       {
+               return FAILED;
+       }
+
+       enumerator = dpkg->create_sw_enumerator(dpkg);
+       while (enumerator->enumerate(enumerator, &package, &arch, &version))
+       {
+               if (streq(arch, "all"))
+               {
+                       continue;
+               }
+
+               /* Concatenate package and architecture strings */
+               snprintf(package_arch, BUF_LEN, "%s:%s", package, arch);
+
+               res = db->update_package(db, package, package_arch);
+               if (res < 0)
+               {
+                               status = EXIT_FAILURE;
+                               break;
+               }
+               else if (res > 0)
+               {
+                       count += res;
+                       DBG2(DBG_IMC, "replaced '%s' by '%s'", package, package_arch);
+               }
+       }
+       enumerator->destroy(enumerator);
+       dpkg->destroy(dpkg);
+
+       DBG1(DBG_IMC, "migrated %d sw identifier records", count);
+       return status;
+}
+
+
 int main(int argc, char *argv[])
 {
        sw_collector_db_t *db = NULL;
+       sw_collector_info_t *info;
        collector_op_t op;
-       char *uri;
-       int status;
+       char *uri, *tag_creator;
+       int status = EXIT_FAILURE;
 
        op = do_args(argc, argv);
 
@@ -543,10 +606,15 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
+       /* Attach OS info */
+       tag_creator = lib->settings->get_str(lib->settings, "%s.tag_creator.regid",
+                                                                                "strongswan.org", lib->ns);
+       info = sw_collector_info_create(tag_creator);
+
        switch (op)
        {
                case COLLECTOR_OP_EXTRACT:
-                       status = extract_history(db);
+                       status = extract_history(info, db);
                        break;
                case COLLECTOR_OP_LIST:
                        status = list_identifiers(db);
@@ -555,11 +623,14 @@ int main(int argc, char *argv[])
                        status = unregistered_identifiers(db);
                        break;
                case COLLECTOR_OP_GENERATE:
-                       status = generate_tags(db);
-               default:
+                       status = generate_tags(info, db);
+                       break;
+               case COLLECTOR_OP_MIGRATE:
+                       status = migrate(info, db);
                        break;
        }
        db->destroy(db);
+       info->destroy(info);
 
        exit(status);
 }
index 62a6507..206cbde 100644 (file)
@@ -110,71 +110,19 @@ METHOD(sw_collector_db_t, add_sw_event, bool,
 
 METHOD(sw_collector_db_t, set_sw_id, uint32_t,
        private_sw_collector_db_t *this, char *name,  char *package, char *version,
-       uint8_t source, bool installed, bool check)
+       uint8_t source, bool installed)
 {
-       uint32_t sw_id = 0, status;
-       enumerator_t *e;
+       uint32_t sw_id;
 
-       /* Does software identifier already exist in database? */
-       e = this->db->query(this->db,
-                       "SELECT id, installed FROM sw_identifiers WHERE name = ?",
-                       DB_TEXT, name, DB_UINT, DB_UINT);
-       if (!e)
+       if (this->db->execute(this->db, &sw_id,
+                       "INSERT INTO sw_identifiers "
+                       "(name, package, version, source, installed) VALUES (?, ?, ?, ?, ?)",
+                        DB_TEXT, name, DB_TEXT, package, DB_TEXT, version, DB_UINT, source,
+                        DB_UINT, installed) != 1)
        {
-               DBG1(DBG_IMC, "database query for sw_identifier failed");
+               DBG1(DBG_IMC, "unable to insert sw_id into database");
                return 0;
        }
-       if (!e->enumerate(e, &sw_id, &status))
-       {
-               sw_id = 0;
-       }
-       e->destroy(e);
-
-       if (sw_id)
-       {
-               if (status == installed)
-               {
-                       if (!check)
-                       {
-                               DBG1(DBG_IMC, "  Warning: sw_id %u is already %s", sw_id,
-                                        status ? "installed" : "deleted");
-                       }
-                       return sw_id;
-               }
-               if (check)
-               {
-                       DBG1(DBG_IMC, "  Warning: sw_id %u is %s", sw_id,
-                                status ? "installed" : "deleted");
-               }
-
-               /* Change installation status */
-               if (this->db->execute(this->db, NULL,
-                               "UPDATE sw_identifiers SET installed = ? WHERE id = ?",
-                                DB_UINT, installed, DB_UINT, sw_id) != 1)
-               {
-                       DBG1(DBG_IMC, "unable to update sw_id status in database");
-                       return 0;
-               }
-       }
-       else
-       {
-               /* Create new software identifier */
-               if (this->db->execute(this->db, &sw_id,
-                               "INSERT INTO sw_identifiers "
-                               "(name, package, version, source, installed) VALUES "
-                               "(?, ?, ?, ?, ?)",
-                                DB_TEXT, name, DB_TEXT, package, DB_TEXT, version,
-                                DB_UINT, source, DB_UINT, installed) != 1)
-               {
-                       DBG1(DBG_IMC, "unable to insert sw_id into database");
-                       return 0;
-               }
-
-               if (check || !installed)
-               {
-                       add_sw_event(this, 1, sw_id, SWIMA_EVENT_ACTION_CREATION);
-               }
-       }
 
        return sw_id;
 }
@@ -255,25 +203,91 @@ METHOD(sw_collector_db_t, get_sw_id_count, uint32_t,
        return count;
 }
 
+METHOD(sw_collector_db_t, update_sw_id, bool,
+       private_sw_collector_db_t *this, uint32_t sw_id, char *name, char *version,
+       bool installed)
+{
+       int res;
+
+       if (name && version)
+       {
+               res = this->db->execute(this->db, NULL,
+                       "UPDATE sw_identifiers SET name = ?, version = ?, installed = ? "
+                       "WHERE id = ?", DB_TEXT, name, DB_TEXT, version, DB_UINT, installed,
+                        DB_UINT, sw_id);
+       }
+       else
+       {
+               res = this->db->execute(this->db, NULL,
+                       "UPDATE sw_identifiers SET installed = ? WHERE id = ?",
+                        DB_UINT, installed, DB_UINT, sw_id);
+       }
+       if (res != 1)
+       {
+               DBG1(DBG_IMC, "unable to update software identifier in database");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+METHOD(sw_collector_db_t, update_package, int,
+       private_sw_collector_db_t *this, char *package, char *package_new)
+{
+       int count;
+
+       count = this->db->execute(this->db, NULL,
+                       "UPDATE sw_identifiers SET package = ? "
+                       "WHERE package = ?", DB_TEXT, package_new, DB_TEXT, package);
+       if (count < 0)
+       {
+               DBG1(DBG_IMC, "unable to update package name in database");
+       }
+
+       return count;
+}
+
 METHOD(sw_collector_db_t, create_sw_enumerator, enumerator_t*,
-       private_sw_collector_db_t *this, sw_collector_db_query_t type)
+       private_sw_collector_db_t *this, sw_collector_db_query_t type, char *package)
 {
        enumerator_t *e;
-       uint32_t installed;
+       u_int installed;
 
        if (type == SW_QUERY_ALL)
        {
-               e = this->db->query(this->db,
-                               "SELECT name, package, version, installed FROM sw_identifiers "
-                               "ORDER BY name ASC", DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+               if (package)
+               {
+                       e = this->db->query(this->db,
+                               "SELECT id, name, package, version, installed "
+                               "FROM sw_identifiers WHERE package = ? ORDER BY name ASC",
+                                DB_TEXT, package, DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+               }
+               else
+               {
+                       e = this->db->query(this->db,
+                               "SELECT id, name, package, version, installed "
+                               "FROM sw_identifiers ORDER BY name ASC",
+                                DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+               }
        }
        else
        {
                installed = (type == SW_QUERY_INSTALLED);
-               e = this->db->query(this->db,
-                               "SELECT name, package, version, installed FROM sw_identifiers "
-                               "WHERE installed = ? ORDER BY name ASC",
-                                DB_UINT, installed, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+
+               if (package)
+               {
+                       e = this->db->query(this->db,
+                               "SELECT id, name, package, version, installed "
+                               "FROM sw_identifiers WHERE package = ? AND installed = ? "
+                               "ORDER BY name ASC", DB_TEXT, package, DB_UINT, installed,
+                                DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+               }
+               else
+               {
+                       e = this->db->query(this->db,
+                               "SELECT id, name, package, version, installed "
+                               "FROM sw_identifiers WHERE installed = ? ORDER BY name ASC",
+                                DB_UINT, installed, DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
+               }
        }
        if (!e)
        {
@@ -308,6 +322,8 @@ sw_collector_db_t *sw_collector_db_create(char *uri)
                        .set_sw_id = _set_sw_id,
                        .get_sw_id = _get_sw_id,
                        .get_sw_id_count = _get_sw_id_count,
+                       .update_sw_id = _update_sw_id,
+                       .update_package = _update_package,
                        .create_sw_enumerator = _create_sw_enumerator,
                        .destroy = _destroy,
                },
index c4e82a9..88a13bb 100644 (file)
@@ -78,12 +78,10 @@ struct sw_collector_db_t {
         * @param version               Version of software package
         * @param source                Source ID of the software collector
         * @param installed             Installation status to be set, TRUE if installed
-        * @param check                 Check if SW ID is already installed
         * @return                              Primary key pointing to SW ID or 0 if failed
         */
        uint32_t (*set_sw_id)(sw_collector_db_t *this, char *name, char *package,
-                                                 char *version, uint8_t source, bool installed,
-                                                 bool check);
+                                                 char *version, uint8_t source, bool installed);
 
        /**
         * Get software_identifier record
@@ -108,13 +106,37 @@ struct sw_collector_db_t {
                                                                sw_collector_db_query_t type);
 
        /**
+        * Update the software identifier version
+        *
+        * @param sw_id                 Primary key of software identifier
+        * @param name                  Software identifier
+        * @param version               Package version
+        * @param installed             Installation status
+        * @return                              TRUE if update successful
+        */
+       bool (*update_sw_id)(sw_collector_db_t *this, uint32_t sw_id, char *name,
+                                                char *version, bool installed);
+
+       /**
+        * Update the package name
+        *
+        * @param package               Package name to be changed
+        * @param package_new   New package name
+        * @return                              TRUE if update successful
+        */
+       int (*update_package)(sw_collector_db_t *this, char *package,
+                                                                                                  char *package_new);
+
+       /**
         * Enumerate over all collected [installed] software identities
         *
         * @param type                  Query type (ALL, INSTALLED, DELETED)
+        * @param package               If not NULL enumerate over all package versions
         * @return                              Enumerator
         */
        enumerator_t* (*create_sw_enumerator)(sw_collector_db_t *this,
-                                                                                 sw_collector_db_query_t type);
+                                                                                 sw_collector_db_query_t type,
+                                                                                 char *package);
 
        /**
         * Destroy sw_collector_db_t object
diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.c b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.c
new file mode 100644 (file)
index 0000000..b5a8582
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "sw_collector_dpkg.h"
+
+typedef struct private_sw_collector_dpkg_t private_sw_collector_dpkg_t;
+
+/**
+ * Private data of an sw_collector_dpkg_t object.
+ */
+struct private_sw_collector_dpkg_t {
+
+       /**
+        * Public members of sw_collector_dpkg_state_t
+        */
+       sw_collector_dpkg_t public;
+
+};
+
+typedef struct {
+       /** public enumerator interface */
+       enumerator_t public;
+       /** dpkg output stream */
+       FILE *file;
+       /** current dpkg output line */
+       char line[BUF_LEN];
+} dpkg_enumerator_t;
+
+METHOD(enumerator_t, enumerate, bool,
+       dpkg_enumerator_t *this, va_list args)
+{
+       char **package, **arch, **version, *state, *pos;
+
+       VA_ARGS_VGET(args, package, arch, version);
+
+       while (TRUE)
+       {
+               if (!fgets(this->line, BUF_LEN, this->file))
+               {
+                       return FALSE;
+               }
+
+               *package = this->line;
+               pos = strchr(this->line, '\t');
+               if (!pos)
+               {
+                       return FALSE;
+               }
+               *pos = '\0';
+
+               *arch = ++pos;
+               pos = strchr(pos, '\t');
+               if (!pos)
+               {
+                       return FALSE;
+               }
+               *pos = '\0';
+
+               *version = ++pos;
+               pos = strchr(pos, '\t');
+               if (!pos)
+               {
+                       return FALSE;
+               }
+               *pos = '\0';
+
+               state = ++pos;
+               pos = strchr(pos, '\n');
+               if (!pos)
+               {
+                       return FALSE;
+               }
+               *pos = '\0';
+
+               if (streq(state, "install ok installed"))
+               {
+                       return TRUE;
+               }
+       }
+}
+
+METHOD(enumerator_t, enumerator_destroy, void,
+       dpkg_enumerator_t *this)
+{
+       pclose(this->file);
+       free(this);     
+}
+
+METHOD(sw_collector_dpkg_t, create_sw_enumerator, enumerator_t*,
+       private_sw_collector_dpkg_t *this)
+{
+       dpkg_enumerator_t *enumerator;
+       char cmd[] = "dpkg-query -W -f="
+                                "\'${Package}\t${Architecture}\t${Version}\t${Status}\n\'";
+       FILE *file;
+
+       file = popen(cmd, "r");
+       if (!file)
+       {
+               DBG1(DBG_IMC, "failed to run dpgk-query command");
+               return NULL;
+       }
+
+       INIT(enumerator,
+               .public = {
+                       .enumerate = enumerator_enumerate_default,
+                       .venumerate = _enumerate,
+                       .destroy = _enumerator_destroy,
+               },
+               .file = file,
+       );
+
+       return &enumerator->public;
+}
+
+METHOD(sw_collector_dpkg_t, destroy, void,
+       private_sw_collector_dpkg_t *this)
+{
+       free(this);
+}
+
+/**
+ * Described in header.
+ */
+sw_collector_dpkg_t *sw_collector_dpkg_create(void)
+{
+       private_sw_collector_dpkg_t *this;
+
+       INIT(this,
+               .public = {
+                       .create_sw_enumerator = _create_sw_enumerator,
+                       .destroy = _destroy,
+               },
+       );
+
+       return &this->public;
+}
diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.h b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_dpkg.h
new file mode 100644 (file)
index 0000000..eab792e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup sw_collector_dpkg_t sw_collector_dpkg
+ * @{ @ingroup sw_collector
+ */
+
+#ifndef SW_COLLECTOR_DPKG_H_
+#define SW_COLLECTOR_DPKG_H_
+
+#include <library.h>
+
+typedef struct sw_collector_dpkg_t sw_collector_dpkg_t;
+
+/**
+ * Software collector dpkg object
+ */
+struct sw_collector_dpkg_t {
+
+       /**
+        * List of installed software identifiers managed by the
+        * Debian "dpkg" package manager
+        *
+        * @return                              Enumerator
+        */
+       enumerator_t* (*create_sw_enumerator)(sw_collector_dpkg_t *this);
+
+       /**
+        * Destroy sw_collector_dpkg_t object
+        */
+       void (*destroy)(sw_collector_dpkg_t *this);
+
+};
+
+/**
+ * Create an sw_collector_dpkg_t instance
+ */
+sw_collector_dpkg_t* sw_collector_dpkg_create(void);
+
+#endif /** SW_COLLECTOR_DPKG_H_ @}*/
index 9371285..0fc6164 100644 (file)
@@ -18,8 +18,8 @@
 #include <time.h>
 
 #include "sw_collector_history.h"
+#include "sw_collector_dpkg.h"
 
-#include "imc/imc_os_info.h"
 #include "swima/swima_event.h"
 
 typedef struct private_sw_collector_history_t private_sw_collector_history_t;
@@ -35,29 +35,14 @@ struct private_sw_collector_history_t {
        sw_collector_history_t public;
 
        /**
-        * tagCreator
-        */
-       char *tag_creator;
-
-       /**
-        * OS string 'name_version-arch'
-        */
-       char *os;
-
-       /**
-        * Product string 'name version arch'
-        */
-       char *product;
-
-       /**
-        * OS info about endpoint
+        * Software Event Source Number
         */
-       imc_os_info_t *os_info;
+       uint8_t source;
 
        /**
-        * Software Event Source Number
+        * Reference to OS info object
         */
-       uint8_t source;
+       sw_collector_info_t *info;
 
        /**
         * Reference to collector database
@@ -66,16 +51,6 @@ struct private_sw_collector_history_t {
 
 };
 
-METHOD(sw_collector_history_t, get_os, char*,
-       private_sw_collector_history_t *this, char **product)
-{
-       if (product)
-       {
-               *product = this->product;
-       }
-       return this->os;
-}
-
 /**
  * Define auxiliary package_t list item object
  */
@@ -90,52 +65,9 @@ struct package_t {
 };
 
 /**
- * Replaces invalid character by a valid one
- */
-static void sanitize_uri(char *uri, char a, char b)
-{
-       char *pos = uri;
-
-       while (TRUE)
-       {
-               pos = strchr(pos, a);
-               if (!pos)
-               {
-                       break;
-               }
-               *pos = b;
-               pos++;
-       }
-}
-
-/**
- * Create software identifier
- */
-char* create_sw_id(char *tag_creator, char *os, char *package, char *version)
-{
-       char *pos, *sw_id;
-       size_t len;
-
-       /* Remove architecture from package name */
-       pos = strchr(package, ':');
-       len = pos ? (pos - package) : strlen(package);
-
-       /* Build software identifier */
-       if (asprintf(&sw_id, "%s__%s-%.*s%s%s", tag_creator, os, len, package,
-                                strlen(version) ? "-" : "", version) == -1)
-       {
-               return NULL;
-       }
-       sanitize_uri(sw_id, ':', '~');
-       sanitize_uri(sw_id, '+', '~');
-
-       return sw_id;
-}
-
-/**
  * Create package_t list item object
  */
-static package_t* create_package(char* tag_creator, char *os, chunk_t package,
+static package_t* create_package(sw_collector_info_t *info, chunk_t package,
                                                                 chunk_t version, chunk_t old_version)
 {
        package_t *this;
@@ -146,11 +78,11 @@ static package_t* create_package(char* tag_creator, char *os, chunk_t package,
                .old_version = strndup(old_version.ptr, old_version.len),
        )
 
-       this->sw_id = create_sw_id(tag_creator, os, this->package, this->version);
+       this->sw_id = info->create_sw_id(info, this->package, this->version);
        if (old_version.len)
        {
-               this->old_sw_id = create_sw_id(tag_creator, os, this->package,
-                                                                          this->old_version);
+               this->old_sw_id = info->create_sw_id(info, this->package,
+                                                                                                  this->old_version);
        }
 
        return this;
@@ -175,8 +107,8 @@ static void free_package(package_t *this)
 /**
  * Extract and parse a single package item
  */
-static package_t* extract_package(chunk_t item, char *tag_creator, char *os,
-                                                                 sw_collector_history_op_t op)
+static package_t* extract_package(chunk_t item, sw_collector_info_t *info,
+                                                                                               sw_collector_history_op_t op)
 {
        chunk_t package, version, old_version;
        package_t *p;
@@ -208,7 +140,7 @@ static package_t* extract_package(chunk_t item, char *tag_creator, char *os,
                        version = item;
                }
        }
-       p = create_package(tag_creator, os, package, version, old_version);
+       p = create_package(info, package, version, old_version);
 
        /* generate log entry */
        if (op == SW_OP_UPGRADE)
@@ -277,16 +209,22 @@ METHOD(sw_collector_history_t, extract_packages, bool,
        private_sw_collector_history_t *this, chunk_t args, uint32_t eid,
        sw_collector_history_op_t op)
 {
+       bool success = FALSE;
        package_t *p = NULL;
-       uint32_t sw_id;
        chunk_t item;
-       bool success = FALSE;
 
        eat_whitespace(&args);
 
        while (extract_token(&item, ')', &args))
        {
-               p = extract_package(item, this->tag_creator, this->os, op);
+               char *del_sw_id = NULL, *del_version = NULL;
+               char *nx, *px, *vx, *v1;
+               bool installed;
+               u_int sw_idx, ix;
+               uint32_t sw_id, sw_id_epoch_less = 0;
+               enumerator_t *e;
+
+               p = extract_package(item, this->info, op);
                if (!p)
                {
                        goto end;
@@ -299,29 +237,115 @@ METHOD(sw_collector_history_t, extract_packages, bool,
                        continue;
                }
 
-               sw_id = this->db->set_sw_id(this->db, p->sw_id, p->package,     p->version,
-                                                                       this->source, op != SW_OP_REMOVE, FALSE);
-               if (!sw_id)
+               switch (op)
                {
-                       goto end;
-               }
-               if (!this->db->add_sw_event(this->db, eid, sw_id, op != SW_OP_REMOVE ?
-                                       SWIMA_EVENT_ACTION_CREATION : SWIMA_EVENT_ACTION_DELETION))
-               {
-                       goto end;
+                       case SW_OP_REMOVE:
+                               /* prepare subsequent deletion sw event */
+                               del_sw_id = p->sw_id;
+                               del_version = p->version;
+                               break;
+                       case SW_OP_UPGRADE:
+                               /* prepare subsequent deletion sw event */
+                               del_sw_id = p->old_sw_id;
+                               del_version = p->old_version;
+                               /* fall through to next case */
+                       case SW_OP_INSTALL:
+                               sw_id = this->db->get_sw_id(this->db, p->sw_id, NULL, NULL,
+                                                                                       NULL, &installed);
+                               if (sw_id)
+                               {
+                                       /* sw identifier exists - update state to 'installed' */
+                                       if (installed)
+                                       {
+                                               /* this case should not occur */
+                                               DBG1(DBG_IMC, "  warning:  sw_id %d is already "
+                                                                         "installed", sw_id);
+                                       }
+                                       else if (!this->db->update_sw_id(this->db, sw_id, NULL,
+                                                                                                        NULL, TRUE))
+                                       {
+                                               goto end;
+                                       }
+                               }
+                               else
+                               {
+                                       /* new sw identifier - create with state 'installed' */
+                                       sw_id = this->db->set_sw_id(this->db, p->sw_id, p->package,
+                                                                                               p->version,     this->source, TRUE);
+                                       if (!sw_id)
+                                       {
+                                               goto end;
+                                       }
+                               }
+
+                               /* add creation sw event with current eid */
+                               if (!this->db->add_sw_event(this->db, eid, sw_id,
+                                                                       SWIMA_EVENT_ACTION_CREATION))
+                               {
+                                       goto end;
+                               }
+                               break;
                }
 
-               if (op == SW_OP_UPGRADE)
+               if (op != SW_OP_INSTALL)
                {
-                       sw_id = this->db->set_sw_id(this->db, p->old_sw_id, p->package,
-                                                                               p->old_version, this->source, FALSE,
-                                                                               FALSE);
-                       if (!sw_id)
+                       sw_id = 0;
+
+                       /* look for existing installed package versions */
+                       e = this->db->create_sw_enumerator(this->db, SW_QUERY_INSTALLED,
+                                                                                          p->package);
+                       if (!e)
                        {
                                goto end;
                        }
+
+                       while (e->enumerate(e, &sw_idx, &nx, &px, &vx, &ix))
+                       {
+                               if (streq(vx, del_version))
+                               {
+                                       /* full match with epoch */
+                                       sw_id = sw_idx;
+                                       break;
+                               }
+                               v1 = strchr(vx, ':');
+                               if (v1 && streq(++v1, del_version))
+                               {
+                                       /* match with stripped epoch */
+                                       sw_id_epoch_less = sw_idx;
+                               }
+                       }
+                       e->destroy(e);
+
+                       if (!sw_id && sw_id_epoch_less)
+                       {
+                               /* no full match - fall back to epoch-less match */
+                               sw_id = sw_id_epoch_less;
+                       }
+                       if (sw_id)
+                       {
+                               /* sw identifier exists - update state to 'deleted' */
+                               if (!this->db->update_sw_id(this->db, sw_id, NULL, NULL, FALSE))
+                               {
+                                       goto end;
+                               }
+                       }
+                       else
+                       {
+                               /* new sw identifier - create with state 'deleted' */
+                               sw_id = this->db->set_sw_id(this->db, del_sw_id, p->package,
+                                                                       del_version, this->source, FALSE);
+
+                               /* add creation sw event with eid = 1 */
+                               if (!sw_id || !this->db->add_sw_event(this->db, 1, sw_id,
+                                                                                       SWIMA_EVENT_ACTION_CREATION))
+                               {
+                                       goto end;
+                               }
+                       }
+
+                       /* add creation sw event with current eid */
                        if (!this->db->add_sw_event(this->db, eid, sw_id,
-                                                                               SWIMA_EVENT_ACTION_DELETION))
+                                                               SWIMA_EVENT_ACTION_DELETION))
                        {
                                goto end;
                        }
@@ -346,150 +370,136 @@ end:
 METHOD(sw_collector_history_t, merge_installed_packages, bool,
        private_sw_collector_history_t *this)
 {
-       FILE *file;
        uint32_t sw_id, count = 0;
-       char line[BUF_LEN], *pos, *package, *version, *state, *name;
-       bool success = FALSE;
-       char cmd[] = "dpkg-query -W -f=\'${Package}\t${Version}\t${Status}\n\'";
+       char package_arch[BUF_LEN];
+       char *package, *arch, *version, *v1, *name, *n1;
+       bool installed, success = FALSE;
+       sw_collector_dpkg_t *dpkg;
+       enumerator_t *enumerator;
 
        DBG1(DBG_IMC, "Merging:");
 
-       file = popen(cmd, "r");
-       if (!file)
+       dpkg = sw_collector_dpkg_create();
+       if (!dpkg)
        {
-               DBG1(DBG_IMC, "failed to run dpgk-query command");
                return FALSE;
        }
 
-       while (TRUE)
+       enumerator = dpkg->create_sw_enumerator(dpkg);
+       while (enumerator->enumerate(enumerator, &package, &arch, &version))
        {
-               if (!fgets(line, sizeof(line), file))
-               {
-                       break;
-               }
+               name = this->info->create_sw_id(this->info, package, version);
+               DBG3(DBG_IMC, "  %s merged", name);
 
-               package = line;
-               pos = strchr(line, '\t');
-               if (!pos)
+               sw_id = this->db->get_sw_id(this->db, name, NULL, NULL, NULL,
+                                                                       &installed);
+               if (sw_id)
                {
-                       goto end;
+                       if (!installed)
+                       {
+                               DBG1(DBG_IMC, "  warning: existing sw_id %u"
+                                                         " is not installed", sw_id);
+
+                               if (!this->db->update_sw_id(this->db, sw_id, name, version,
+                                                                                       TRUE))
+                               {
+                                       free(name);
+                                       goto end;
+                               }
+                       }
                }
-               *pos = '\0';
-
-               version = ++pos;
-               pos = strchr(pos, '\t');
-               if (!pos)
+               else
                {
-                       goto end;
+                       /* check for a Debian epoch number */
+                       v1 = strchr(version, ':');
+                       if (v1)
+                       {
+                               /* check for existing and installed epoch-less version */
+                               n1 = this->info->create_sw_id(this->info, package, ++v1);
+                               sw_id = this->db->get_sw_id(this->db, n1, NULL, NULL, NULL,
+                                                                                       &installed);
+                               free(n1);
+
+                               if (sw_id && installed)
+                               {
+                                       /* add epoch to existing version */
+                                       if (!this->db->update_sw_id(this->db, sw_id, name, version,
+                                                                                               installed))
+                                       {
+                                               free(name);
+                                               goto end;
+                                       }
+                               }
+                               else
+                               {
+                                       sw_id = 0;
+                               }
+                       }
                }
-               *pos = '\0';
 
-               state = ++pos;
-               pos = strchr(pos, '\n');
-               if (!pos)
+               if (!sw_id)
                {
-                       goto end;
-               }
-               *pos = '\0';
+                       /* Package name is stored with appended architecture */
+                       if (!streq(arch, "all"))
+                       {
+                               snprintf(package_arch, BUF_LEN, "%s:%s", package, arch);
+                               package = package_arch;
+                       }
 
-               if (!streq(state, "install ok installed"))
-               {
-                       continue;
-               }
-               name = create_sw_id(this->tag_creator, this->os, package, version);
-               DBG3(DBG_IMC, "  %s merged", name);
+                       /* new sw identifier - create with state 'installed' */
+                       sw_id = this->db->set_sw_id(this->db, name, package, version,
+                                                                               this->source, TRUE);
+
+                       /* add creation sw event with eid = 1 */
+                       if (!sw_id || !this->db->add_sw_event(this->db, 1, sw_id,
+                                                                               SWIMA_EVENT_ACTION_CREATION))
+                       {
+                               free(name);
+                               goto end;
+                       }
 
-               sw_id = this->db->set_sw_id(this->db, name, package, version,
-                                                                       this->source, TRUE, TRUE);
-               free(name);
-               if (!sw_id)
-               {
-                       goto end;
                }
+               free(name);
                count++;
        }
        success = TRUE;
-       DBG1(DBG_IMC, "  merged %u installed packages, %u registed in database",
+
+       DBG1(DBG_IMC, "  merged %u installed packages, %u registered in database",
                 count, this->db->get_sw_id_count(this->db, SW_QUERY_INSTALLED));
 
 end:
-       pclose(file);
+       enumerator->destroy(enumerator);
+       dpkg->destroy(dpkg);
+
        return success;
 }
 
 METHOD(sw_collector_history_t, destroy, void,
        private_sw_collector_history_t *this)
 {
-       this->os_info->destroy(this->os_info);
-       free(this->os);
-       free(this->product);
        free(this);
 }
 
 /**
  * Described in header.
  */
-sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db,
+sw_collector_history_t *sw_collector_history_create(sw_collector_info_t *info,
+                                                                                                       sw_collector_db_t *db,
                                                                                                        uint8_t source)
 {
        private_sw_collector_history_t *this;
-       chunk_t os_name, os_version, os_arch;
-       os_type_t os_type;
 
        INIT(this,
                .public = {
-                       .get_os = _get_os,
                        .extract_timestamp = _extract_timestamp,
                        .extract_packages = _extract_packages,
                        .merge_installed_packages = _merge_installed_packages,
                        .destroy = _destroy,
                },
-               .db = db,
                .source = source,
-               .os_info = imc_os_info_create(),
-               .tag_creator = lib->settings->get_str(lib->settings,
-                               "%s.tag_creator.regid", "strongswan.org", lib->ns),
+               .info = info,
+               .db = db,
        );
 
-       os_type = this->os_info->get_type(this->os_info);
-       os_name = this->os_info->get_name(this->os_info);
-       os_arch = this->os_info->get_version(this->os_info);
-
-       /* check if OS is supported */
-       if (os_type !=  OS_TYPE_DEBIAN && os_type != OS_TYPE_UBUNTU)
-       {
-               DBG1(DBG_IMC, "%.*s OS not supported", os_name.len, os_name.ptr);
-               destroy(this);
-               return NULL;
-       }
-
-       /* get_version() returns version followed by arch */ 
-       if (!extract_token(&os_version, ' ', &os_arch))
-       {
-               DBG1(DBG_IMC, "separation of OS version from arch failed");
-               destroy(this);
-               return NULL;
-       }
-
-       /* construct OS string */
-       if (asprintf(&this->os, "%.*s_%.*s-%.*s", os_name.len, os_name.ptr,
-                                                                                         os_version.len, os_version.ptr,
-                                                                                         os_arch.len, os_arch.ptr) == -1)
-       {
-               DBG1(DBG_IMC, "constructon of OS string failed");
-               destroy(this);
-               return NULL;
-       }
-
-       /* construct product string */
-       if (asprintf(&this->product, "%.*s %.*s %.*s", os_name.len, os_name.ptr,
-                                                                                         os_version.len, os_version.ptr,
-                                                                                         os_arch.len, os_arch.ptr) == -1)
-       {
-               DBG1(DBG_IMC, "constructon of product string failed");
-               destroy(this);
-               return NULL;
-       }
-
        return &this->public;
 }
index d1a3b21..857cc17 100644 (file)
 
 /**
  * @defgroup sw_collector_history_t sw_collector_history
- * @{ @ingroup imc_swima
+ * @{ @ingroup sw_collector
  */
 
 #ifndef SW_COLLECTOR_HISTORY_H_
 #define SW_COLLECTOR_HISTORY_H_
 
+#include "sw_collector_history.h"
+#include "sw_collector_info.h"
 #include "sw_collector_db.h"
 
 #include <library.h>
@@ -45,14 +47,6 @@ enum sw_collector_history_op_t {
 struct sw_collector_history_t {
 
        /**
-        * Get OS and product strings
-        *
-        * @param product               Product string formed from OS info
-        * @return                              OS string formed from OS info
-        */
-       char* (*get_os)(sw_collector_history_t *this, char **product);
-
-       /**
         * Extract timestamp from event in installation history
         *
         * @param args                  Arguments to be processed
@@ -90,10 +84,12 @@ struct sw_collector_history_t {
 /**
  * Create an sw_collector_history_t instance
  *
+ * @param info                         Internal reference to collector info
  * @param db                           Internal reference to collector database
  * @param source                       Software event source number
  */
-sw_collector_history_t* sw_collector_history_create(sw_collector_db_t *db,
+sw_collector_history_t* sw_collector_history_create(sw_collector_info_t *info,
+                                                                                                       sw_collector_db_t *db,
                                                                                                        uint8_t source);
 
 #endif /** SW_COLLECTOR_HISTORY_H_ @}*/
diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.c b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.c
new file mode 100644 (file)
index 0000000..0ac5f0d
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "sw_collector_info.h"
+
+#include <library.h>
+#include <utils/lexparser.h>
+
+typedef struct private_sw_collector_info_t private_sw_collector_info_t;
+
+/**
+ * Private data of an sw_collector_info_t object.
+ */
+struct private_sw_collector_info_t {
+
+       /**
+        * Public members of sw_collector_info_state_t
+        */
+       sw_collector_info_t public;
+
+       /**
+        * tagCreator
+        */
+       char *tag_creator;
+
+       /**
+        * OS string 'Name_Version-Arch'
+        */
+       char *os;
+
+       /**
+        * Product string 'Name Version Arch'
+        */
+       char *product;
+
+       /**
+        * OS info about endpoint
+        */
+       imc_os_info_t *os_info;
+
+};
+
+/**
+ * Replaces invalid character by a valid one
+ */
+static void sanitize_uri(char *uri, char a, char b)
+{
+       char *pos = uri;
+
+       while (TRUE)
+       {
+               pos = strchr(pos, a);
+               if (!pos)
+               {
+                       break;
+               }
+               *pos = b;
+               pos++;
+       }
+}
+
+METHOD(sw_collector_info_t, get_os_type, os_type_t,
+       private_sw_collector_info_t *this)
+{
+       return this->os_info->get_type(this->os_info);
+}
+
+METHOD(sw_collector_info_t, get_os, char*,
+       private_sw_collector_info_t *this, char **product)
+{
+       if (product)
+       {
+               *product = this->product;
+       }
+       return this->os;
+}
+
+METHOD(sw_collector_info_t, create_sw_id, char*,
+       private_sw_collector_info_t *this, char *package, char *version)
+{
+       char *pos, *sw_id;
+       size_t len;
+
+       /* Remove architecture from package name */
+       pos = strchr(package, ':');
+       len = pos ? (pos - package) : strlen(package);
+
+       /* Build software identifier */
+       if (asprintf(&sw_id, "%s__%s-%.*s%s%s", this->tag_creator, this->os, len,
+                                package, strlen(version) ? "-" : "", version) == -1)
+       {
+               return NULL;
+       }
+       sanitize_uri(sw_id, ':', '~');
+       sanitize_uri(sw_id, '+', '~');
+
+       return sw_id;
+}
+
+METHOD(sw_collector_info_t, destroy, void,
+       private_sw_collector_info_t *this)
+{
+       this->os_info->destroy(this->os_info);
+       free(this->os);
+       free(this->product);
+       free(this->tag_creator);
+       free(this);
+}
+
+/**
+ * Described in header.
+ */
+sw_collector_info_t *sw_collector_info_create(char *tag_creator)
+{
+       private_sw_collector_info_t *this;
+       chunk_t os_name, os_version, os_arch;
+
+       INIT(this,
+               .public = {
+                       .get_os_type = _get_os_type,
+                       .get_os = _get_os,
+                       .create_sw_id = _create_sw_id,
+                       .destroy = _destroy,
+               },
+               .os_info = imc_os_info_create(),
+               .tag_creator = strdup(tag_creator),
+       );
+
+       os_name = this->os_info->get_name(this->os_info);
+       os_arch = this->os_info->get_version(this->os_info);
+
+       /* get_version() returns version followed by arch */ 
+       if (!extract_token(&os_version, ' ', &os_arch))
+       {
+               DBG1(DBG_IMC, "separation of OS version from arch failed");
+               destroy(this);
+               return NULL;
+       }
+
+       /* construct OS string */
+       if (asprintf(&this->os, "%.*s_%.*s-%.*s", os_name.len, os_name.ptr,
+                                                                                         os_version.len, os_version.ptr,
+                                                                                         os_arch.len, os_arch.ptr) == -1)
+       {
+               DBG1(DBG_IMC, "constructon of OS string failed");
+               destroy(this);
+               return NULL;
+       }
+
+       /* construct product string */
+       if (asprintf(&this->product, "%.*s %.*s %.*s", os_name.len, os_name.ptr,
+                                                                                         os_version.len, os_version.ptr,
+                                                                                         os_arch.len, os_arch.ptr) == -1)
+       {
+               DBG1(DBG_IMC, "constructon of product string failed");
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.h b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_info.h
new file mode 100644 (file)
index 0000000..a54d788
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup sw_collector_info_t sw_collector_info
+ * @{ @ingroup sw_collector
+ */
+
+#ifndef SW_COLLECTOR_INFO_H_
+#define SW_COLLECTOR_INFO_H_
+
+typedef struct sw_collector_info_t sw_collector_info_t;
+
+#include "imc/imc_os_info.h"
+
+struct sw_collector_info_t {
+
+       /**
+        * Get OS type
+        *
+        * @return                              OS type
+        */
+       os_type_t (*get_os_type)(sw_collector_info_t *this);
+
+       /**
+        * Get OS and product strings
+        *
+        * @param product               Product string 'Name Version Arch'
+        * @return                              OS string      'Name_Version-Arch'
+        */
+       char* (*get_os)(sw_collector_info_t *this, char **product);
+
+       /**
+        * Create software identifier including tagCreator and OS
+        *
+        * @param package               Package string
+        * @param version               Version string
+        * @return                              Software Identifier string
+        */
+       char* (*create_sw_id)(sw_collector_info_t *this, char *package,
+                                                                                                        char *version);
+
+       /**
+        * Destroy sw_collector_info_t object
+        */
+       void (*destroy)(sw_collector_info_t *this);
+
+};
+
+/**
+ * Create an sw_collector_info_t instance
+ *
+ * @param tag_creator          Regid of tagCreator
+ */
+sw_collector_info_t* sw_collector_info_create(char *tag_creator);
+
+#endif /** SW_COLLECTOR_INFO_H_ @}*/
index 15108a0..6b9b7b9 100644 (file)
@@ -50,19 +50,19 @@ static json_object* create_rest_request(private_sw_collector_rest_api_t *this,
 {
        json_object *jrequest, *jarray, *jstring;
        char *name, *package, *version;
-       uint32_t i;
+       uint32_t sw_id, i;
        enumerator_t *e;
 
        jrequest = json_object_new_object();
        jarray = json_object_new_array();
        json_object_object_add(jrequest, "data", jarray);
 
-       e = this->db->create_sw_enumerator(this->db, type);
+       e = this->db->create_sw_enumerator(this->db, type, NULL);
        if (!e)
        {
                return NULL;
        }
-       while (e->enumerate(e, &name, &package, &version, &i))
+       while (e->enumerate(e, &sw_id, &name, &package, &version, &i))
        {
                jstring = json_object_new_string(name);
                json_object_array_add(jarray, jstring);
index e44ab6d..ca45230 100644 (file)
@@ -26,7 +26,7 @@
 typedef struct sw_collector_rest_api_t sw_collector_rest_api_t;
 
 /**
- * Software collector database object
+ * Software collector REST API object
  */
 struct sw_collector_rest_api_t {