/*
* Copyright (C) 2012 Red Hat, Inc
*
* osinfo-query: query the contents of the database
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see
*/
#include
#include
#include
#include
#include
#include
#include
#include
struct OsinfoLabel {
const gchar *prop;
const gchar *label;
gboolean enabled;
gsize width;
};
typedef OsinfoList * (*osinfo_list_func)(OsinfoDb *db);
struct OsinfoType {
const gchar *name;
osinfo_list_func listFunc;
GType entityType;
GType filterType;
GType listType;
struct OsinfoLabel *labels;
};
static struct OsinfoLabel os_labels[] = {
{ OSINFO_PRODUCT_PROP_SHORT_ID,
N_("Short ID"), TRUE, 20 },
{ OSINFO_PRODUCT_PROP_NAME,
N_("Name"), TRUE, 50 },
{ OSINFO_PRODUCT_PROP_VERSION,
N_("Version"), TRUE, 8 },
{ OSINFO_OS_PROP_FAMILY,
N_("Family"), FALSE, 12 },
{ OSINFO_OS_PROP_DISTRO,
N_("Distro"), FALSE, 12 },
{ OSINFO_PRODUCT_PROP_VENDOR,
N_("Vendor"), FALSE, 25 },
{ OSINFO_PRODUCT_PROP_RELEASE_DATE,
N_("Release date"), FALSE, 12 },
{ OSINFO_PRODUCT_PROP_EOL_DATE,
N_("End of life"), FALSE, 12 },
{ OSINFO_PRODUCT_PROP_CODENAME,
N_("Code name"), FALSE, 10 },
{ OSINFO_ENTITY_PROP_ID,
N_("ID"), TRUE, 40 },
{ OSINFO_OS_PROP_RELEASE_STATUS,
N_("Release status"), FALSE, 15 },
{ NULL, NULL, 0, 0},
};
static struct OsinfoLabel platform_labels[] = {
{ OSINFO_PRODUCT_PROP_SHORT_ID,
N_("Short ID"), TRUE, 20 },
{ OSINFO_PRODUCT_PROP_NAME,
N_("Name"), TRUE, 50 },
{ OSINFO_PRODUCT_PROP_VERSION,
N_("Version"), TRUE, 8 },
{ OSINFO_PRODUCT_PROP_VENDOR,
N_("Vendor"), TRUE, 25 },
{ OSINFO_PRODUCT_PROP_RELEASE_DATE,
N_("Release date"), FALSE, 12 },
{ OSINFO_PRODUCT_PROP_EOL_DATE,
N_("End of life"), FALSE, 12 },
{ OSINFO_PRODUCT_PROP_CODENAME,
N_("Code name"), FALSE, 10 },
{ OSINFO_ENTITY_PROP_ID,
N_("ID"), TRUE, 40 },
{ NULL, NULL, 0, 0 },
};
static struct OsinfoLabel device_labels[] = {
{ OSINFO_DEVICE_PROP_VENDOR,
N_("Vendor"), TRUE, 20 },
{ OSINFO_DEVICE_PROP_VENDOR_ID,
N_("Vendor ID"), TRUE, 12 },
{ OSINFO_DEVICE_PROP_PRODUCT,
N_("Product"), TRUE, 20 },
{ OSINFO_DEVICE_PROP_PRODUCT_ID,
N_("Product ID"), TRUE, 12 },
{ OSINFO_PRODUCT_PROP_NAME,
N_("Name"), TRUE, 14 },
{ OSINFO_DEVICE_PROP_CLASS,
N_("Class"), TRUE, 15 },
{ OSINFO_DEVICE_PROP_BUS_TYPE,
N_("Bus"), TRUE, 8 },
{ OSINFO_ENTITY_PROP_ID,
N_("ID"), TRUE, 40 },
{ NULL, NULL, 0, 0 },
};
static struct OsinfoLabel deployment_labels[] = {
{ OSINFO_ENTITY_PROP_ID,
N_("ID"), TRUE, 40 },
{ NULL, NULL, 0, 0 },
};
static gboolean toggle_fields(struct OsinfoLabel *labels,
const gchar *fieldStr,
GError **error)
{
gboolean ret = FALSE;
gchar **fields;
gsize i, j;
if (!fieldStr)
return TRUE;
fields = g_strsplit(fieldStr, ",", 0);
for (j = 0; labels[j].prop; j++) {
labels[j].enabled = FALSE;
}
for (i = 0; fields[i] != NULL; i++) {
gboolean found = FALSE;
for (j = 0; labels[j].prop; j++) {
if (g_str_equal(fields[i], labels[j].prop)) {
labels[j].enabled = TRUE;
found = TRUE;
}
}
if (!found) {
g_set_error(error, OSINFO_ERROR, 0,
_("Unknown property name %s"), fields[i]);
goto cleanup;
}
}
ret = TRUE;
cleanup:
g_strfreev(fields);
return ret;
}
static gboolean build_filter(struct OsinfoLabel *labels,
OsinfoFilter *filter,
gint argc, char **argv,
GError **error)
{
gboolean ret = FALSE;
gsize i, j;
for (i = 0; i < argc; i++) {
const gchar *tmp;
gchar *key = NULL;
gchar *val = NULL;
gboolean found = FALSE;
tmp = strchr(argv[i], '=');
if (!tmp) {
g_set_error(error, OSINFO_ERROR, 0, "%s", _("Syntax error in condition, expecting KEY=VALUE"));
goto cleanup;
}
key = g_strndup(argv[i], tmp-argv[i]);
val = g_strdup(tmp+1);
for (j = 0; labels[j].prop != NULL; j++) {
if (g_str_equal(key, labels[j].prop))
found = TRUE;
}
if (!found) {
g_set_error(error, OSINFO_ERROR, 0,
_("Unknown property name %s"), key);
goto cleanup;
}
osinfo_filter_add_constraint(filter, key, val);
g_free(key);
g_free(val);
}
ret = TRUE;
cleanup:
return ret;
}
static gint sort_entity(gconstpointer a,
gconstpointer b,
gpointer data)
{
OsinfoEntity *entityA = OSINFO_ENTITY((gpointer) a);
OsinfoEntity *entityB = OSINFO_ENTITY((gpointer) b);
gchar *key = data;
const gchar *valA;
const gchar *valB;
valA = osinfo_entity_get_param_value(entityA, key);
valB = osinfo_entity_get_param_value(entityB, key);
if (!valA && !valB)
return 0;
if (!valA && valB)
return 1;
if (valA && !valB)
return 1;
return strcmp(valA, valB);
}
static gboolean print_entity_text(OsinfoEntity *entity,
const struct OsinfoLabel *labels)
{
gsize i;
gboolean first = TRUE;
for (i = 0; labels[i].prop != NULL; i++) {
gsize pad;
gchar *padstr;
const gchar *val = osinfo_entity_get_param_value(entity, labels[i].prop);
if (!labels[i].enabled)
continue;
if (first)
g_print(" ");
else
g_print(" | ");
first = FALSE;
if (val && (strlen(val) > labels[i].width))
pad = 0;
else
pad = labels[i].width - (val ? strlen(val) : 0);
padstr = g_new0(gchar, pad+1);
padstr[pad] = '\0';
if (pad)
memset(padstr, ' ', pad);
g_print("%s%s",
val ? val : "", padstr);
g_free(padstr);
}
g_print("\n");
return FALSE;
}
static gboolean print_results_text(OsinfoList *list,
const struct OsinfoLabel *labels,
const gchar *sortKey)
{
gboolean ret = FALSE;
GList *entities = osinfo_list_get_elements(list);
GList *tmp;
gsize i;
gboolean first = TRUE;
tmp = entities = g_list_sort_with_data(entities, sort_entity,
(gchar*)(sortKey ? sortKey :
labels[0].prop));
for (i = 0; labels[i].prop != NULL; i++) {
gsize pad;
gchar *padstr;
if (!labels[i].enabled)
continue;
if (first)
g_print(" ");
else
g_print(" | ");
first = FALSE;
if (strlen(gettext(labels[i].label)) > labels[i].width)
pad = 0;
else
pad = labels[i].width - strlen(gettext(labels[i].label));
padstr = g_new0(gchar, pad+1);
padstr[pad] = '\0';
if (pad)
memset(padstr, ' ', pad);
g_print("%s%s",
gettext(labels[i].label), padstr);
g_free(padstr);
}
g_print("\n");
first = TRUE;
for (i = 0; labels[i].prop != NULL; i++) {
gchar *padstr;
if (!labels[i].enabled)
continue;
if (first)
g_print("-");
else
g_print("-+-");
first = FALSE;
padstr = g_new0(gchar, labels[i].width+1);
memset(padstr, '-', labels[i].width);
padstr[labels[i].width] = '\0';
g_print("%s", padstr);
g_free(padstr);
}
g_print("\n");
/* No match */
if (tmp == NULL)
goto end;
while (tmp) {
OsinfoEntity *entity = OSINFO_ENTITY(tmp->data);
print_entity_text(entity, labels);
tmp = tmp->next;
}
ret = TRUE;
end:
g_list_free(entities);
// cleanup:
return ret;
}
gint main(gint argc, gchar **argv)
{
GOptionContext *context;
GError *error = NULL;
gint ret = EXIT_FAILURE;
const gchar *type = NULL;
OsinfoLoader *loader = NULL;
OsinfoDb *db = NULL;
OsinfoList *entities = NULL;
OsinfoFilter *filter = NULL;
OsinfoList *results = NULL;
struct OsinfoLabel *labels = NULL;
gsize i;
const gchar *sortKey = NULL;
const gchar *fields = NULL;
struct OsinfoType types[] = {
{ "os",
(osinfo_list_func)osinfo_db_get_os_list,
OSINFO_TYPE_OS,
OSINFO_TYPE_PRODUCTFILTER,
OSINFO_TYPE_OSLIST,
os_labels },
{ "platform",
(osinfo_list_func)osinfo_db_get_platform_list,
OSINFO_TYPE_PLATFORM,
OSINFO_TYPE_PRODUCTFILTER,
OSINFO_TYPE_PLATFORMLIST,
platform_labels },
{ "device",
(osinfo_list_func)osinfo_db_get_device_list,
OSINFO_TYPE_DEVICE,
OSINFO_TYPE_FILTER,
OSINFO_TYPE_DEVICELIST,
device_labels },
{ "deployment",
(osinfo_list_func)osinfo_db_get_deployment_list,
OSINFO_TYPE_DEPLOYMENT,
OSINFO_TYPE_FILTER,
OSINFO_TYPE_DEPLOYMENTLIST,
deployment_labels },
};
GOptionEntry entries[] = {
{ "sort", 's', 0, G_OPTION_ARG_STRING, &sortKey,
_("Sort column"), NULL },
{ "fields", 'f', 0, G_OPTION_ARG_STRING, &fields,
_("Display fields"), NULL },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
setlocale(LC_ALL, "");
textdomain(GETTEXT_PACKAGE);
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
context = g_option_context_new(_("- Query the OS info database"));
g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_printerr(_("Error while parsing commandline options: %s\n"),
error->message);
g_printerr("%s\n", g_option_context_get_help(context, FALSE, NULL));
goto error;
}
if (argc < 2) {
g_printerr(_("Missing data type parameter\n"));
goto error;
}
type = argv[1];
loader = osinfo_loader_new();
osinfo_loader_process_default_path(loader, &error);
if (error != NULL) {
g_printerr(_("Error loading OS data: %s\n"), error->message);
goto error;
}
db = osinfo_loader_get_db(loader);
for (i = 0; i < (sizeof(types)/sizeof(types[0])); i++) {
if (g_str_equal(types[i].name, type)) {
entities = types[i].listFunc(db);
filter = g_object_new(types[i].filterType, NULL);
results = g_object_new(types[i].listType,
"element-type", types[i].entityType,
NULL);
labels = types[i].labels;
}
}
if (!entities) {
g_printerr(_("Unknown type '%s' requested\n"), type);
goto error;
}
if (!build_filter(labels, filter, argc-2, argv+2, &error)) {
g_printerr(_("Unable to construct filter: %s\n"), error->message);
goto error;
}
if (!toggle_fields(labels, fields, &error)) {
g_printerr(_("Unable to set field visibility: %s\n"), error->message);
goto error;
}
osinfo_list_add_filtered(results, entities, filter);
if (!print_results_text(results, labels, sortKey)) {
/*
* The os wasn't found, no need to print an error,
* just be sure to return EXIT_FAILURE.
*/
goto error;
}
ret = EXIT_SUCCESS;
error:
g_clear_error(&error);
g_option_context_free(context);
if (entities)
g_object_unref(entities);
if (filter)
g_object_unref(filter);
if (results)
g_object_unref(results);
if (loader)
g_object_unref(loader);
return ret;
}
/*
=pod
=head1 NAME
osinfo-query - Query information in the database
=head1 SYNOPSIS
osinfo-query [OPTIONS...] TYPE [CONDITION-1 [CONDITION-2 ...]]
=head1 DESCRIPTION
The C command allows extraction of information from the
database. B can be one of C, C, C, or
C. With no conditions specified, all entities of the given
type will be listed.
# List all operating systems
$ osinfo-query os
Short ID | Name ...
----------------------+-----------
centos-6.0 | CentOS 6.0 ...
centos-6.1 | CentOS 6.1 ...
...
Conditions allow filtering based on specific properties of an entity.
For example, to filter only distros from the Fedora Project, use
# List all operating systems
$ osinfo-query os vendor="Fedora Project"
Short ID | Name ...
----------------------+--------------
fedora1 | Fedora Core 1 ...
fedora2 | Fedora Core 2 ...
...
The set of fields which are printed can be controlled using the B<--fields>
command line argument:
# List all operating systems
$ osinfo-query --fields=short-id,version os vendor="Fedora Project"
Short ID | Version
----------------------+----------
fedora1 | 1
fedora2 | 2
...
=head1 OPTIONS
=over 8
=item B<-s PROPERTY>, B<--sort-key PROPERTY>
Set the data sorting key. Defaults sorting the first column
=item B<-f PROPERTY1,PROPERTY2,...>, B<--fields PROPERTY1,PROPERTY2,...>
Set the visibility of properties in output
=back
=head1 PROPERTY NAMES
=head2 OS
Valid property names for the C type are:
=over 4
=item B
The short OS identifier
=item B
The long OS name
=item B
The OS version string
=item B
The OS kernel family
=item B
The OS vendor
=item B
The OS release date
=item B
The OS end-of-life date
=item B
The OS code name
=item B
The OS identifier
=back
=head2 PLATFORM
Valid property names for the C type are:
=over 4
=item B
The short platform identifier
=item B
The long platform name
=item B
The platform version string
=item B
The platform vendor
=item B
The platform release date
=item B
The platform end-of-life date
=item B
The platform code name
=item B
The platform identifier
=back
=head2 DEVICE
Valid property names for the C type are:
=over 4
=item B
The device name
=item B
The device product name
=item B
The device product ID string
=item B
The device vendor name
=item B
The device vendor ID string
=item B
The device type class
=item B
The device bus type
=item B
The device identifier
=back
=head2 DEPLOYMENT
Valid property names for the C type are:
=over 4
=item B
The deployment identifier
=back
=head1 EXIT STATUS
The exit status will be 0 if matching entries were found,
or 1 if not matches were found
=head1 SEE ALSO
L, L
=head1 AUTHORS
Daniel P. Berrange
=head1 COPYRIGHT
Copyright (C) 2012, 2014 Red Hat, Inc.
=head1 LICENSE
C is distributed under the termsof the GNU LGPL v2+
license. This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE
=cut
*/