[virt-tools-list] [libosinfo 2/4] Add osinfo_db_guess_os_from_location()

Zeeshan Ali (Khattak) zeeshanak at gnome.org
Mon Aug 22 21:31:24 UTC 2011


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);
 
-- 
1.7.6




More information about the virt-tools-list mailing list