sw-collector: Check for epoch-less Debian package versions
This commit is contained in:
parent
eab650d62f
commit
5b1dbc3a8d
|
@ -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 = \
|
||||
|
|
|
@ -23,14 +23,18 @@
|
|||
# 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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
@ -107,14 +105,38 @@ struct sw_collector_db_t {
|
|||
uint32_t (*get_sw_id_count)(sw_collector_db_t *this,
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_ @}*/
|
|
@ -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;
|
||||
|
@ -34,31 +34,16 @@ 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
|
||||
*/
|
||||
imc_os_info_t *os_info;
|
||||
|
||||
/**
|
||||
* Software Event Source Number
|
||||
*/
|
||||
uint8_t source;
|
||||
|
||||
/**
|
||||
* Reference to OS info object
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -89,53 +64,10 @@ struct package_t {
|
|||
char *old_sw_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
package_t *p = NULL;
|
||||
uint32_t sw_id;
|
||||
chunk_t item;
|
||||
bool success = FALSE;
|
||||
package_t *p = NULL;
|
||||
chunk_t item;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
package = line;
|
||||
pos = strchr(line, '\t');
|
||||
if (!pos)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
*pos = '\0';
|
||||
|
||||
version = ++pos;
|
||||
pos = strchr(pos, '\t');
|
||||
if (!pos)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
*pos = '\0';
|
||||
|
||||
state = ++pos;
|
||||
pos = strchr(pos, '\n');
|
||||
if (!pos)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
*pos = '\0';
|
||||
|
||||
if (!streq(state, "install ok installed"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
name = create_sw_id(this->tag_creator, this->os, package, version);
|
||||
name = this->info->create_sw_id(this->info, package, version);
|
||||
DBG3(DBG_IMC, " %s merged", name);
|
||||
|
||||
sw_id = this->db->set_sw_id(this->db, name, package, version,
|
||||
this->source, TRUE, TRUE);
|
||||
free(name);
|
||||
sw_id = this->db->get_sw_id(this->db, name, NULL, NULL, NULL,
|
||||
&installed);
|
||||
if (sw_id)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sw_id)
|
||||
{
|
||||
goto end;
|
||||
/* Package name is stored with appended architecture */
|
||||
if (!streq(arch, "all"))
|
||||
{
|
||||
snprintf(package_arch, BUF_LEN, "%s:%s", package, arch);
|
||||
package = package_arch;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
|
||||
/**
|
||||
* @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>
|
||||
|
@ -44,14 +46,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
|
||||
*
|
||||
|
@ -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_ @}*/
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_ @}*/
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue