#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <getopt.h> #include <osinfo/osinfo.h> #define ERROR(...) \ do { \ fprintf(stderr, "ERROR %s:%d : ", __FUNCTION__, __LINE__); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ } while (0) #define NULLSTR(s) \ ((s) ? (s) : "") typedef struct _Control Control; struct _Control { const char *db_path; const char *os_id; const char *detect_path; bool list_os_ids; }; static void print_libosinfo_version(void) { printf("libosinfo version: %d.%d.%d\n", OSINFO_MAJOR_VERSION, OSINFO_MINOR_VERSION, OSINFO_MICRO_VERSION); } static void print_help(const char *progname) { printf("\n" "%s [options] [<ID>]\n" "\n" " options:\n" " -v | --version print libosinfo version and exit\n" " -h | --help print this help and exit\n" " -p | --db-path <PATH> where to load libosinfo DB from\n" " -i | --os-id <ID> OS identifier (short or long)\n" " -l | --list list OS identifiers and exit\n" " -d | --detect <PATH> detect OS from given path\n", progname); } static int parseArgv(Control *ctl, int argc, char *argv[]) { int ret = -1; int arg; int longindex = -1; const char *progname = NULL; struct option opt[] = { { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "db-path", required_argument, NULL, 'p' }, { "os-id", required_argument, NULL, 'i' }, { "list", no_argument, NULL, 'l' }, { "detect", required_argument, NULL, 'd' }, { NULL, 0, NULL, 0 }, }; progname = strrchr(argv[0], '/'); if (!progname) { progname = argv[0]; } else { progname++; } while ((arg = getopt_long(argc, argv, ":vhp:ild:", opt, &longindex)) != -1) { switch (arg) { case 'v': print_libosinfo_version(); exit(EXIT_SUCCESS); break; case 'h': print_help(progname); exit(EXIT_SUCCESS); break; case 'p': ctl->db_path = optarg; break; case 'i': ctl->os_id = optarg; break; case 'l': ctl->list_os_ids = true; break; case 'd': ctl->detect_path = optarg; break; case '?': if (optopt) ERROR("unsupported option '-%1$c'. See --help.", optopt); else ERROR("unsupported option '%1$s'. See --help.", argv[optind - 1]); goto cleanup; default: ERROR("unknown option"); goto cleanup; } longindex = -1; } if (argc != optind) { if (ctl->os_id || optind + 1 != argc) { ERROR("Too much args"); goto cleanup; } ctl->os_id = argv[optind]; } if (ctl->detect_path && ctl->os_id) { ERROR("--os-id and --detect are mutually exclusive"); goto cleanup; } ret = 0; cleanup: return ret; } static OsinfoDb * load_db(Control *ctl) { g_autoptr(OsinfoLoader) loader = osinfo_loader_new(); GError *error = NULL; if (ctl->db_path) { osinfo_loader_process_path(loader, ctl->db_path, &error); } else { osinfo_loader_process_default_path(loader, &error); } if (error) { ERROR(error->message); return NULL; } return g_object_ref(osinfo_loader_get_db(loader)); } 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); } #define FMT_STRING "%25s\t%-50s\t%-10s\t%s\n" static void list_os_ids(OsinfoDb *db) { g_autoptr(OsinfoOsList) list = osinfo_db_get_os_list(db); g_autoptr(GList) entities = osinfo_list_get_elements(OSINFO_LIST(list)); GList *tmp; tmp = entities = g_list_sort_with_data(entities, sort_entity, OSINFO_PRODUCT_PROP_SHORT_ID); printf(FMT_STRING, "Short ID", "Name", "Version", "ID"); /* No match */ if (tmp == NULL) return; while (tmp) { OsinfoEntity *entity = OSINFO_ENTITY(tmp->data); const char *shortID = osinfo_entity_get_param_value(entity, OSINFO_PRODUCT_PROP_SHORT_ID); const char *name = osinfo_entity_get_param_value(entity, OSINFO_PRODUCT_PROP_NAME); const char *version = osinfo_entity_get_param_value(entity, OSINFO_PRODUCT_PROP_VERSION); const char *id = osinfo_entity_get_param_value(entity, OSINFO_ENTITY_PROP_ID); printf(FMT_STRING, NULLSTR(shortID), NULLSTR(name), NULLSTR(version), NULLSTR(id)); tmp = tmp->next; } } #undef FMT_STRING static OsinfoOs * find_os_from_path(Control *ctl, OsinfoDb *db) { g_autoptr(OsinfoMedia) media = NULL; GError *error = NULL; OsinfoOs *os = NULL; g_autoptr(OsinfoMediaList) matched = NULL; media = osinfo_media_create_from_location(ctl->detect_path, NULL, &error); if (error) { ERROR(error->message); return NULL; } matched = osinfo_db_identify_medialist(db, media); if (osinfo_list_get_length(OSINFO_LIST(matched)) > 0) { OsinfoMedia *newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(matched), 0)); g_object_get(G_OBJECT(newmedia), "os", &os, NULL); if (os) { return os; } } ERROR("Unable to find OS from: %s", ctl->detect_path); return NULL; } static OsinfoOs * find_os(Control *ctl, OsinfoDb *db) { OsinfoOs *os = NULL; g_autoptr(OsinfoOsList) oslist = NULL; g_autoptr(OsinfoFilter) filter = NULL; g_autoptr(OsinfoOsList) filteredList = NULL; if (!ctl->os_id) { ERROR("No OS specified"); return NULL; } if ((os = osinfo_db_get_os(db, ctl->os_id))) { return g_object_ref(os); } oslist = osinfo_db_get_os_list(db); filter = osinfo_filter_new(); osinfo_filter_add_constraint(filter, OSINFO_PRODUCT_PROP_SHORT_ID, ctl->os_id); filteredList = OSINFO_OSLIST(osinfo_list_new_filtered(OSINFO_LIST(oslist), filter)); if (osinfo_list_get_length(OSINFO_LIST(filteredList)) > 0) { os = OSINFO_OS(osinfo_list_get_nth(OSINFO_LIST(filteredList), 0)); return g_object_ref(os); } ERROR("Unable to find OS: %s", ctl->os_id); return NULL; } #define PRINT_POSITIVE(val, ...) \ do { \ typeof(val) _v = val; \ if (_v > 0) { \ printf(__VA_ARGS__, _v); \ } \ } while (0) static void print_one_resource(OsinfoResources *res) { PRINT_POSITIVE(osinfo_resources_get_n_cpus(res), "N CPUs: %d\n"); PRINT_POSITIVE(osinfo_resources_get_cpu(res) / OSINFO_MEGAHERTZ, "CPU freq: %" G_GINT64_FORMAT " MHz\n"); PRINT_POSITIVE(osinfo_resources_get_ram(res) / OSINFO_MEBIBYTES, "Memory: %" G_GINT64_FORMAT " MiB\n"); PRINT_POSITIVE(osinfo_resources_get_storage(res) / OSINFO_GIBIBYTES, "Storage: %" G_GINT64_FORMAT " GiB\n"); printf("\n"); } #undef PRINT_POSITIVE static int print_resources(Control *ctl, OsinfoOs *os) { OsinfoResourcesList *resources_list; OsinfoResources *resources; resources_list = osinfo_os_get_minimum_resources(os); if (resources_list && osinfo_list_get_length(OSINFO_LIST(resources_list)) > 0) { resources = OSINFO_RESOURCES(osinfo_list_get_nth(OSINFO_LIST(resources_list), 0)); printf("Minimum resources\n"); print_one_resource(resources); } g_clear_object(&resources_list); resources_list = osinfo_os_get_recommended_resources(os); if (resources_list && osinfo_list_get_length(OSINFO_LIST(resources_list)) > 0) { resources = OSINFO_RESOURCES(osinfo_list_get_nth(OSINFO_LIST(resources_list), 0)); printf("Recommended resources\n"); print_one_resource(resources); } g_clear_object(&resources_list); resources_list = osinfo_os_get_maximum_resources(os); if (resources_list && osinfo_list_get_length(OSINFO_LIST(resources_list)) > 0) { resources = OSINFO_RESOURCES(osinfo_list_get_nth(OSINFO_LIST(resources_list), 0)); printf("Maximum resources\n"); print_one_resource(resources); } g_clear_object(&resources_list); resources_list = osinfo_os_get_network_install_resources(os); if (resources_list && osinfo_list_get_length(OSINFO_LIST(resources_list)) > 0) { resources = OSINFO_RESOURCES(osinfo_list_get_nth(OSINFO_LIST(resources_list), 0)); printf("Network install resources\n"); print_one_resource(resources); } g_clear_object(&resources_list); return 0; } int main(int argc, char *argv[]) { Control ctl = { }; g_autoptr(OsinfoDb) db = NULL; g_autoptr(OsinfoOs) os = NULL; if (parseArgv(&ctl, argc, argv) < 0) { return EXIT_FAILURE; } if (!(db = load_db(&ctl))) { return EXIT_FAILURE; } if (ctl.list_os_ids) { list_os_ids(db); return EXIT_SUCCESS; } if (ctl.detect_path) { os = find_os_from_path(&ctl, db); } else { os = find_os(&ctl, db); } if (!os) { return EXIT_FAILURE; } if (print_resources(&ctl, os) < 0) { return EXIT_FAILURE; } return EXIT_SUCCESS; }