/* * Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: Peter Schiffer */ #include "sw-utils.h" const char *provider_name = "software"; const ConfigEntry *provider_config_defaults = NULL; /******************************************************************************* * SwPackage & related functions ******************************************************************************/ void init_sw_package(SwPackage *pkg) { pkg->name = NULL; pkg->epoch = NULL; pkg->version = NULL; pkg->release = NULL; pkg->arch = NULL; pkg->pk_version = NULL; } void free_sw_package(SwPackage *pkg) { free(pkg->name); free(pkg->epoch); free(pkg->version); free(pkg->release); free(pkg->arch); free(pkg->pk_version); init_sw_package(pkg); } short create_sw_package_from_pk_pkg(PkPackage *pk_pkg, SwPackage *sw_pkg) { short ret = -1; char *delim; const char *id, *name, *arch, *ver; init_sw_package(sw_pkg); if (!(id = pk_package_get_id(pk_pkg))) { warn("Package without ID!"); goto done; } if (!(name = pk_package_get_name(pk_pkg))) { warn("Package with ID: %s doesn't have name!", id); goto done; } if (!(ver = pk_package_get_version(pk_pkg))) { warn("Package with ID: %s doesn't have version!", id); goto done; } if (!(arch = pk_package_get_arch(pk_pkg))) { warn("Package with ID: %s doesn't have architecture!", id); goto done; } sw_pkg->name = strdup(name); sw_pkg->arch = strdup(arch); sw_pkg->pk_version = strdup(ver); if ((delim = strchr(ver, ':'))) { sw_pkg->epoch = strndup(ver, delim - ver); ver = delim + 1; } else { sw_pkg->epoch = strdup("0"); } if ((delim = strrchr(ver, '-'))) { sw_pkg->version = strndup(ver, delim - ver); sw_pkg->release = strdup(delim + 1); } else { sw_pkg->version = strdup(ver); sw_pkg->release = strdup("0"); warn("Package with ID: %s doesn't have release number! Using '0' instead.", id); } if (!sw_pkg->name || !sw_pkg->arch || !sw_pkg->epoch || !sw_pkg->version || !sw_pkg->release || !sw_pkg->pk_version) { warn("Memory allocation failed."); goto done; } ret = 0; done: if (ret != 0) { free_sw_package(sw_pkg); } return ret; } short create_sw_package_from_elem_name(const char *elem_name, SwPackage *sw_pkg) { short ret = -1; char *en, *delim; init_sw_package(sw_pkg); if (!(en = strdup(elem_name))) { warn("Memory allocation failed."); goto done; } if (!(delim = strrchr(en, '.'))) { warn("Invalid element name of the package: %s", elem_name); goto done; } sw_pkg->arch = strdup(delim + 1); delim[0] = '\0'; if (!(delim = strrchr(en, '-'))) { warn("Invalid element name of the package: %s", elem_name); goto done; } sw_pkg->release = strdup(delim + 1); delim[0] = '\0'; if ((delim = strrchr(en, ':'))) { sw_pkg->version = strdup(delim + 1); delim[0] = '\0'; if (!(delim = strrchr(en, '-'))) { warn("Invalid element name of the package: %s", elem_name); goto done; } sw_pkg->epoch = strdup(delim + 1); delim[0] = '\0'; } else { if (!(delim = strrchr(en, '-'))) { warn("Invalid element name of the package: %s", elem_name); goto done; } sw_pkg->version = strdup(delim + 1); delim[0] = '\0'; sw_pkg->epoch = strdup("0"); } sw_pkg->name = strdup(en); if (!sw_pkg->name || !sw_pkg->arch || !sw_pkg->epoch || !sw_pkg->version || !sw_pkg->release) { warn("Memory allocation failed."); goto done; } if (strcmp(sw_pkg->epoch, "0") == 0) { if (asprintf(&sw_pkg->pk_version, "%s-%s", sw_pkg->version, sw_pkg->release) < 0) { warn("Memory allocation failed."); goto done; } } else { if (asprintf(&sw_pkg->pk_version, "%s:%s-%s", sw_pkg->epoch, sw_pkg->version, sw_pkg->release) < 0) { warn("Memory allocation failed."); goto done; } } ret = 0; done: free(en); if (ret != 0) { free_sw_package(sw_pkg); } return ret; } void sw_pkg_get_version_str(const SwPackage *pkg, char *ver_str, const unsigned ver_str_len) { snprintf(ver_str, ver_str_len, "%s:%s-%s.%s", pkg->epoch, pkg->version, pkg->release, pkg->arch); } void sw_pkg_get_element_name(const SwPackage *pkg, char *elem_name, const unsigned elem_name_len) { snprintf(elem_name, elem_name_len, "%s-%s:%s-%s.%s", pkg->name, pkg->epoch, pkg->version, pkg->release, pkg->arch); } /******************************************************************************* * Functions related to single PkPackage ******************************************************************************/ void get_pk_pkg_from_sw_pkg(const SwPackage *sw_pkg, PkPackage **pk_pkg) { PkTask *task = NULL; PkPackage *item = NULL; PkResults *results = NULL; GPtrArray *array = NULL; GError *gerror = NULL; gchar **values = NULL; unsigned i; char error_msg[ERROR_MSG_LEN] = ""; task = pk_task_new(); values = g_new0(gchar*, 2); values[0] = g_strdup(sw_pkg->name); results = pk_task_search_names_sync(task, 0, values, NULL, NULL, NULL, &gerror); if (check_and_create_error_msg(results, gerror, "Resolving package failed", error_msg, ERROR_MSG_LEN)) { warn(error_msg); goto done; } array = pk_results_get_package_array(results); for (i = 0; i < array->len; i++) { item = g_ptr_array_index(array, i); if (strcmp(pk_package_get_name(item), sw_pkg->name) == 0 && strcmp(pk_package_get_version(item), sw_pkg->pk_version) == 0 && strcmp(pk_package_get_arch(item), sw_pkg->arch) == 0) { *pk_pkg = g_object_ref(item); break; } } done: g_strfreev(values); g_clear_error(&gerror); if (array) { g_ptr_array_unref(array); } if (results) { g_object_unref(results); } if (task) { g_object_unref(task); } return; } void get_pk_det_from_pk_pkg(PkPackage *pk_pkg, PkDetails **pk_det) { PkTask *task = NULL; PkDetails *item = NULL; PkResults *results = NULL; GPtrArray *array = NULL; GError *gerror = NULL; gchar **values = NULL; unsigned i; char error_msg[ERROR_MSG_LEN] = ""; task = pk_task_new(); values = g_new0(gchar*, 2); values[0] = g_strdup(pk_package_get_id(pk_pkg)); results = pk_task_get_details_sync(task, values, NULL, NULL, NULL, &gerror); if (check_and_create_error_msg(results, gerror, "Getting package details failed", error_msg, ERROR_MSG_LEN)) { warn(error_msg); goto done; } array = pk_results_get_details_array(results); for (i = 0; i < array->len; i++) { item = g_ptr_array_index(array, i); if (strcmp(pk_details_get_package_id(item), pk_package_get_id(pk_pkg)) == 0) { *pk_det = g_object_ref(item); break; } } done: g_strfreev(values); g_clear_error(&gerror); if (array) { g_ptr_array_unref(array); } if (results) { g_object_unref(results); } if (task) { g_object_unref(task); } return; } void create_instance_from_pkgkit_data(PkPackage *pk_pkg, PkDetails *pk_det, SwPackage *sw_pkg, const CMPIBroker *cb, const char *ns, LMI_SoftwareIdentity *w) { const gchar *summary, *desc = NULL; char elem_name[ELEM_NAME_LEN] = "", ver_str[VER_STR_LEN] = "", instance_id[INSTANCE_ID_LEN] = ""; summary = pk_package_get_summary(pk_pkg); if (pk_det) { desc = pk_details_get_description(pk_det); } sw_pkg_get_element_name(sw_pkg, elem_name, ELEM_NAME_LEN); sw_pkg_get_version_str(sw_pkg, ver_str, VER_STR_LEN); create_instance_id(SW_IDENTITY_CLASS_NAME, elem_name, instance_id, INSTANCE_ID_LEN); LMI_SoftwareIdentity_Init(w, cb, ns); LMI_SoftwareIdentity_Set_InstanceID(w, instance_id); LMI_SoftwareIdentity_Init_Classifications(w, 1); LMI_SoftwareIdentity_Set_Classifications(w, 0, 0); LMI_SoftwareIdentity_Init_TargetTypes(w, 2); LMI_SoftwareIdentity_Set_TargetTypes(w, 0, "rpm"); LMI_SoftwareIdentity_Set_TargetTypes(w, 1, "yum"); LMI_SoftwareIdentity_Set_IsEntity(w, 1); LMI_SoftwareIdentity_Set_Architecture(w, sw_pkg->arch); LMI_SoftwareIdentity_Set_ElementName(w, elem_name); LMI_SoftwareIdentity_Set_Epoch(w, atoi(sw_pkg->epoch)); LMI_SoftwareIdentity_Set_Name(w, sw_pkg->name); LMI_SoftwareIdentity_Set_Release(w, sw_pkg->release); LMI_SoftwareIdentity_Set_Version(w, sw_pkg->version); LMI_SoftwareIdentity_Set_VersionString(w, ver_str); if (summary) { LMI_SoftwareIdentity_Set_Caption(w, summary); } if (desc) { LMI_SoftwareIdentity_Set_Description(w, desc); } return; } /******************************************************************************* * Functions related to multiple PkPackages ******************************************************************************/ void get_pk_packages(PkBitfield filters, GPtrArray **garray, char *error_msg, const unsigned error_msg_len) { PkTask *task = NULL; PkResults *results = NULL; GError *gerror = NULL; GPtrArray *array = NULL; task = pk_task_new(); results = pk_task_get_packages_sync(task, filters, NULL, NULL, NULL, &gerror); if (check_and_create_error_msg(results, gerror, "Getting list of packages failed", error_msg, error_msg_len)) { goto done; } array = pk_results_get_package_array(results); g_ptr_array_sort(array, (GCompareFunc) pk_pkg_cmp); *garray = g_ptr_array_ref(array); done: g_clear_error(&gerror); if (array) { g_ptr_array_unref(array); } if (results) { g_object_unref(results); } if (task) { g_object_unref(task); } return; } void enum_sw_identity_instance_names(PkBitfield filters, const CMPIBroker *cb, const char *ns, const CMPIResult* cr, char *error_msg, const unsigned error_msg_len) { GPtrArray *array = NULL; SwPackage sw_pkg; unsigned i; char elem_name[ELEM_NAME_LEN] = "", instance_id[INSTANCE_ID_LEN] = ""; init_sw_package(&sw_pkg); get_pk_packages(filters, &array, error_msg, error_msg_len); if (!array) { goto done; } for (i = 0; i < array->len; i++) { if (create_sw_package_from_pk_pkg(g_ptr_array_index(array, i), &sw_pkg) != 0) { continue; } sw_pkg_get_element_name(&sw_pkg, elem_name, ELEM_NAME_LEN); create_instance_id(SW_IDENTITY_CLASS_NAME, elem_name, instance_id, INSTANCE_ID_LEN); free_sw_package(&sw_pkg); LMI_SoftwareIdentityRef w; LMI_SoftwareIdentityRef_Init(&w, cb, ns); LMI_SoftwareIdentityRef_Set_InstanceID(&w, instance_id); KReturnObjectPath(cr, w); } done: if (array) { g_ptr_array_unref(array); } return; } void enum_sw_identity_instances(PkBitfield filters, const CMPIBroker *cb, const char *ns, const CMPIResult* cr, char *error_msg, const unsigned error_msg_len) { LMI_SoftwareIdentity w; PkTask *task = NULL; PkPackage *pk_pkg = NULL; PkDetails *pk_det = NULL; PkResults *results = NULL; GPtrArray *array = NULL, *array2 = NULL; GError *gerror = NULL; gchar **values = NULL; SwPackage sw_pkg; int cmpres; unsigned i, j, a2i; init_sw_package(&sw_pkg); get_pk_packages(filters, &array, error_msg, error_msg_len); if (!array) { goto done; } task = pk_task_new(); for (i = 0; i < array->len / PK_DETAILS_LIMIT + 1; i++) { values = g_new0(gchar*, PK_DETAILS_LIMIT + 1); for (j = i * PK_DETAILS_LIMIT; j < (i + 1) * PK_DETAILS_LIMIT && j < array->len; j++) { values[j - i * PK_DETAILS_LIMIT] = g_strdup(pk_package_get_id( g_ptr_array_index(array, j))); } results = pk_task_get_details_sync(task, values, NULL, NULL, NULL, &gerror); if (check_and_create_error_msg(results, gerror, "Getting package details failed", error_msg, error_msg_len)) { warn(error_msg); /* This is non-fatal problem. */ error_msg[0] = '\0'; } else { array2 = pk_results_get_details_array(results); g_ptr_array_sort(array2, (GCompareFunc) pk_det_cmp); } g_strfreev(values); values = NULL; a2i = 0; for (j = i * PK_DETAILS_LIMIT; j < (i + 1) * PK_DETAILS_LIMIT && j < array->len; j++) { pk_pkg = g_ptr_array_index(array, j); if (create_sw_package_from_pk_pkg(pk_pkg, &sw_pkg) != 0) { continue; } cmpres = -1; if (array2) { while (cmpres < 0 && a2i < array2->len) { pk_det = g_ptr_array_index(array2, a2i); cmpres = strcmp(pk_details_get_package_id(pk_det), pk_package_get_id(pk_pkg)); if (cmpres < 0) { /* this should not happen - * we have spare unmatched package details */ a2i++; } else if (cmpres > 0) { /* no matching package details for current pk_pkg */ pk_det = NULL; } else { /* found a match */ a2i++; } } } create_instance_from_pkgkit_data(pk_pkg, pk_det, &sw_pkg, cb, ns, &w); KReturnInstance(cr, w); free_sw_package(&sw_pkg); } if (results) { g_object_unref(results); results = NULL; } if (array2) { g_ptr_array_unref(array2); array2 = NULL; } } done: g_clear_error(&gerror); if (array) { g_ptr_array_unref(array); } if (task) { g_object_unref(task); } return; } /******************************************************************************* * Functions related to PackageKit ******************************************************************************/ short check_and_create_error_msg(PkResults *results, GError *gerror, const char *custom_msg, char *error_msg, const unsigned error_msg_len) { short ret = 0; PkError *error_code = NULL; if (results) { error_code = pk_results_get_error_code(results); if (error_code) { snprintf(error_msg, error_msg_len, "%s: %s, %s", custom_msg, pk_error_enum_to_string(pk_error_get_code(error_code)), pk_error_get_details(error_code)); g_object_unref(error_code); ret = 1; goto done; } } if (gerror) { snprintf(error_msg, error_msg_len, "%s: %s", custom_msg, gerror->message); ret = 1; goto done; } if (!results) { snprintf(error_msg, error_msg_len, "%s: Nothing returned", custom_msg); ret = 1; goto done; } done: return ret; } gint pk_pkg_cmp(gpointer a, gpointer b) { PkPackage *al = *(PkPackage **) a; PkPackage *bl = *(PkPackage **) b; return (gint) strcmp(pk_package_get_id(al), pk_package_get_id(bl)); } gint pk_det_cmp(gpointer a, gpointer b) { PkDetails *al = *(PkDetails **) a; PkDetails *bl = *(PkDetails **) b; return (gint) strcmp(pk_details_get_package_id(al), pk_details_get_package_id(bl)); } /******************************************************************************* * Functions related to CMPI ******************************************************************************/ void create_instance_id(const char *class_name, const char *id, char *instance_id, const unsigned instance_id_len) { if (id) { snprintf(instance_id, instance_id_len, ORGID ":" ORGID "_%s:%s", class_name, id); } else { snprintf(instance_id, instance_id_len, ORGID ":" ORGID "_%s", class_name); } } const char *get_str_property_from_op(const CMPIObjectPath *o, const char *prop) { CMPIData d; d = CMGetKey(o, prop, NULL); return KChars(d.value.string); } short cm_class_is_a(const CMPIBroker *cb, const char *ns, const char *cm_class, const char *type) { CMPIStatus st; CMPIObjectPath *o = NULL; short ret = 0; o = CMNewObjectPath(cb, ns, cm_class, &st); if (!o) { goto done; } else if (st.rc != CMPI_RC_OK) { goto done; } if (type && !CMClassPathIsA(cb, o, type, &st)) { goto done; } ret = 1; done: if (o) { CMRelease(o); } return ret; }