On Tue, Aug 23, 2011 at 12:31:24AM +0300, Zeeshan Ali (Khattak) wrote: > From: "Zeeshan Ali (Khattak)" <[email protected]> > > 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 :| _______________________________________________ virt-tools-list mailing list [email protected] https://www.redhat.com/mailman/listinfo/virt-tools-list
