/*
* libosinfo: An installation tree for a (guest) OS
*
* Copyright (C) 2009-2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include
#include
#include
#include
#include
#include "osinfo_util_private.h"
typedef struct _CreateFromLocationAsyncData CreateFromLocationAsyncData;
struct _CreateFromLocationAsyncData {
SoupSession *session;
SoupMessage *message;
GFile *file;
gchar *content;
gchar *location;
gchar *treeinfo;
GTask *res;
};
static void create_from_location_async_data_free(CreateFromLocationAsyncData *data)
{
g_clear_object(&data->session);
g_clear_object(&data->message);
g_clear_object(&data->file);
g_clear_object(&data->res);
g_slice_free(CreateFromLocationAsyncData, data);
}
typedef struct _CreateFromLocationData CreateFromLocationData;
struct _CreateFromLocationData {
GMainLoop *main_loop;
GAsyncResult *res;
};
static void create_from_location_data_free(CreateFromLocationData *data)
{
g_object_unref(data->res);
g_main_loop_unref(data->main_loop);
g_slice_free(CreateFromLocationData, data);
}
/**
* osinfo_tree_error_quark:
*
* Gets a #GQuark representing the string "osinfo-tree-error"
*
* Returns: the #GQuark representing the string.
*
* Since: 0.1.0
*/
GQuark
osinfo_tree_error_quark(void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string("osinfo-tree-error");
return quark;
}
/**
* SECTION:osinfo_tree
* @short_description: An installation tree for a (guest) OS
* @see_also: #OsinfoOs
*
* #OsinfoTree is an entity representing an installation tree
* a (guest) operating system.
*/
struct _OsinfoTreePrivate
{
GWeakRef os;
};
G_DEFINE_TYPE_WITH_PRIVATE(OsinfoTree, osinfo_tree, OSINFO_TYPE_ENTITY);
enum {
PROP_0,
PROP_ARCHITECTURE,
PROP_URL,
PROP_TREEINFO_FAMILY,
PROP_TREEINFO_VARIANT,
PROP_TREEINFO_VERSION,
PROP_TREEINFO_ARCH,
PROP_KERNEL_PATH,
PROP_INITRD_PATH,
PROP_BOOT_ISO_PATH,
PROP_HAS_TREEINFO,
PROP_OS,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
static void
osinfo_tree_get_property(GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
OsinfoTree *tree = OSINFO_TREE(object);
switch (property_id) {
case PROP_ARCHITECTURE:
g_value_set_string(value,
osinfo_tree_get_architecture(tree));
break;
case PROP_URL:
g_value_set_string(value,
osinfo_tree_get_url(tree));
break;
case PROP_TREEINFO_FAMILY:
g_value_set_string(value,
osinfo_tree_get_treeinfo_family(tree));
break;
case PROP_TREEINFO_VARIANT:
g_value_set_string(value,
osinfo_tree_get_treeinfo_variant(tree));
break;
case PROP_TREEINFO_VERSION:
g_value_set_string(value,
osinfo_tree_get_treeinfo_version(tree));
break;
case PROP_TREEINFO_ARCH:
g_value_set_string(value,
osinfo_tree_get_treeinfo_arch(tree));
break;
case PROP_KERNEL_PATH:
g_value_set_string(value,
osinfo_tree_get_kernel_path(tree));
break;
case PROP_INITRD_PATH:
g_value_set_string(value,
osinfo_tree_get_initrd_path(tree));
break;
case PROP_BOOT_ISO_PATH:
g_value_set_string(value,
osinfo_tree_get_boot_iso_path(tree));
break;
case PROP_HAS_TREEINFO:
g_value_set_boolean(value,
osinfo_tree_has_treeinfo(tree));
break;
case PROP_OS:
g_value_take_object(value, osinfo_tree_get_os(tree));
break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
osinfo_tree_set_property(GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
OsinfoTree *tree = OSINFO_TREE(object);
switch (property_id) {
case PROP_ARCHITECTURE:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_ARCHITECTURE,
g_value_get_string(value));
break;
case PROP_URL:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_URL,
g_value_get_string(value));
break;
case PROP_TREEINFO_FAMILY:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_FAMILY,
g_value_get_string(value));
break;
case PROP_TREEINFO_VARIANT:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VARIANT,
g_value_get_string(value));
break;
case PROP_TREEINFO_VERSION:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VERSION,
g_value_get_string(value));
break;
case PROP_TREEINFO_ARCH:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_ARCH,
g_value_get_string(value));
break;
case PROP_KERNEL_PATH:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_KERNEL,
g_value_get_string(value));
break;
case PROP_INITRD_PATH:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_INITRD,
g_value_get_string(value));
break;
case PROP_BOOT_ISO_PATH:
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_BOOT_ISO,
g_value_get_string(value));
break;
case PROP_HAS_TREEINFO:
osinfo_entity_set_param_boolean(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_HAS_TREEINFO,
g_value_get_boolean(value));
break;
case PROP_OS:
osinfo_tree_set_os(tree, g_value_get_object(value));
break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
osinfo_tree_finalize(GObject *object)
{
/* Chain up to the parent class */
G_OBJECT_CLASS(osinfo_tree_parent_class)->finalize(object);
}
static void osinfo_tree_dispose(GObject *obj)
{
OsinfoTree *tree = OSINFO_TREE(obj);
g_weak_ref_clear(&tree->priv->os);
G_OBJECT_CLASS(osinfo_tree_parent_class)->dispose(obj);
}
/* Init functions */
static void
osinfo_tree_class_init(OsinfoTreeClass *klass)
{
GObjectClass *g_klass = G_OBJECT_CLASS(klass);
g_klass->dispose = osinfo_tree_dispose;
g_klass->finalize = osinfo_tree_finalize;
g_klass->get_property = osinfo_tree_get_property;
g_klass->set_property = osinfo_tree_set_property;
/**
* OsinfoTree:architecture:
*
* The target hardware architecture of this tree.
*/
properties[PROP_ARCHITECTURE] = g_param_spec_string("architecture",
"ARCHITECTURE",
_("CPU Architecture"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:url:
*
* The URL to this tree.
*/
properties[PROP_URL] = g_param_spec_string("url",
"URL",
_("The URL to this tree"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:kernel-path:
*
* The path to the kernel image in the install tree.
*/
properties[PROP_KERNEL_PATH] = g_param_spec_string("kernel-path",
"KernelPath",
_("The path to the kernel image"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:initrd-path:
*
* The path to the initrd image in the install tree.
*/
properties[PROP_INITRD_PATH] = g_param_spec_string("initrd-path",
"InitrdPath",
_("The path to the initrd image"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:boot-iso-path:
*
* The path to the boot ISO in the install tree
*/
properties[PROP_BOOT_ISO_PATH] = g_param_spec_string("boot-iso-path",
"BootISOPath",
_("The path to the bootable ISO image"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:has-treeinfo
*
* Whether the tree has treeinfo or not
*/
properties[PROP_HAS_TREEINFO] = g_param_spec_boolean("has-treeinfo",
"HasTreeinfo",
_("Whether the tree has treeinfo"),
FALSE /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:treeinfo-family
*
* The treeinfo family
*/
properties[PROP_TREEINFO_FAMILY] = g_param_spec_string("treeinfo-family",
"TreeInfoFamily",
_("The treeinfo family"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:treeinfo-variant
*
* The treeinfo variant
*/
properties[PROP_TREEINFO_VARIANT] = g_param_spec_string("treeinfo-variant",
"TreeInfoVariant",
_("The treeinfo variant"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:treeinfo-version
*
* The treeinfo version
*/
properties[PROP_TREEINFO_VERSION] = g_param_spec_string("treeinfo-version",
"TreeInfoVersion",
_("The treeinfo version"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:treeinfo-arch
*
* The treeinfo arch
*/
properties[PROP_TREEINFO_ARCH] = g_param_spec_string("treeinfo-arch",
"TreeInfoArch",
_("The treeinfo architecture"),
NULL /* default value */,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* OsinfoTree:os:
*
* Os information for the current tree. For tree stored in an
* #OsinfoDb, it will be filled when the database is loaded, otherwise
* the property will be filled after a successful call to
* osinfo_db_identify_tree().
*/
properties[PROP_OS] = g_param_spec_object("os",
"Os",
_("Information about the operating system on this tree"),
OSINFO_TYPE_OS,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(g_klass, LAST_PROP, properties);
}
static void
osinfo_tree_init(OsinfoTree *tree)
{
tree->priv = osinfo_tree_get_instance_private(tree);
g_weak_ref_init(&tree->priv->os, NULL);
}
/**
* osinfo_tree_new:
* @id: the id of the tree to be created
* @architecture: the architecture of the tree to be created
*
* Create a new tree entity
*
* Returns: (transfer full): A tree entity
*
* Since: 0.1.0
*/
OsinfoTree *osinfo_tree_new(const gchar *id,
const gchar *architecture)
{
OsinfoTree *tree;
tree = g_object_new(OSINFO_TYPE_TREE,
"id", id,
NULL);
if (architecture)
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_ARCHITECTURE,
architecture);
return tree;
}
static void on_tree_create_from_location_ready(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
CreateFromLocationData *data = (CreateFromLocationData *)user_data;
data->res = g_object_ref(res);
g_main_loop_quit(data->main_loop);
}
/**
* osinfo_tree_create_from_location:
* @location: the location of an installation tree
* @cancellable: (allow-none): a #GCancellable, or %NULL
* @error: The location where to store any error, or %NULL
*
* Creates a new #OsinfoTree for installation tree at @location. The @location
* could be a http:// or a https:// URI, or a local file.
*
* NOTE: Currently this only works for trees with a .treeinfo file
*
* Returns: (transfer full): a new #OsinfoTree , or NULL on error
*
* Since: 0.1.0
*/
OsinfoTree *osinfo_tree_create_from_location(const gchar *location,
GCancellable *cancellable,
GError **error)
{
CreateFromLocationData *data;
OsinfoTree *ret;
data = g_slice_new0(CreateFromLocationData);
data->main_loop = g_main_loop_new(g_main_context_get_thread_default(),
FALSE);
osinfo_tree_create_from_location_async(location,
G_PRIORITY_DEFAULT,
cancellable,
on_tree_create_from_location_ready,
data);
/* Loop till we get a reply (or time out) */
g_main_loop_run(data->main_loop);
ret = osinfo_tree_create_from_location_finish(data->res, error);
create_from_location_data_free(data);
return ret;
}
static gboolean is_str_empty(const gchar *str) {
guint8 i;
gboolean ret = TRUE;
if ((str == NULL) || (*str == 0))
return TRUE;
for (i = 0; i < strlen(str); i++)
if (!g_ascii_isspace(str[i])) {
ret = FALSE;
break;
}
return ret;
}
static gboolean is_unknown_group_or_key_error(const GError *error)
{
return (g_error_matches(error, G_KEY_FILE_ERROR,
G_KEY_FILE_ERROR_KEY_NOT_FOUND) ||
g_error_matches(error, G_KEY_FILE_ERROR,
G_KEY_FILE_ERROR_GROUP_NOT_FOUND));
}
static OsinfoTree *load_keyinfo(const gchar *location,
const gchar *content,
gsize length,
GError **error)
{
GKeyFile *file = g_key_file_new();
OsinfoTree *tree = NULL;
gchar *family = NULL;
gchar *variant = NULL;
gchar *version = NULL;
gchar *arch = NULL;
gchar *kernel = NULL;
gchar *initrd = NULL;
gchar *bootiso = NULL;
gchar *group = NULL;
if (!g_key_file_load_from_data(file, content, length,
G_KEY_FILE_NONE, error))
goto cleanup;
if (!(family = g_key_file_get_string(file, "general", "family", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (!(variant = g_key_file_get_string(file, "general", "variant", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (!(version = g_key_file_get_string(file, "general", "version", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (!(arch = g_key_file_get_string(file, "general", "arch", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (arch) {
group = g_strdup_printf("images-%s", arch);
if (!(kernel = g_key_file_get_string(file, group, "kernel", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (!(initrd = g_key_file_get_string(file, group, "initrd", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
if (!(bootiso = g_key_file_get_string(file, group, "boot.iso", error))) {
if (!is_unknown_group_or_key_error(*error))
goto cleanup;
g_clear_error(error);
}
g_clear_pointer(&group, g_free);
}
tree = osinfo_tree_new(location, arch ? arch : "i386");
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_URL,
location);
if (!is_str_empty(family))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_FAMILY,
family);
if (!is_str_empty(variant))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VARIANT,
variant);
if (!is_str_empty(version))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VERSION,
version);
if (!is_str_empty(arch))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_ARCH,
arch);
if (!is_str_empty(kernel))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_KERNEL,
kernel);
if (!is_str_empty(initrd))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_INITRD,
initrd);
if (!is_str_empty(bootiso))
osinfo_entity_set_param(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_BOOT_ISO,
bootiso);
cleanup:
g_free(family);
g_free(variant);
g_free(version);
g_free(arch);
g_free(kernel);
g_free(initrd);
g_free(bootiso);
g_key_file_free(file);
return tree;
}
static void
osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data,
const gchar *treeinfo);
static void on_content_read(GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CreateFromLocationAsyncData *data;
gsize length = 0;
GError *error = NULL;
OsinfoTree *ret;
data = (CreateFromLocationAsyncData *)user_data;
if (!g_input_stream_read_all_finish(G_INPUT_STREAM(source),
res,
&length,
&error)) {
g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo content: "));
g_task_return_error(data->res, error);
goto cleanup;
}
if (!(ret = load_keyinfo(data->location,
data->content,
length,
&error))) {
g_prefix_error(&error, _("Failed to process keyinfo file: "));
g_task_return_error(data->res, error);
goto cleanup;
}
g_task_return_pointer(data->res, ret, g_object_unref);
cleanup:
create_from_location_async_data_free(data);
}
static void on_soup_location_read(GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CreateFromLocationAsyncData *data;
GError *error = NULL;
GInputStream *stream;
goffset content_size;
data = (CreateFromLocationAsyncData *)user_data;
stream = soup_session_send_finish(SOUP_SESSION(source),
res,
&error);
if (stream == NULL ||
!SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(data->message))) {
/* It means no ".treeinfo" file has been found. Try again, this time
* looking for a "treeinfo" file. */
if (g_str_equal(data->treeinfo, ".treeinfo")) {
osinfo_tree_create_from_location_async_helper(data, "treeinfo");
return;
}
if (error == NULL) {
g_set_error_literal(&error,
OSINFO_TREE_ERROR,
OSINFO_TREE_ERROR_NO_TREEINFO,
soup_status_get_phrase(soup_message_get_status(data->message)));
}
g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo file: "));
g_task_return_error(data->res, error);
create_from_location_async_data_free(data);
return;
}
content_size = soup_message_headers_get_content_length(soup_message_get_response_headers(data->message));
data->content = g_malloc0(content_size);
g_input_stream_read_all_async(stream,
data->content,
content_size,
g_task_get_priority(data->res),
g_task_get_cancellable(data->res),
on_content_read,
data);
}
static void on_local_location_read(GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CreateFromLocationAsyncData *data;
GError *error = NULL;
gchar *content = NULL;
gsize length = 0;
OsinfoTree *ret = NULL;
data = (CreateFromLocationAsyncData *)user_data;
if (!g_file_load_contents_finish(G_FILE(source),
res,
&content,
&length,
NULL,
&error)) {
if (g_str_equal(data->treeinfo, ".treeinfo")) {
osinfo_tree_create_from_location_async_helper(data, "treeinfo");
return;
}
g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo file: "));
g_task_return_error(data->res, error);
goto cleanup;
}
if (!(ret = load_keyinfo(data->location,
content,
length,
&error))) {
g_prefix_error(&error, _("Failed to process keyinfo file: "));
g_task_return_error(data->res, error);
goto cleanup;
}
g_task_return_pointer(data->res, ret, g_object_unref);
cleanup:
create_from_location_async_data_free(data);
g_free(content);
}
static void
osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data,
const gchar *treeinfo)
{
gchar *location;
gboolean requires_soup;
g_return_if_fail(treeinfo != NULL);
requires_soup = osinfo_util_requires_soup(data->location);
if (!requires_soup &&
!g_str_has_prefix(data->location, "file://")) {
GError *error = NULL;
g_set_error_literal(&error,
OSINFO_TREE_ERROR,
OSINFO_TREE_ERROR_NOT_SUPPORTED_PROTOCOL,
_("URL protocol is not supported"));
g_task_return_error(data->res, error);
create_from_location_async_data_free(data);
return;
}
location = g_strdup_printf("%s/%s", data->location, treeinfo);
g_free(data->treeinfo);
data->treeinfo = g_strdup(treeinfo);
if (requires_soup) {
if (data->session == NULL)
data->session = soup_session_new_with_options(
"user-agent", "Wget/1.0",
NULL);
g_clear_object(&data->message);
data->message = soup_message_new("GET", location);
soup_session_send_async(data->session,
data->message,
#if SOUP_MAJOR_VERSION > 2
G_PRIORITY_DEFAULT,
#endif
g_task_get_cancellable(data->res),
on_soup_location_read,
data);
} else {
g_clear_object(&data->file);
data->file = g_file_new_for_uri(location);
g_file_load_contents_async(data->file,
g_task_get_cancellable(data->res),
on_local_location_read,
data);
}
g_free(location);
}
/**
* osinfo_tree_create_from_location_async:
* @location: the location of an installation tree
* @priority: the I/O priority of the request
* @cancellable: (allow-none): a #GCancellable, or %NULL
* @callback: Function to call when result of this call is ready
* @user_data: The user data to pass to @callback, or %NULL
*
* Asynchronous variant of #osinfo_tree_create_from_location.
*
* Since: 0.1.0
*/
void osinfo_tree_create_from_location_async(const gchar *location,
gint priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
CreateFromLocationAsyncData *data;
data = g_slice_new0(CreateFromLocationAsyncData);
data->res = g_task_new(NULL,
cancellable,
callback,
user_data);
g_task_set_priority(data->res, priority);
data->location = g_strdup(location);
osinfo_tree_create_from_location_async_helper(data, ".treeinfo");
}
/**
* osinfo_tree_create_from_location_finish:
* @res: a #GAsyncResult
* @error: The location where to store any error, or %NULL
*
* Finishes an asynchronous tree object creation process started with
* #osinfo_tree_create_from_location_async.
*
* Returns: (transfer full): a new #OsinfoTree , or NULL on error
*
* Since: 0.1.0
*/
OsinfoTree *osinfo_tree_create_from_location_finish(GAsyncResult *res,
GError **error)
{
GTask *task = G_TASK(res);
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
return g_task_propagate_pointer(task, error);
}
/**
* osinfo_tree_get_architecture:
* @tree: an #OsinfoTree instance
*
* Retrieves the target hardware architecture of the OS @tree provides.
*
* Returns: (transfer none): the hardware architecture, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_architecture(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_ARCHITECTURE);
}
/**
* osinfo_tree_get_url:
* @tree: an #OsinfoTree instance
*
* The URL to the @tree
*
* Returns: (transfer none): the URL, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_url(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_URL);
}
/**
* osinfo_tree_get_treeinfo_family:
* @tree: an #OsinfoTree instance
*
* If @tree has treeinfo, this function retrieves the expected family.
*
* Note: In practice, this will usually not be the exact copy of the family
* but rather a regular expression that matches it.
*
* Returns: (transfer none): the treeinfo family, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_treeinfo_family(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_FAMILY);
}
/**
* osinfo_tree_get_treeinfo_arch:
* @tree: an #OsinfoTree instance
*
* If @tree has treeinfo, this function retrieves the expected architecture.
*
* Note: In practice, this will usually not be the exact copy of the
* architecture but rather a regular expression that matches it.
*
* Returns: (transfer none): the treeinfo architecture, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_treeinfo_arch(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_ARCH);
}
/**
* osinfo_tree_get_treeinfo_variant:
* @tree: an #OsinfoTree instance
*
* If @tree has treeinfo, this function retrieves the expected variant.
*
* Note: In practice, this will usually not be the exact copy of the variant
* but rather a regular expression that matches it.
*
* Returns: (transfer none): the treeinfo variant, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_treeinfo_variant(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VARIANT);
}
/**
* osinfo_tree_get_treeinfo_version:
* @tree: an #OsinfoTree instance
*
* If @tree has treeinfo, this function retrieves the expected version.
*
* Note: In practice, this will usually not be the exact copy of version but
* rather a regular expression that matches it.
*
* Returns: (transfer none): the treeinfo version, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_treeinfo_version(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_TREEINFO_VERSION);
}
/**
* osinfo_tree_get_boot_iso_path:
* @tree: an #OsinfoTree instance
*
* Retrieves the path to the boot_iso image in the install tree.
*
* Returns: (transfer none): the path to boot_iso image, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_boot_iso_path(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_BOOT_ISO);
}
/**
* osinfo_tree_get_kernel_path:
* @tree: an #OsinfoTree instance
*
* Retrieves the path to the kernel image in the install tree.
*
* Note: This only applies to installer trees of 'linux' OS family.
*
* Returns: (transfer none): the path to kernel image, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_kernel_path(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_KERNEL);
}
/**
* osinfo_tree_get_initrd_path:
* @tree: an #OsinfoTree instance
*
* Retrieves the path to the initrd image in the install tree.
*
* Note: This only applies to installer trees of 'linux' OS family.
*
* Returns: (transfer none): the path to initrd image, or NULL
*
* Since: 0.1.0
*/
const gchar *osinfo_tree_get_initrd_path(OsinfoTree *tree)
{
return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_INITRD);
}
/**
* osinfo_tree_has_treeinfo:
* @tree: an #OsinfoTree instance
*
* Return whether a tree has treeinfo or not.
*
* Returns: TRUE if the tree has treeinfo. FALSE otherwise.
*
* Since: 1.3.0
*/
gboolean osinfo_tree_has_treeinfo(OsinfoTree *tree)
{
return osinfo_entity_get_param_value_boolean(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_HAS_TREEINFO);
}
/**
* osinfo_tree_get_os:
* @tree: an #OsinfoTree instance
*
* Returns: (transfer full): the operating system, or NULL
*
* Since: 1.5.0
*/
OsinfoOs *osinfo_tree_get_os(OsinfoTree *tree)
{
g_return_val_if_fail(OSINFO_IS_TREE(tree), NULL);
return g_weak_ref_get(&tree->priv->os);
}
/**
* osinfo_tree_set_os
* @tree: an #OsinfoTree instance
* @os: an #OsinfoOs instance
*
* Sets the #OsinfoOs associated to the #OsinfoTree instance.
*
* Since: 1.5.0
*/
void osinfo_tree_set_os(OsinfoTree *tree, OsinfoOs *os)
{
g_return_if_fail(OSINFO_IS_TREE(tree));
g_object_ref(os);
g_weak_ref_set(&tree->priv->os, os);
g_object_unref(os);
}
/**
* osinfo_tree_get_os_variants:
* @tree: an #OsinfoTree instance
*
* Gets the variants of the associated operating system.
*
* Returns: (transfer full): the operating system variant, or NULL
*
* Since: 1.5.0
*/
OsinfoOsVariantList *osinfo_tree_get_os_variants(OsinfoTree *tree)
{
OsinfoOs *os;
OsinfoOsVariantList *os_variants;
OsinfoOsVariantList *tree_variants;
GList *ids, *node;
OsinfoFilter *filter;
g_return_val_if_fail(OSINFO_IS_TREE(tree), NULL);
os = osinfo_tree_get_os(tree);
if (os == NULL)
return NULL;
os_variants = osinfo_os_get_variant_list(os);
g_object_unref(os);
ids = osinfo_entity_get_param_value_list(OSINFO_ENTITY(tree),
OSINFO_TREE_PROP_VARIANT);
filter = osinfo_filter_new();
tree_variants = osinfo_os_variantlist_new();
for (node = ids; node != NULL; node = node->next) {
osinfo_filter_clear_constraints(filter);
osinfo_filter_add_constraint(filter,
OSINFO_ENTITY_PROP_ID,
(const char *) node->data);
osinfo_list_add_filtered(OSINFO_LIST(tree_variants),
OSINFO_LIST(os_variants),
filter);
}
g_list_free(ids);
g_object_unref(filter);
g_object_unref(os_variants);
return tree_variants;
}
/**
* osinfo_tree_create_from_treeinfo:
* @treeinfo: a string representing the .treeinfo content
* @location: the location of the original @treeinfo
* @error: The location where to store any error, or %NULL
*
* Creates a new #OsinfoTree for installation tree represented by @treeinfo.
*
* Returns: (transfer full): a new #OsinfoTree, or NULL on error
*
* Since: 1.7.0
*/
OsinfoTree *osinfo_tree_create_from_treeinfo(const gchar *treeinfo,
const gchar *location,
GError **error)
{
g_return_val_if_fail(treeinfo != NULL, NULL);
g_return_val_if_fail(location != NULL, NULL);
return load_keyinfo(location, treeinfo, strlen(treeinfo), error);
}
#define match_regex(pattern, str) \
(((pattern) == NULL) || \
(((str) != NULL) && \
g_regex_match_simple((pattern), (str), 0, 0)))
/**
* osinfo_tree_matches:
* @tree: an unidentified #OsinfoTree instance
* @reference: a reference #OsinfoTree instance
*
* Determines whether the metadata for the unidentified @tree is a match
* for the @reference tree.
*
* The metadata in the unidentified @tree must be literal strings,
* while the metadata in the @reference tree must be regular expressions.
*
* Returns: #TRUE if @tree is a match for @reference. #FALSE otherwise
*
* Since: 1.10.0
*/
gboolean osinfo_tree_matches(OsinfoTree *tree, OsinfoTree *reference)
{
const gchar *tree_arch = osinfo_tree_get_architecture(tree);
const gchar *tree_treeinfo_family = osinfo_tree_get_treeinfo_family(tree);
const gchar *tree_treeinfo_variant = osinfo_tree_get_treeinfo_variant(tree);
const gchar *tree_treeinfo_version = osinfo_tree_get_treeinfo_version(tree);
const gchar *tree_treeinfo_arch = osinfo_tree_get_treeinfo_arch(tree);
const gchar *reference_arch = osinfo_tree_get_architecture(reference);
const gchar *reference_treeinfo_family = osinfo_tree_get_treeinfo_family(reference);
const gchar *reference_treeinfo_variant = osinfo_tree_get_treeinfo_variant(reference);
const gchar *reference_treeinfo_version = osinfo_tree_get_treeinfo_version(reference);
const gchar *reference_treeinfo_arch = osinfo_tree_get_treeinfo_arch(reference);
if (!osinfo_tree_has_treeinfo(reference))
return FALSE;
if ((!tree_arch ||
g_str_equal(reference_arch, tree_arch) ||
g_str_equal(reference_arch, "all")) &&
match_regex(reference_treeinfo_family, tree_treeinfo_family) &&
match_regex(reference_treeinfo_variant, tree_treeinfo_variant) &&
match_regex(reference_treeinfo_version, tree_treeinfo_version) &&
match_regex(reference_treeinfo_arch, tree_treeinfo_arch))
return TRUE;
return FALSE;
}