385 lines
8.4 KiB
C
385 lines
8.4 KiB
C
/*
|
|
* Copyright (C) 2013-2014 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.
|
|
*/
|
|
|
|
#include "swid_inventory.h"
|
|
#include "swid_tag.h"
|
|
#include "swid_tag_id.h"
|
|
|
|
#include <collections/linked_list.h>
|
|
#include <bio/bio_writer.h>
|
|
#include <utils/debug.h>
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <libgen.h>
|
|
#include <errno.h>
|
|
|
|
typedef struct private_swid_inventory_t private_swid_inventory_t;
|
|
|
|
/**
|
|
* Private data of a swid_inventory_t object.
|
|
*
|
|
*/
|
|
struct private_swid_inventory_t {
|
|
|
|
/**
|
|
* Public swid_inventory_t interface.
|
|
*/
|
|
swid_inventory_t public;
|
|
|
|
/**
|
|
* Full SWID tags or just SWID tag IDs
|
|
*/
|
|
bool full_tags;
|
|
|
|
/**
|
|
* List of SWID tags or tag IDs
|
|
*/
|
|
linked_list_t *list;
|
|
};
|
|
|
|
static status_t generate_tags(private_swid_inventory_t *this, char *generator,
|
|
swid_inventory_t *targets, bool pretty, bool full)
|
|
{
|
|
FILE *file;
|
|
char command[512], line[2048];
|
|
chunk_t tag_creator, unique_sw_id, tag_file_path = chunk_empty;
|
|
swid_tag_id_t *tag_id;
|
|
swid_tag_t *tag;
|
|
status_t status = SUCCESS;
|
|
|
|
/* Assemble the SWID generator command */
|
|
snprintf(command, sizeof(command), "%s %s%s%s\n", generator,
|
|
(this->full_tags) ? "swid" : "software-id",
|
|
(this->full_tags && pretty) ? " --pretty" : "",
|
|
(this->full_tags && full) ? " --full" : "");
|
|
|
|
/* Open a pipe stream for reading the output of the dpkg-query commmand */
|
|
file = popen(command, "r");
|
|
if (!file)
|
|
{
|
|
DBG1(DBG_IMC, "failed to run swid_generator command");
|
|
return NOT_SUPPORTED;
|
|
}
|
|
if (this->full_tags)
|
|
{
|
|
bio_writer_t *writer;
|
|
chunk_t tag_encoding;
|
|
bool more_tags = TRUE, end_of_tag;
|
|
|
|
DBG2(DBG_IMC, "SWID tags generated by package manager:");
|
|
while (more_tags)
|
|
{
|
|
end_of_tag = FALSE;
|
|
writer = bio_writer_create(512);
|
|
do
|
|
{
|
|
if (fgets(line, sizeof(line), file) <= 0)
|
|
{
|
|
more_tags = FALSE;
|
|
end_of_tag = TRUE;
|
|
break;
|
|
}
|
|
if (line[0] == '\n')
|
|
{
|
|
end_of_tag = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
writer->write_data(writer, chunk_from_str(line));
|
|
}
|
|
}
|
|
while (!end_of_tag);
|
|
|
|
tag_encoding = writer->get_buf(writer);
|
|
|
|
/* remove trailing newline if present */
|
|
if (tag_encoding.len > 0 &&
|
|
tag_encoding.ptr[tag_encoding.len - 1] == '\n')
|
|
{
|
|
tag_encoding.len--;
|
|
}
|
|
DBG2(DBG_IMC, " %.*s", tag_encoding.len, tag_encoding.ptr);
|
|
|
|
tag = swid_tag_create(tag_encoding, tag_file_path);
|
|
this->list->insert_last(this->list, tag);
|
|
writer->destroy(writer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG2(DBG_IMC, "SWID tag IDs generated by package manager:");
|
|
while (TRUE)
|
|
{
|
|
char *separator;
|
|
size_t len;
|
|
|
|
if (fgets(line, sizeof(line), file) <= 0)
|
|
{
|
|
goto end;
|
|
}
|
|
len = strlen(line);
|
|
|
|
/* remove trailing newline if present */
|
|
if (len > 0 && line[len - 1] == '\n')
|
|
{
|
|
len--;
|
|
}
|
|
DBG2(DBG_IMC, " %.*s", len, line);
|
|
|
|
separator = strchr(line, '_');
|
|
if (!separator)
|
|
{
|
|
DBG1(DBG_IMC, "separatation of regid from unique software ID "
|
|
"failed");
|
|
status = FAILED;
|
|
goto end;
|
|
}
|
|
tag_creator = chunk_create(line, separator - line);
|
|
separator++;
|
|
|
|
unique_sw_id = chunk_create(separator, len - (separator - line));
|
|
tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
|
|
this->list->insert_last(this->list, tag_id);
|
|
|
|
if (fgets(line, sizeof(line), file) <= 0)
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
end:
|
|
pclose(file);
|
|
return status;
|
|
}
|
|
|
|
static bool collect_tags(private_swid_inventory_t *this, char *pathname,
|
|
swid_inventory_t *targets)
|
|
{
|
|
char *rel_name, *abs_name;
|
|
struct stat st;
|
|
bool success = FALSE;
|
|
enumerator_t *enumerator;
|
|
|
|
enumerator = enumerator_create_directory(pathname);
|
|
if (!enumerator)
|
|
{
|
|
DBG1(DBG_IMC, "directory '%s' can not be opened, %s",
|
|
pathname, strerror(errno));
|
|
return FALSE;
|
|
}
|
|
DBG2(DBG_IMC, "entering %s", pathname);
|
|
|
|
while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
|
|
{
|
|
char * start, *stop;
|
|
chunk_t tag_creator;
|
|
chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty;
|
|
if (!strstr(rel_name, "regid."))
|
|
{
|
|
continue;
|
|
}
|
|
if (S_ISDIR(st.st_mode))
|
|
{
|
|
/* In case of a targeted request */
|
|
if (targets->get_count(targets))
|
|
{
|
|
enumerator_t *target_enumerator;
|
|
swid_tag_id_t *tag_id;
|
|
bool match = FALSE;
|
|
|
|
target_enumerator = targets->create_enumerator(targets);
|
|
while (target_enumerator->enumerate(target_enumerator, &tag_id))
|
|
{
|
|
if (chunk_equals(tag_id->get_tag_creator(tag_id),
|
|
chunk_from_str(rel_name)))
|
|
{
|
|
match = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
target_enumerator->destroy(target_enumerator);
|
|
|
|
if (!match)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!collect_tags(this, abs_name, targets))
|
|
{
|
|
goto end;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* parse the regid filename into its components */
|
|
start = rel_name;
|
|
stop = strchr(start, '_');
|
|
if (!stop)
|
|
{
|
|
DBG1(DBG_IMC, " %s", rel_name);
|
|
DBG1(DBG_IMC, " '_' separator not found");
|
|
goto end;
|
|
}
|
|
tag_creator = chunk_create(start, stop-start);
|
|
start = stop + 1;
|
|
|
|
stop = strstr(start, ".swidtag");
|
|
if (!stop)
|
|
{
|
|
DBG1(DBG_IMC, " %s", rel_name);
|
|
DBG1(DBG_IMC, " swidtag postfix not found");
|
|
goto end;
|
|
}
|
|
unique_sw_id = chunk_create(start, stop-start);
|
|
tag_file_path = chunk_from_str(abs_name);
|
|
|
|
/* In case of a targeted request */
|
|
if (targets->get_count(targets))
|
|
{
|
|
enumerator_t *target_enumerator;
|
|
swid_tag_id_t *tag_id;
|
|
bool match = FALSE;
|
|
|
|
target_enumerator = targets->create_enumerator(targets);
|
|
while (target_enumerator->enumerate(target_enumerator, &tag_id))
|
|
{
|
|
if (chunk_equals(tag_id->get_unique_sw_id(tag_id, NULL),
|
|
unique_sw_id) &&
|
|
chunk_equals(tag_id->get_tag_creator(tag_id),
|
|
tag_creator))
|
|
{
|
|
match = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
target_enumerator->destroy(target_enumerator);
|
|
|
|
if (!match)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
DBG2(DBG_IMC, " %s", rel_name);
|
|
|
|
if (this->full_tags)
|
|
{
|
|
swid_tag_t *tag;
|
|
chunk_t *xml_tag;
|
|
|
|
xml_tag = chunk_map(abs_name, FALSE);
|
|
if (!xml_tag)
|
|
{
|
|
DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
|
|
strerror(errno));
|
|
goto end;
|
|
}
|
|
|
|
tag = swid_tag_create(*xml_tag, tag_file_path);
|
|
this->list->insert_last(this->list, tag);
|
|
chunk_unmap(xml_tag);
|
|
}
|
|
else
|
|
{
|
|
swid_tag_id_t *tag_id;
|
|
|
|
tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
|
|
this->list->insert_last(this->list, tag_id);
|
|
}
|
|
}
|
|
success = TRUE;
|
|
|
|
end:
|
|
enumerator->destroy(enumerator);
|
|
DBG2(DBG_IMC, "leaving %s", pathname);
|
|
|
|
return success;
|
|
}
|
|
|
|
METHOD(swid_inventory_t, collect, bool,
|
|
private_swid_inventory_t *this, char *directory, char *generator,
|
|
swid_inventory_t *targets, bool pretty, bool full)
|
|
{
|
|
/**
|
|
* Tags are generated by a package manager
|
|
*/
|
|
generate_tags(this, generator, targets, pretty, full);
|
|
|
|
/**
|
|
* Collect swidtag files by iteratively entering all directories in
|
|
* the tree under the "directory" path.
|
|
*/
|
|
return collect_tags(this, directory, targets);
|
|
}
|
|
|
|
METHOD(swid_inventory_t, add, void,
|
|
private_swid_inventory_t *this, void *item)
|
|
{
|
|
this->list->insert_last(this->list, item);
|
|
}
|
|
|
|
METHOD(swid_inventory_t, get_count, int,
|
|
private_swid_inventory_t *this)
|
|
{
|
|
return this->list->get_count(this->list);
|
|
}
|
|
|
|
METHOD(swid_inventory_t, create_enumerator, enumerator_t*,
|
|
private_swid_inventory_t *this)
|
|
{
|
|
return this->list->create_enumerator(this->list);
|
|
}
|
|
|
|
METHOD(swid_inventory_t, destroy, void,
|
|
private_swid_inventory_t *this)
|
|
{
|
|
if (this->full_tags)
|
|
{
|
|
this->list->destroy_offset(this->list, offsetof(swid_tag_t, destroy));
|
|
}
|
|
else
|
|
{
|
|
this->list->destroy_offset(this->list, offsetof(swid_tag_id_t, destroy));
|
|
}
|
|
free(this);
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
swid_inventory_t *swid_inventory_create(bool full_tags)
|
|
{
|
|
private_swid_inventory_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.collect = _collect,
|
|
.add = _add,
|
|
.get_count = _get_count,
|
|
.create_enumerator = _create_enumerator,
|
|
.destroy = _destroy,
|
|
},
|
|
.full_tags = full_tags,
|
|
.list = linked_list_create(),
|
|
);
|
|
|
|
return &this->public;
|
|
}
|