From bbf83307946d07c7189ba7bfe90b56797c11ef39 Mon Sep 17 00:00:00 2001 From: Vitezslav Crhonek Date: Thu, 10 Apr 2014 14:14:29 +0200 Subject: Service-dbus: Improve EnumerateInstances efficiency --- src/service-dbus/LMI_ServiceProvider.c | 55 ++++++--- src/service-dbus/util/serviceutil.c | 199 +++++++++++++++++++++++++++++++++ src/service-dbus/util/serviceutil.h | 10 ++ 3 files changed, 249 insertions(+), 15 deletions(-) (limited to 'src/service-dbus') diff --git a/src/service-dbus/LMI_ServiceProvider.c b/src/service-dbus/LMI_ServiceProvider.c index ff61e49..709faa5 100644 --- a/src/service-dbus/LMI_ServiceProvider.c +++ b/src/service-dbus/LMI_ServiceProvider.c @@ -77,24 +77,49 @@ static CMPIStatus LMI_ServiceEnumInstances( const CMPIObjectPath* cop, const char** properties) { - CMPIStatus st; - CMPIEnumeration* e; - if (!(e = _cb->bft->enumerateInstanceNames(_cb, cc, cop, &st))) { - KReturn2(_cb, ERR_FAILED, "Unable to enumerate instances of LMI_Service"); - } - CMPIData cd; - while (CMHasNext(e, &st)) { + AllServices *svcs = NULL; + CMPIStatus status; + char output[1024]; - cd = CMGetNext(e, &st); - if (st.rc || cd.type != CMPI_ref) { - KReturn2(_cb, ERR_FAILED, "Enumerate instances didn't returned list of references"); - } - CMPIInstance *in = _cb->bft->getInstance(_cb, cc, cd.value.ref, properties, &st); - if (st.rc) { - KReturn2(_cb, ERR_FAILED, "Unable to get instance of LMI_Service"); + if ((svcs = service_get_properties_all(output, sizeof(output))) != NULL) { + for(int i = 0; i < svcs->cnt; i++) { + LMI_Service w; + LMI_Service_InitFromObjectPath(&w, _cb, cop); + LMI_Service_Set_CreationClassName(&w, LMI_Service_ClassName); + LMI_Service_Set_SystemCreationClassName(&w, get_system_creation_class_name()); + LMI_Service_Set_SystemName(&w, get_system_name()); + LMI_Service_Set_Name(&w, svcs->svc[i]->svName); + LMI_Service_Set_Status(&w, svcs->svc[i]->svStatus); + LMI_Service_Set_Started(&w, svcs->svc[i]->svStarted); + LMI_Service_Set_Caption(&w, svcs->svc[i]->svCaption); + LMI_Service_Init_OperationalStatus(&w, svcs->svc[i]->svOperationalStatusCnt); + for (int j = 0; j < svcs->svc[i]->svOperationalStatusCnt; j++) { + LMI_Service_Set_OperationalStatus(&w, j, svcs->svc[i]->svOperationalStatus[j]); + } + + switch (svcs->svc[i]->svEnabledDefault) { + case ENABLED: + LMI_Service_Set_EnabledDefault(&w, LMI_Service_EnabledDefault_Enabled); + break; + case DISABLED: + LMI_Service_Set_EnabledDefault(&w, LMI_Service_EnabledDefault_Disabled); + break; + default: + LMI_Service_Set_EnabledDefault(&w, LMI_Service_EnabledDefault_Not_Applicable); + break; + } + + status = __KReturnInstance((cr), &(w).__base); + if (!KOkay(status)) { + service_free_all_services(svcs); + return status; + } } - cr->ft->returnInstance(cr, in); + } else { + KReturn2(_cb, ERR_FAILED, "%s", output); } + + service_free_all_services(svcs); KReturn(OK); } diff --git a/src/service-dbus/util/serviceutil.c b/src/service-dbus/util/serviceutil.c index b56bd16..bca196e 100644 --- a/src/service-dbus/util/serviceutil.c +++ b/src/service-dbus/util/serviceutil.c @@ -56,6 +56,24 @@ void service_free_slist(SList *slist) return; } +void service_free_all_services(AllServices *svcs) +{ + int i; + + if (!svcs) + return; + + for(i = 0; i < svcs->cnt; i++) { + free(svcs->svc[i]->svName); + free(svcs->svc[i]->svCaption); + free(svcs->svc[i]->svStatus); + free(svcs->svc[i]); + } + free(svcs); + + return; +} + SList *service_find_all( char *output, int output_len) @@ -140,6 +158,187 @@ SList *service_find_all( return slist; } +AllServices *service_get_properties_all( + char *output, + int output_len) +{ + GDBusProxy *manager_proxy = NULL; + GDBusProxy *proxy = NULL; + GVariantIter *arr = NULL; + GVariant *result = NULL; + GVariant *result2 = NULL; + GError *error = NULL; + gchar *primary_unit_name = NULL, *unit_file_state = NULL; + gchar *unit, *value_str; + AllServices *svcs = NULL; + char *tmps = NULL; + + svcs = malloc(sizeof(AllServices)); + if (!svcs) { + strncpy(output, "Insufficient memory", output_len); + return NULL; + } + svcs->nalloc = INITIAL_SLIST_NALLOC; + svcs->svc = malloc(svcs->nalloc * sizeof(Service *)); + if (!svcs->svc) { + free(svcs); + strncpy(output, "Insufficient memory", output_len); + return NULL; + } + svcs->cnt = 0; + +#if !defined(GLIB_VERSION_2_36) + g_type_init(); +#endif + + manager_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, + NULL, MANAGER_NAME, MANAGER_OP, MANAGER_INTERFACE, NULL, &error); + if (!manager_proxy) goto err; + + error = NULL; + result = g_dbus_proxy_call_sync(manager_proxy, "ListUnitFiles", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) goto err; + + g_variant_get(result, "(a(ss))", &arr); + while (g_variant_iter_loop(arr, "(ss)", &primary_unit_name, &unit_file_state)) { + /* Ignore instantiable units (containing '@') until we find out how to properly present them */ + if (strstr(primary_unit_name, ".service") && strchr(primary_unit_name, '@') == NULL) { + + /* Realloc we are out of space */ + if (svcs->cnt >= svcs->nalloc) { + Service **tmpp = NULL; + svcs->nalloc *= 2; + tmpp = realloc(svcs->svc, svcs->nalloc * sizeof(Service *)); + if (!tmpp) { + g_variant_iter_free(arr); + service_free_all_services(svcs); + g_object_unref(manager_proxy); + strncpy(output, "Insufficient memory", output_len); + return NULL; + } + svcs->svc = tmpp; + } + + svcs->svc[svcs->cnt] = malloc(sizeof(Service)); + + /* Fill svName */ + tmps = strdup(primary_unit_name); + if (!tmps) { + g_variant_iter_free(arr); + service_free_all_services(svcs); + g_object_unref(manager_proxy); + strncpy(output, "Insufficient memory", output_len); + return NULL; + } + svcs->svc[svcs->cnt]->svName = strndup(basename(tmps), strlen(basename(tmps))); + if (!svcs->svc[svcs->cnt]->svName) { + free(tmps); + g_variant_iter_free(arr); + service_free_all_services(svcs); + g_object_unref(manager_proxy); + strncpy(output, "Insufficient memory", output_len); + return NULL; + } + free(tmps); + + /* Fill svEnabledDefault */ + svcs->svc[svcs->cnt]->svEnabledDefault = NOT_APPLICABLE; + if (strncmp(unit_file_state, "enabled", 7) == 0) + svcs->svc[svcs->cnt]->svEnabledDefault = ENABLED; + if (strncmp(unit_file_state, "disabled", 8) == 0) + svcs->svc[svcs->cnt]->svEnabledDefault = DISABLED; + + error = NULL; + result = g_dbus_proxy_call_sync(manager_proxy, "LoadUnit", g_variant_new("(s)", svcs->svc[svcs->cnt]->svName), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) goto err; + + g_variant_get(result, "(o)", &unit); + + proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, + NULL, MANAGER_NAME, unit, PROPERTY_INTERFACE, NULL, &error); + if (!proxy) goto err; + + error = NULL; + result = g_dbus_proxy_call_sync(proxy, "Get", g_variant_new("(ss)", UNIT_INTERFACE, "Description"), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) goto err; + + /* Fill svCaption */ + g_variant_get(result, "(v)", &result2); + g_variant_get(result2, "s", &value_str); + svcs->svc[svcs->cnt]->svCaption = strdup(value_str); + if (!svcs->svc[svcs->cnt]->svCaption) goto err; + + error = NULL; + result = g_dbus_proxy_call_sync(proxy, "Get", g_variant_new("(ss)", UNIT_INTERFACE, "ActiveState"), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) goto err; + + /* Fill svOperationalStatus, svStarted, svStatus */ + g_variant_get(result, "(v)", &result2); + g_variant_get(result2, "s", &value_str); + + if (strcmp(value_str, "active") == 0) { + svcs->svc[svcs->cnt]->svOperationalStatus[0] = OS_OK; + svcs->svc[svcs->cnt]->svOperationalStatusCnt = 1; + svcs->svc[svcs->cnt]->svStarted = 1; + svcs->svc[svcs->cnt]->svStatus = strdup("OK"); + } + else if (strcmp(value_str, "inactive") == 0) { + svcs->svc[svcs->cnt]->svOperationalStatus[0] = OS_COMPLETED; + svcs->svc[svcs->cnt]->svOperationalStatus[1] = OS_OK; + svcs->svc[svcs->cnt]->svOperationalStatusCnt = 2; + svcs->svc[svcs->cnt]->svStarted = 0; + svcs->svc[svcs->cnt]->svStatus = strdup("Stopped"); + } + else if (strcmp(value_str, "failed") == 0) { + svcs->svc[svcs->cnt]->svOperationalStatus[0] = OS_COMPLETED; + svcs->svc[svcs->cnt]->svOperationalStatus[1] = OS_ERROR; + svcs->svc[svcs->cnt]->svOperationalStatusCnt = 2; + svcs->svc[svcs->cnt]->svStarted = 0; + svcs->svc[svcs->cnt]->svStatus = strdup("Stopped"); + } + else if (strcmp(value_str, "activating") == 0) { + svcs->svc[svcs->cnt]->svOperationalStatus[0] = OS_STARTING; + svcs->svc[svcs->cnt]->svOperationalStatusCnt = 1; + svcs->svc[svcs->cnt]->svStarted = 0; + svcs->svc[svcs->cnt]->svStatus = strdup("Stopped"); + } + else if (strcmp(value_str, "deactivating") == 0) { + svcs->svc[svcs->cnt]->svOperationalStatus[0] = OS_STOPPING; + svcs->svc[svcs->cnt]->svOperationalStatusCnt = 1; + svcs->svc[svcs->cnt]->svStarted = 1; + svcs->svc[svcs->cnt]->svStatus = strdup("OK"); + } + if (!svcs->svc[svcs->cnt]->svStatus) goto err; + + g_object_unref(proxy); + svcs->cnt++; + } + } + g_variant_iter_free(arr); + arr = NULL; + + g_object_unref(manager_proxy); + manager_proxy = NULL; + + return svcs; + +err: + service_free_all_services(svcs); + if (error) { + strncpy(output, error->message, output_len); + g_error_free(error); + } + if (arr) g_variant_iter_free(arr); + if (manager_proxy) g_object_unref(manager_proxy); + if (proxy) g_object_unref(proxy); + + return NULL; +} + int service_get_properties( Service *svc, diff --git a/src/service-dbus/util/serviceutil.h b/src/service-dbus/util/serviceutil.h index 99a228e..c5b0abf 100644 --- a/src/service-dbus/util/serviceutil.h +++ b/src/service-dbus/util/serviceutil.h @@ -61,9 +61,19 @@ struct _SList { typedef struct _Service Service; typedef struct _SList SList; +struct _AllServices { + Service **svc; + int cnt; + int nalloc; +}; + +typedef struct _AllServices AllServices; + void service_free_slist(SList *slist); +void service_free_all_services(AllServices *svcs); SList *service_find_all(char *output, int output_len); +AllServices *service_get_properties_all(char *output, int output_len); int service_get_properties(Service *svc, const char *service, char *output, int output_len); unsigned int service_operation(const char *service, const char *method, char *output, int output_len); -- cgit