[virt-tools-list] [libosinfo 2/4] Add osinfo_db_guess_os_from_location()
Daniel P. Berrange
berrange at redhat.com
Tue Aug 30 15:37:33 UTC 2011
On Tue, Aug 23, 2011 at 12:31:24AM +0300, Zeeshan Ali (Khattak) wrote:
> From: "Zeeshan Ali (Khattak)" <zeeshanak at gnome.org>
>
> Add API to guess OS given an installation media location.
> ---
> docs/reference/Libosinfo-sections.txt | 1 +
> osinfo/libosinfo.syms | 2 +
> osinfo/osinfo_db.c | 191 ++++++++++++++++++++++++++++++++-
> osinfo/osinfo_db.h | 30 +++++
> 4 files changed, 223 insertions(+), 1 deletions(-)
>
> diff --git a/docs/reference/Libosinfo-sections.txt b/docs/reference/Libosinfo-sections.txt
> index 0aee98f..80816e6 100644
> --- a/docs/reference/Libosinfo-sections.txt
> +++ b/docs/reference/Libosinfo-sections.txt
> @@ -18,6 +18,7 @@ osinfo_db_add_os
> osinfo_db_add_platform
> osinfo_db_add_device
> osinfo_db_add_deployment
> +osinfo_db_guess_os_from_location
> osinfo_db_unique_values_for_property_in_os
> osinfo_db_unique_values_for_property_in_platform
> osinfo_db_unique_values_for_property_in_device
> diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms
> index aadcbc3..2b2a03e 100644
> --- a/osinfo/libosinfo.syms
> +++ b/osinfo/libosinfo.syms
> @@ -1,6 +1,7 @@
> LIBOSINFO_0.0.1 {
> global:
> osinfo_db_get_type;
> + osinfo_install_media_error_quark;
> osinfo_db_new;
> osinfo_db_get_platform;
> osinfo_db_get_device;
> @@ -15,6 +16,7 @@ LIBOSINFO_0.0.1 {
> osinfo_db_add_platform;
> osinfo_db_add_device;
> osinfo_db_add_deployment;
> + osinfo_db_guess_os_from_location;
> osinfo_db_unique_values_for_property_in_os;
> osinfo_db_unique_values_for_property_in_platform;
> osinfo_db_unique_values_for_property_in_device;
> diff --git a/osinfo/osinfo_db.c b/osinfo/osinfo_db.c
> index 4c37365..d8e6b7c 100644
> --- a/osinfo/osinfo_db.c
> +++ b/osinfo/osinfo_db.c
> @@ -23,11 +23,54 @@
> */
>
> #include <osinfo/osinfo.h>
> +#include <gio/gio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +
> +#define MAX_VOLUME 32
> +#define MAX_SYSTEM 32
> +#define MAX_PUBLISHER 128
> +
> +#define PVD_OFFSET 0x00008000
> +#define BOOTABLE_TAG "EL TORITO SPECIFICATION"
> +
> +typedef struct _PrimaryVolumeDescriptor PrimaryVolumeDescriptor;
> +
> +struct _PrimaryVolumeDescriptor {
> + guint8 ignored[8];
> + gchar system[MAX_SYSTEM]; /* System ID */
> + gchar volume[MAX_VOLUME]; /* Volume ID */
> + guint8 ignored2[246];
> + gchar publisher[MAX_PUBLISHER]; /* Publisher ID */
> + guint8 ignored3[1602];
> +};
> +
> +typedef struct _SupplementaryVolumeDescriptor SupplementaryVolumeDescriptor;
> +
> +struct _SupplementaryVolumeDescriptor {
> + guint8 ignored[7];
> + gchar system[MAX_SYSTEM]; /* System ID */
> +};
> +
> +GQuark
> +osinfo_install_media_error_quark (void)
> +{
> + static GQuark quark = 0;
> +
> + if (!quark)
> + quark = g_quark_from_static_string ("osinfo-install-media-error");
> +
> + return quark;
> +}
>
> G_DEFINE_TYPE (OsinfoDb, osinfo_db, G_TYPE_OBJECT);
>
> #define OSINFO_DB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), OSINFO_TYPE_DB, OsinfoDbPrivate))
>
> +#define str_contains(str, substr) ((str) && \
> + (substr) && \
> + strstr((str), (substr)) != NULL)
> +
> /**
> * SECTION:osinfo_db
> * @short_description: Database of all entities
> @@ -144,7 +187,6 @@ OsinfoOs *osinfo_db_get_os(OsinfoDb *db, const gchar *id)
> return OSINFO_OS(osinfo_list_find_by_id(OSINFO_LIST(db->priv->oses), id));
> }
>
> -
> /**
> * osinfo_db_get_deployment:
> * @db: the database
> @@ -316,6 +358,153 @@ void osinfo_db_add_deployment(OsinfoDb *db, OsinfoDeployment *deployment)
> osinfo_list_add(OSINFO_LIST(db->priv->deployments), OSINFO_ENTITY(deployment));
> }
>
> +/**
> + * osinfo_db_guess_os_from_location:
> + * @db: the database
> + * @location: the location of an installation media
> + * @cancellable (allow-none): a #GCancellable, or %NULL
> + * @error: The location where to store any error, or %NULL
> + *
> + * The @location could be any URI that GIO can handle or a local path.
> + *
> + * NOTE: Currently this only works for ISO images/devices.
> + *
> + * Returns: (transfer none): the operating system, or NULL if guessing failed
> + */
> +OsinfoOs *osinfo_db_guess_os_from_location(OsinfoDb *db,
> + const gchar *location,
> + GCancellable *cancellable,
> + GError **error)
> +{
> + OsinfoOs *ret = NULL;
> + PrimaryVolumeDescriptor pvd;
> + SupplementaryVolumeDescriptor svd;
> + GFile *file;
> + GFileInputStream *stream;
> + GList *oss = NULL;
> + GList *os_iter;
> +
> + g_return_val_if_fail(OSINFO_IS_DB(db), NULL);
> + g_return_val_if_fail(location != NULL, NULL);
> + g_return_val_if_fail(error == NULL || *error == NULL, NULL);
> +
> + file = g_file_new_for_commandline_arg(location);
> + stream = g_file_read(file, NULL, error);
> + if (error != NULL && *error != NULL) {
> + g_prefix_error(error, "Failed to open file");
> +
> + goto EXIT;
> + }
> +
> + memset(&pvd, 0, sizeof(pvd));
> + if (g_input_stream_skip(G_INPUT_STREAM(stream),
> + PVD_OFFSET,
> + cancellable,
> + error) < sizeof(pvd)) {
> + if (*error)
> + g_prefix_error(error, "Failed to skip %d bytes", PVD_OFFSET);
> + else
> + g_set_error(error,
> + OSINFO_INSTALL_MEDIA_ERROR,
> + OSINFO_INSTALL_MEDIA_ERROR_NO_DESCRIPTORS,
> + "No volume descriptors");
> +
> + goto EXIT;
> + }
> +
> + if (g_input_stream_read(G_INPUT_STREAM(stream),
> + &pvd,
> + sizeof(pvd),
> + cancellable,
> + error) < sizeof(pvd)) {
> + if (*error)
> + g_prefix_error(error, "Failed to read primary volume descriptor");
> + else
> + g_set_error(error,
> + OSINFO_INSTALL_MEDIA_ERROR,
> + OSINFO_INSTALL_MEDIA_ERROR_NO_PVD,
> + "Primary volume descriptor unavailable");
> +
> + goto EXIT;
> + }
> +
> + pvd.volume[MAX_VOLUME - 1] = 0;
> + pvd.system[MAX_SYSTEM - 1] = 0;
> + pvd.publisher[MAX_PUBLISHER - 1] = 0;
> +
> + if (pvd.volume[0] && (pvd.system[0] == 0 && pvd.publisher[0] == 0)) {
> + g_set_error(error,
> + OSINFO_INSTALL_MEDIA_ERROR,
> + OSINFO_INSTALL_MEDIA_ERROR_INSUFFIENT_METADATA,
> + "Insufficient metadata on installation media");
> +
> + goto EXIT;
> + }
> +
> + memset(&svd, 0, sizeof(svd));
> + if (g_input_stream_read(G_INPUT_STREAM(stream),
> + &svd,
> + sizeof(svd),
> + cancellable,
> + error) < sizeof(svd)) {
> + if (*error)
> + g_prefix_error(error,
> + "Failed to read supplementary volume descriptor");
> + else
> + g_set_error(error,
> + OSINFO_INSTALL_MEDIA_ERROR,
> + OSINFO_INSTALL_MEDIA_ERROR_NO_SVD,
> + "Supplementary volume descriptor unavailable");
> +
> + goto EXIT;
> + }
> +
> + svd.system[MAX_SYSTEM - 1] = 0;
> +
> + if (strncmp(BOOTABLE_TAG, svd.system, sizeof(BOOTABLE_TAG) != 0)) {
> + g_set_error(error,
> + OSINFO_INSTALL_MEDIA_ERROR,
> + OSINFO_INSTALL_MEDIA_ERROR_NOT_BOOTABLE,
> + "Install media is not bootable");
> +
> + goto EXIT;
> + }
> +
> + oss = osinfo_list_get_elements(OSINFO_LIST(db->priv->oses));
> + for (os_iter = oss; os_iter; os_iter = os_iter->next) {
> + OsinfoOs *os = OSINFO_OS(os_iter->data);
> + OsinfoMediaList *media_list = osinfo_os_get_media_list(os);
> + GList *medias = osinfo_list_get_elements(OSINFO_LIST(media_list));
> + GList *media_iter;
> +
> + for (media_iter = medias; media_iter; media_iter = media_iter->next) {
> + OsinfoMedia *media = OSINFO_MEDIA(media_iter->data);
> + const gchar *media_volume = osinfo_media_get_volume_id(media);
> + const gchar *media_system = osinfo_media_get_system_id(media);
> + const gchar *media_publisher = osinfo_media_get_publisher_id(media);
> +
> + if (str_contains(pvd.volume, media_volume) &&
> + (str_contains(pvd.system, media_system) ||
> + str_contains(pvd.publisher, media_publisher))) {
> + ret = os;
> + break;
> + }
> + }
> +
> + g_list_free(medias);
> + g_object_unref(media_list);
> +
> + if (ret)
> + break;
> + }
> +
> +EXIT:
> + g_list_free(oss);
> + g_object_unref(stream);
> + g_object_unref(file);
> +
> + return ret;
> +}
>
> struct osinfo_db_populate_values_args {
> GHashTable *values;
> diff --git a/osinfo/osinfo_db.h b/osinfo/osinfo_db.h
> index c9d506e..3f56de1 100644
> --- a/osinfo/osinfo_db.h
> +++ b/osinfo/osinfo_db.h
> @@ -23,6 +23,7 @@
> */
>
> #include <glib-object.h>
> +#include <gio/gio.h>
> #include <osinfo/osinfo_platform.h>
> #include <osinfo/osinfo_os.h>
> #include <osinfo/osinfo_device.h>
> @@ -33,6 +34,30 @@
> #ifndef __OSINFO_DB_H__
> #define __OSINFO_DB_H__
>
> +GQuark
> +osinfo_install_media_error_quark (void) G_GNUC_CONST;
> +
> +#define OSINFO_INSTALL_MEDIA_ERROR (osinfo_install_media_error_quark ())
> +
> +/**
> + * OsinfoInstallMediaError:
> + * @OSINFO_INSTALL_MEDIA_ERROR_NO_DESCRIPTORS: No descriptors.
> + * @OSINFO_INSTALL_MEDIA_ERROR_INSUFFIENT_METADATA: Not enough metadata.
> + * @OSINFO_INSTALL_MEDIA_ERROR_NOT_BOOTABLE: Install media not bootable.
> + * @OSINFO_INSTALL_MEDIA_ERROR_NO_PVD: No Primary volume descriptor.
> + * @OSINFO_INSTALL_MEDIA_ERROR_NO_SVD: No supplementary volume descriptor.
> + *
> + * #GError codes used for errors in the #OSINFO_INSTALL_MEDIA_ERROR domain, during
> + * reading of data from install media for detection of OS.
> + */
> +typedef enum {
> + OSINFO_INSTALL_MEDIA_ERROR_NO_DESCRIPTORS,
> + OSINFO_INSTALL_MEDIA_ERROR_NO_PVD,
> + OSINFO_INSTALL_MEDIA_ERROR_NO_SVD,
> + OSINFO_INSTALL_MEDIA_ERROR_INSUFFIENT_METADATA,
> + OSINFO_INSTALL_MEDIA_ERROR_NOT_BOOTABLE
> +} OsinfoInstallMediaError;
> +
> /*
> * Type macros.
> */
> @@ -92,6 +117,11 @@ void osinfo_db_add_platform(OsinfoDb *db, OsinfoPlatform *platform);
> void osinfo_db_add_device(OsinfoDb *db, OsinfoDevice *device);
> void osinfo_db_add_deployment(OsinfoDb *db, OsinfoDeployment *deployment);
>
> +OsinfoOs *osinfo_db_guess_os_from_location(OsinfoDb *db,
> + const gchar *location,
> + GCancellable *cancellable,
> + GError **error);
> +
> // Get me all unique values for property "vendor" among operating systems
> GList *osinfo_db_unique_values_for_property_in_os(OsinfoDb *db, const gchar *propName);
>
ACK
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the virt-tools-list
mailing list