OsinfoImage object has been created to represent pre-installed images distributed by the OSes. This commit introduce libguestfs as dependency for libosinfo on linux and the rationale for using libguestfs was to be able to provide a similar approach for identifying the image as the approach we currently have for medias and trees. When creating a media from location, we use libguestfs to get: - osinfo: guestfs API returns "osinfo", which matches the distro's short-id - product-name: guestfs API returns what I assume to be the PRETTY_NAME in /etc/os-release and this will be used to actually identify the image (thus, requires explicit user-input when filling in the image element in osinfo-db Apart from that, osinfo_image_create_from_location() may be far from optimal as libguestfs doesn't offer an async API that we could take advantage of and simply makes no sense to try to re-implement what's already done (and well done) by libguestfs on our side just to gain an async API for _create_from_location(). https://gitlab.com/libosinfo/osinfo-db/issues/10 Signed-off-by: Fabiano Fidêncio <fidencio@xxxxxxxxxx> --- configure.ac | 9 + osinfo/Makefile.am | 7 +- osinfo/libosinfo.syms | 8 + osinfo/osinfo.h | 1 + osinfo/osinfo_image.c | 410 ++++++++++++++++++++++++++++++++++ osinfo/osinfo_image.h | 91 ++++++++ osinfo/osinfo_image_private.h | 43 ++++ po/POTFILES.in | 1 + 8 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 osinfo/osinfo_image.c create mode 100644 osinfo/osinfo_image.h create mode 100644 osinfo/osinfo_image_private.h diff --git a/configure.ac b/configure.ac index 00547a5..a885f40 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,15 @@ GLIB_ENCODED_VERSION="GLIB_VERSION_2_38" PKG_CHECK_MODULES([LIBXML], [libxml-2.0 >= 2.6.0]) PKG_CHECK_MODULES([LIBXSLT], [libxslt >= 1.0.0]) +have_guestfs=no +PKG_CHECK_MODULES([GUESTFS], [libguestfs], [have_guestfs=yes], [:]) +AC_SUBST(GUESTFS_CFLAGS) +AC_SUBST(GUESTFS_LIBS) + +if test "x$have_guestfs" = "xyes"; then + AC_DEFINE([HAVE_GUESTFS], 1, [libguestfs is present]) +fi + PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $GLIB_MINIMUM_VERSION gobject-2.0 gio-2.0]) GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=$GLIB_ENCODED_VERSION" GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MAX_ALLOWED=$GLIB_ENCODED_VERSION" diff --git a/osinfo/Makefile.am b/osinfo/Makefile.am index 86f6344..b53acd1 100644 --- a/osinfo/Makefile.am +++ b/osinfo/Makefile.am @@ -36,6 +36,7 @@ libosinfo_1_0_la_CFLAGS = \ $(GOBJECT_CFLAGS) \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \ + $(GUESTFS_CFLAGS) \ -DDATA_DIR='"$(datadir)"' \ -DPKG_DATA_DIR='"$(pkgdatadir)"' \ -DSYS_CONF_DIR='"$(sysconfdir)"' \ @@ -47,7 +48,8 @@ libosinfo_1_0_la_LIBADD = \ $(LIBXSLT_LIBS) \ $(GOBJECT_LIBS) \ $(GLIB_LIBS) \ - $(GIO_LIBS) + $(GIO_LIBS) \ + $(GUESTFS_LIBS) libosinfo_1_0_la_LDFLAGS = \ $(COVERAGE_LDFLAGS) \ @@ -98,6 +100,7 @@ libosinfo_1_0_include_HEADERS = \ osinfo_resourceslist.h \ osinfo_tree.h \ osinfo_treelist.h \ + osinfo_image.h \ $(NULL) nodist_libosinfo_1_0_include_HEADERS = \ @@ -141,6 +144,7 @@ libosinfo_c_files = \ osinfo_resourceslist.c \ osinfo_tree.c \ osinfo_treelist.c \ + osinfo_image.c \ osinfo_db.c \ osinfo_loader.c \ $(NULL) @@ -150,6 +154,7 @@ libosinfo_private_header_files = \ osinfo_install_script_private.h \ osinfo_product_private.h \ osinfo_media_private.h \ + osinfo_image_private.h \ ignore-value.h \ $(NULL) diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms index db9b8b2..fdbaaf3 100644 --- a/osinfo/libosinfo.syms +++ b/osinfo/libosinfo.syms @@ -532,6 +532,14 @@ LIBOSINFO_0.2.13 { LIBOSINFO_1.3.0 { global: osinfo_error_quark; + + osinfo_image_create_from_location; + osinfo_image_error_quark; + osinfo_image_get_architecture; + osinfo_image_get_os; + osinfo_image_get_type; + osinfo_image_get_url; + osinfo_image_new; } LIBOSINFO_0.2.13; /* Symbols in next release... diff --git a/osinfo/osinfo.h b/osinfo/osinfo.h index 8d0a595..9e8e604 100644 --- a/osinfo/osinfo.h +++ b/osinfo/osinfo.h @@ -65,6 +65,7 @@ #include <osinfo/osinfo_loader.h> #include <osinfo/osinfo_os_variant.h> #include <osinfo/osinfo_os_variantlist.h> +#include <osinfo/osinfo_image.h> #include <osinfo/osinfo_version.h> #endif diff --git a/osinfo/osinfo_image.c b/osinfo/osinfo_image.c new file mode 100644 index 0000000..e83160e --- /dev/null +++ b/osinfo/osinfo_image.c @@ -0,0 +1,410 @@ +/* + * libosinfo: An installed image of a (guest) OS + * + * Copyright (C) 2018 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 + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Fabiano Fidêncio <fidencio@xxxxxxxxxx> + */ + +#include <config.h> + +#include <osinfo/osinfo.h> +#include "osinfo_image_private.h" +#include <gio/gio.h> +#include <stdlib.h> +#include <string.h> +#include <glib/gi18n-lib.h> +#ifdef HAVE_GUESTFS +# include <guestfs.h> +#endif /* HAVE_GUESTFS */ + +GQuark +osinfo_image_error_quark(void) +{ + static GQuark quark = 0; + + if (!quark) + quark = g_quark_from_static_string("osinfo-image-error"); + + return quark; +} + +G_DEFINE_TYPE(OsinfoImage, osinfo_image, OSINFO_TYPE_ENTITY); + +#define OSINFO_IMAGE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + OSINFO_TYPE_IMAGE, \ + OsinfoImagePrivate)) + +/** + * SECTION:osinfo_image + * @short_description: An installation image for a (guest) OS + * @see_also: #OsinfoOs + * + * #OsinfoImage is an entity representing an installation image + * a (guest) operating system. + */ + +struct _OsinfoImagePrivate +{ + GWeakRef os; +}; + +enum { + PROP_0, + + PROP_ARCHITECTURE, + PROP_URL, + PROP_OS, + PROP_OSINFO, + PROP_PRODUCT_NAME, +}; + +static void +osinfo_image_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + OsinfoImage *image = OSINFO_IMAGE(object); + + switch (property_id) { + case PROP_ARCHITECTURE: + g_value_set_string(value, osinfo_image_get_architecture(image)); + break; + + case PROP_URL: + g_value_set_string(value, osinfo_image_get_url(image)); + break; + + case PROP_OS: + g_value_take_object(value, osinfo_image_get_os(image)); + break; + + case PROP_OSINFO: + g_value_set_string(value, osinfo_image_get_osinfo(image)); + break; + + case PROP_PRODUCT_NAME: + g_value_set_string(value, osinfo_image_get_product_name(image)); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +osinfo_image_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + OsinfoImage *image = OSINFO_IMAGE(object); + + switch (property_id) { + case PROP_ARCHITECTURE: + osinfo_entity_set_param(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_ARCHITECTURE, + g_value_get_string(value)); + break; + + case PROP_URL: + osinfo_entity_set_param(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_URL, + g_value_get_string(value)); + break; + + case PROP_OS: + osinfo_image_set_os(image, g_value_get_object(value)); + break; + + case PROP_OSINFO: + osinfo_entity_set_param(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_OSINFO, + g_value_get_string(value)); + break; + + case PROP_PRODUCT_NAME: + osinfo_entity_set_param(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_PRODUCT_NAME, + g_value_get_string(value)); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +osinfo_image_finalize(GObject *object) +{ + /* Chain up to the parent class */ + G_OBJECT_CLASS(osinfo_image_parent_class)->finalize(object); +} + +/* Init functions */ +static void +osinfo_image_class_init(OsinfoImageClass *klass) +{ + GObjectClass *g_klass = G_OBJECT_CLASS(klass); + GParamSpec *pspec; + + g_klass->finalize = osinfo_image_finalize; + g_klass->get_property = osinfo_image_get_property; + g_klass->set_property = osinfo_image_set_property; + g_type_class_add_private(klass, sizeof(OsinfoImagePrivate)); + + /** + * OsinfoImage:architecture: + * + * The target hardware architecture of this image. + */ + pspec = g_param_spec_string("architecture", + "ARCHITECTURE", + _("CPU Architecture"), + NULL /* default value */, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property(g_klass, PROP_ARCHITECTURE, pspec); + + /** + * OsinfoImage:url: + * + * The URL to this image. + */ + pspec = g_param_spec_string("url", + "URL", + _("The URL to this image"), + NULL /* default value */, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property(g_klass, PROP_URL, pspec); + + /** + * OsinfoImage:os: + * + * Os information for the current image. For image 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_image(). + */ + pspec = g_param_spec_object("os", + "Os", + _("Information about the operating system on this image"), + OSINFO_TYPE_OS, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property(g_klass, PROP_OS, pspec); +} + +static void +osinfo_image_init(OsinfoImage *image) +{ + image->priv = OSINFO_IMAGE_GET_PRIVATE(image); +} + +OsinfoImage *osinfo_image_new(const gchar *id, + const gchar *architecture) +{ + OsinfoImage *image; + + image = g_object_new(OSINFO_TYPE_IMAGE, + "id", id, + NULL); + + osinfo_entity_set_param(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_ARCHITECTURE, + architecture); + + return image; +} + +static gboolean osinfo_image_get_guestfs_info(const gchar *location, + gchar **arch, + gchar **osinfo, + gchar **product_name) +{ + gboolean ret = FALSE; + +#ifdef HAVE_GUESTFS + gchar **roots = NULL; + guestfs_h *guest; + + guest = guestfs_create(); + if (guest == NULL) + return FALSE; + + if (guestfs_add_drive_opts(guest, location, + GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, + -1) == -1) + goto done; + + if (guestfs_launch(guest) == -1) + goto done; + + roots = guestfs_inspect_os(guest); + if (roots == NULL || roots[0] == NULL) + goto done; + + *arch = guestfs_inspect_get_arch(guest, roots[0]); + *osinfo = guestfs_inspect_get_osinfo(guest, roots[0]); + *product_name = guestfs_inspect_get_product_name(guest, roots[0]); + + ret = TRUE; + + done: + if (roots != NULL) { + for (int i = 0; roots[i] != NULL; i++) + g_free(roots[i]); + } + g_free(roots); + guestfs_close(guest); +#endif /* HAVE_GUESTFS */ + + return ret; +} + +/** + * osinfo_image_create_from_location: + * @location: the location of an installation image + * + * Creates a new #OsinfoImage for installation image at @location. The @location + * could be any URI that GIO can handle or a local path. + * + * Returns: (transfer full): a new #OsinfoImage , or NULL on error + */ +OsinfoImage *osinfo_image_create_from_location(const gchar *location) +{ + OsinfoImage *ret = NULL; + gchar *arch = NULL; + gchar *product_name = NULL; + gchar *osinfo = NULL; + + if (!osinfo_image_get_guestfs_info(location, &arch, &osinfo, &product_name)) + return NULL; + + ret = osinfo_image_new(location, arch ? arch : "i386"); + + osinfo_entity_set_param(OSINFO_ENTITY(ret), + OSINFO_IMAGE_PROP_URL, + location); + + if (osinfo != NULL) + osinfo_entity_set_param(OSINFO_ENTITY(ret), + OSINFO_IMAGE_PROP_OSINFO, + osinfo); + + if (product_name != NULL) + osinfo_entity_set_param(OSINFO_ENTITY(ret), + OSINFO_IMAGE_PROP_PRODUCT_NAME, + product_name); + + g_free(arch); + g_free(osinfo); + g_free(product_name); + + return ret; +} + +/** + * osinfo_image_get_architecture: + * @image: an #OsinfoImage instance + * + * Retrieves the target hardware architecture of the OS @image provides. + * + * Returns: (transfer none): the hardware architecture, or NULL + */ +const gchar *osinfo_image_get_architecture(OsinfoImage *image) +{ + return osinfo_entity_get_param_value(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_ARCHITECTURE); +} + +/** + * osinfo_image_get_url: + * @image: an #OsinfoImage instance + * + * The URL to the @image + * + * Returns: (transfer none): the URL, or NULL + */ +const gchar *osinfo_image_get_url(OsinfoImage *image) +{ + return osinfo_entity_get_param_value(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_URL); +} + +/** + * osinfo_image_get_os: + * @image: an #OsinfoImage instance + * + * Returns: (transfer full): the operating system, or NULL + */ +OsinfoOs *osinfo_image_get_os(OsinfoImage *image) +{ + g_return_val_if_fail(OSINFO_IS_IMAGE(image), NULL); + + return g_weak_ref_get(&image->priv->os); +} + +void osinfo_image_set_os(OsinfoImage *image, OsinfoOs *os) +{ + g_return_if_fail(OSINFO_IS_IMAGE(image)); + + g_object_ref(os); + g_weak_ref_set(&image->priv->os, os); + g_object_unref(os); +} + +/** + * osinfo_image_get_product_name: + * @image: an #OsinfoImage instance + * + * Returns: (transfer none): the image's product name, or NULL + */ +const gchar *osinfo_image_get_product_name(OsinfoImage *image) +{ + return osinfo_entity_get_param_value(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_PRODUCT_NAME); +} + + +/** + * osinfo_image_get_osinfo: + * @image: an #OsinfoImage instance + * + * Returns: (transfer none): the image's osinfo, or NULL + */ +const gchar *osinfo_image_get_osinfo(OsinfoImage *image) +{ + return osinfo_entity_get_param_value(OSINFO_ENTITY(image), + OSINFO_IMAGE_PROP_OSINFO); +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/osinfo/osinfo_image.h b/osinfo/osinfo_image.h new file mode 100644 index 0000000..1941afb --- /dev/null +++ b/osinfo/osinfo_image.h @@ -0,0 +1,91 @@ +/* + * libosinfo: An installed image of a (guest) OS + * + * Copyright (C) 2018 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 + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Fabiano Fidêncio <fidencio@xxxxxxxxxx> + */ + +#include <glib-object.h> +#include <gio/gio.h> +#include <osinfo/osinfo_entity.h> + +#ifndef __OSINFO_IMAGE_H__ +#define __OSINFO_IMAGE_H__ + +GQuark +osinfo_image_error_quark (void) G_GNUC_CONST; + +#define OSINFO_IMAGE_ERROR (osinfo_image_error_quark ()) + + +/* + * Type macros. + */ +#define OSINFO_TYPE_IMAGE (osinfo_image_get_type ()) +#define OSINFO_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSINFO_TYPE_IMAGE, OsinfoImage)) +#define OSINFO_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSINFO_TYPE_IMAGE)) +#define OSINFO_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OSINFO_TYPE_IMAGE, OsinfoImageClass)) +#define OSINFO_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OSINFO_TYPE_IMAGE)) +#define OSINFO_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OSINFO_TYPE_IMAGE, OsinfoImageClass)) + +typedef struct _OsinfoImage OsinfoImage; + +typedef struct _OsinfoImageClass OsinfoImageClass; + +typedef struct _OsinfoImagePrivate OsinfoImagePrivate; + +#define OSINFO_IMAGE_PROP_ARCHITECTURE "architecture" +#define OSINFO_IMAGE_PROP_URL "url" + +/* object */ +struct _OsinfoImage +{ + OsinfoEntity parent_instance; + + /* public */ + + /* private */ + OsinfoImagePrivate *priv; +}; + +/* class */ +struct _OsinfoImageClass +{ + /*< private >*/ + OsinfoEntityClass parent_class; + + /* class members */ +}; + +GType osinfo_image_get_type(void); + +OsinfoImage *osinfo_image_new(const gchar *id, const gchar *architecture); +OsinfoImage *osinfo_image_create_from_location(const gchar *location); +OsinfoOs *osinfo_image_get_os(OsinfoImage *image); +const gchar *osinfo_image_get_architecture(OsinfoImage *image); +const gchar *osinfo_image_get_url(OsinfoImage *image); + +#endif /* __OSINFO_IMAGE_H__ */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/osinfo/osinfo_image_private.h b/osinfo/osinfo_image_private.h new file mode 100644 index 0000000..3398649 --- /dev/null +++ b/osinfo/osinfo_image_private.h @@ -0,0 +1,43 @@ +/* + * libosinfo: An installed image of a (guest) OS + * + * Copyright (C) 2018 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 + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Fabiano Fidêncio <fidencio@xxxxxxxxxx> + */ + +#include <osinfo/osinfo_image.h> + +#ifndef __OSINFO_IMAGE_PRIVATE_H__ +#define __OSINFO_IMAGE_PRIVATE_H__ + +#define OSINFO_IMAGE_PROP_OSINFO "osinfo" +#define OSINFO_IMAGE_PROP_PRODUCT_NAME "product-name" + +void osinfo_image_set_os(OsinfoImage *image, OsinfoOs *os); +const gchar *osinfo_image_get_osinfo(OsinfoImage* image); +const gchar *osinfo_image_get_product_name(OsinfoImage* image); + +#endif /* __OSINFO_IMAGE_PRIVATE_H__ */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/po/POTFILES.in b/po/POTFILES.in index fc81f42..2a714df 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,6 +3,7 @@ osinfo/osinfo_deployment.c osinfo/osinfo_devicelink.c osinfo/osinfo_devicelinkfilter.c osinfo/osinfo_entity.c +osinfo/osinfo_image.c osinfo/osinfo_install_config_param.c osinfo/osinfo_install_script.c osinfo/osinfo_list.c -- 2.19.1 _______________________________________________ Libosinfo mailing list Libosinfo@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libosinfo