/* * Copyright (c) 2011-2015, Emulex * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "elxu_mgmt.h" #include #include #include #include #include #include #include #include #include #include #include static void display_mgmt_list(elxu_device_t *device); static void parse_node(mgmt_list_t *list, xmlNodePtr node); /* Functions for manipulating lists, objects, and properties */ static mgmt_list_t *parse_list(char *buf); #define INFO_BUFFER_SIZE 1024*1024 #define OCS_MGMT_MAX_NAME 128 #define EBUSY 16 void elxu_mgmt_info(elxu_device_t *device) { display_mgmt_list(device); } static void display_mgmt_list(elxu_device_t *device) { mgmt_list_t *status_list; mgmt_object_t *obj; printf("Mgmt values:\n"); status_list = mgmt_get_all(device); obj = status_list->head; while (obj) { mgmt_property_t *prop; prop = obj->head; while (prop) { if (strstr(prop->access, "r")) { printf("%s (%s) = %s\n", prop->name, prop->access, prop->value); } else { printf("%s (%s)\n", prop->name, prop->access); } prop = prop->next; } obj = obj->next; } mgmt_delete_list(status_list); } /** * @brief mgmt_new_list: Create a new empty linked list */ mgmt_list_t* mgmt_new_list() { mgmt_list_t *ret; ret = malloc(sizeof(mgmt_list_t)); if (ret != NULL) { ret->head = NULL; } return ret; } /** * @brief mgmt_delete_list Delete a linked list and free its contents */ void mgmt_delete_list(mgmt_list_t *list) { mgmt_object_t *node; mgmt_object_t *next; if (list != NULL) { node = list->head; while (node != NULL) { next = node->next; mgmt_delete_object(node); node = next; } free(list); } } /** * @brief mgmt_list_add: Add an object to the tail of a list */ void mgmt_list_add(mgmt_list_t *list, mgmt_object_t *object) { mgmt_object_t *node; object->next = NULL; if (list != NULL) { if (list->head == NULL) { list->head = object; return; } node = list->head; while (node->next != NULL) { node = node->next; } node->next = object; } } /** * @brief Remove an object from a list * * @par Description * Given a list and a property name, remove the first object found with that * property name from the list. * * @param list The list to operate on. * @param name The name of a property to remove. * * @return Returns a pointer to the removed object if found, NULL if not found. */ mgmt_object_t *mgmt_list_remove(mgmt_list_t *list, char *name) { mgmt_object_t *node; mgmt_object_t *result; mgmt_object_t *previous; result = NULL; previous = NULL; if (list == NULL) { return NULL; } if ((name == NULL) || (strlen(name) < 1)) { return NULL; } node = list->head; while (node) { if (strcmp(node->head->name, name) == 0) { /* Found the object */ result = node; if (previous == NULL) { /* Found it at the head of the list */ list->head = node->next; } else { /* Not at the head of the list */ previous->next = node->next; } break; } previous = node; node = node->next; } return result; } int mgmt_list_is_empty(mgmt_list_t *list) { return (list->head == NULL); } void mgmt_list_sort(mgmt_list_t *list) { mgmt_list_t *new_list; mgmt_object_t *obj; mgmt_object_t *smallest_obj; char *smallest_name; new_list = mgmt_new_list(); while (!mgmt_list_is_empty(list)) { /* Find the smallest in the list */ obj = list->head; smallest_obj = obj; smallest_name = obj->head->name; while (obj) { if (strcmp(obj->head->name, smallest_name) < 0) { smallest_name = obj->head->name; smallest_obj = obj; } obj = obj->next; } /* Remove the smallest from the list */ mgmt_list_remove(list, smallest_obj->head->name); /* Add it to the new list */ mgmt_list_add(new_list, smallest_obj); } /* At this point all items have been removed from list and placed on new_list in order */ /* Swap the lists */ list->head = new_list->head; new_list->head = NULL; mgmt_delete_list(new_list); } /** * @brief mgmt_new_property: Create a new property with the given name and value * */ mgmt_property_t *mgmt_new_property(char *name, char *value, char *access) { mgmt_property_t *ret; ret = malloc(sizeof(mgmt_property_t)); if (ret != NULL) { ret->name = strdup(name); ret->value = strdup(value); ret->access = strdup(access); ret->next = NULL; } return ret; } /** * @brief mgmt_delete_property: delete a property, freeing the name and value */ void mgmt_delete_property(mgmt_property_t *prop) { if (prop != NULL) { if (prop->name != NULL) { free(prop->name); } if (prop->value != NULL) { free(prop->value); } free(prop); } } /** * @brief mgmt_new_object: Create a new mgmt object */ mgmt_object_t *mgmt_new_object() { mgmt_object_t *ret; ret = malloc(sizeof(mgmt_object_t)); if (ret != NULL) { ret->head = NULL; ret->next = NULL; } return ret; } /** * @brief mgmt_delete_object: Delete a mgmt object * * Since an object is just a list of properties we just delete the list */ void mgmt_delete_object(mgmt_object_t *obj) { mgmt_property_t *prop; mgmt_property_t *next; if (obj != NULL) { prop = obj->head; while (prop) { next = prop->next; mgmt_delete_property(prop); prop = next; } free(obj); } } /** * @brief mgmt_object_add_property: Add a name/value pair to an object as a new property */ void mgmt_object_add_property(mgmt_object_t *obj, char *name, char *value, char *access) { mgmt_property_t *prop; mgmt_property_t *node; if (obj == NULL) { return; } prop = mgmt_new_property(name, value, access); if (prop != NULL) { if (obj->head == NULL) { obj->head = prop; return; } node = obj->head; while (node->next != NULL) { node = node->next; } node->next = prop; } } char* mgmt_get_value(elxu_device_t *device, char *name) { int rval; char *buf = calloc(INFO_BUFFER_SIZE, sizeof(char)); static char result[INFO_BUFFER_SIZE]; ocs_ioctl_cmd_get_t req; xmlDocPtr doc; xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; char xmlExpr[1024]; result[0] = '\0'; req.name = (uint8_t *)name; req.value = (uint8_t *) buf; req.value_length = INFO_BUFFER_SIZE; req.status = 0; rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_GET, &req); if (rval) { if (req.status == -EBUSY) { printf("Error: Device is busy in performing other operations. Please retry the command\n"); } free(buf); return result; } doc = xmlParseMemory(buf, strlen(buf)); if (doc == NULL) { // Failed to parse the XML result free(buf); return result; } xpathCtx = xmlXPathNewContext(doc); if (xpathCtx == NULL) { xmlFreeDoc(doc); free(buf); return result; } if (strchr(name, '[')) { /* * If the name has predicates in it we need to change the format * to the correct XPath format. That's because in the mgmt API * when we ask for domain[0] we want the domain with an instance * number of 0. In XPath indexes start with 1, and they are numbered * sequentially. So domain[1] would be the first domain found, not * the one with an instance number of 1. * * To fix this, anything in the name of the form "name[n]" needs to * be changed to "name[@instance='n']" */ char *src; char *dest; dest = xmlExpr; src = name; while (*src != '\0') { if (*src == '[') { *dest++ = *src++; strcpy(dest, "@instance='"); dest += strlen("@instance='"); while (*src != ']') { *dest++ = *src++; } *dest++ = '\''; } else { *dest++ = *src++; } } *dest = '\0'; } else { /* Simple case - no predicates in the name, just use it as-is */ sprintf(xmlExpr, "//%s", name); } xpathObj = xmlXPathEval((xmlChar *)xmlExpr, xpathCtx); if (xpathObj == NULL) { xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); free(buf); return result; } strncpy(result, (char *)xmlXPathCastNodeSetToString(xpathObj->nodesetval) , sizeof(result) - 1); xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); free(buf); return result; } int mgmt_set_value(elxu_device_t *device, char *name, char *value) { ocs_ioctl_cmd_set_t req; int rc; req.name = (uint8_t *) name; req.value = (uint8_t *) value; rc = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_SET, &req); if (rc == 0) { rc = req.result; if (rc == -EBUSY) { printf("Device is busy in performing other operations. Please retry the command\n"); } } return rc; } int mgmt_exec(elxu_device_t *device, char *name, void* arg_in, int arg_in_len, void* arg_out, int arg_out_len) { ocs_ioctl_action_t req; req.name = (uint8_t *)name; req.arg_in = arg_in; req.arg_in_length = arg_in_len; req.arg_out = arg_out; req.arg_out_length = arg_out_len; if (elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_EXEC, &req) != 0) { perror("ioctl"); } return req.result; } mgmt_list_t* mgmt_get_all(elxu_device_t* device) { char *buf = calloc(INFO_BUFFER_SIZE, sizeof(char)); ocs_ioctl_mgmt_buffer_t req; int rval; mgmt_list_t *status_list; // Send the MGMT_GET_ALL ioctl to get all mgmt values req.user_buffer = (uint8_t *) buf; req.user_buffer_len = INFO_BUFFER_SIZE; rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_GET_ALL, &req); if (rval < 0) { perror("ioctl"); } buf[req.bytes_written] = '\0'; status_list = parse_list(buf); free(buf); return status_list; } static mgmt_list_t *parse_list(char *buf) { mgmt_list_t *status_list; xmlDocPtr doc; xmlNodePtr cur; /* Create a list to store the values that we get back */ status_list = mgmt_new_list(); doc = xmlParseMemory(buf, strlen(buf)); if (doc == NULL) { // Failed to parse the XML result return status_list; } cur = xmlDocGetRootElement(doc); parse_node(status_list, cur); xmlFreeDoc(doc); return status_list; } static void parse_node(mgmt_list_t *list, xmlNodePtr node) { int numChildren; mgmt_object_t *obj; char long_name[OCS_MGMT_MAX_NAME]; char *value = calloc(INFO_BUFFER_SIZE, sizeof(char)); char *access; numChildren = xmlChildElementCount(node); if (numChildren == 0) { /* Leaf */ strncpy(long_name, (char *)xmlGetNodePath(node) , sizeof(long_name) - 1); strncpy(value, (char *)xmlNodeGetContent(node) , INFO_BUFFER_SIZE - 1); access = (char *)xmlGetProp(node, (xmlChar *)"mode"); if (access == NULL) { access = ""; } obj = mgmt_new_object(); mgmt_object_add_property(obj, long_name, value, access); mgmt_list_add(list, obj); } else { // Iterate over children, recursively parsing each xmlNodePtr child; child = xmlFirstElementChild(node); while (child) { parse_node(list, child); child = xmlNextElementSibling(child); } } free(value); } #if 0 current_section[0] = '\0'; /* Parse the values * We're looking for the beginning of a section: *
* Or the end of a section: *
* Or a property: * */ p = strtok(buf, "<"); while (p) { if (strncmp(p, "section", 7) == 0) { // Beginning of a section // Extract the name char *p2 = strstr(p, "name="); p2 += 6; char *p3 = strchr(p2, '"'); int len = p3 - p2; // The name is the (len) characters starting at (p2) char name[OCS_MGMT_MAX_NAME]; strncpy(name, p2, len); name[len] = '\0'; if (strlen(current_section) != 0) { strcat(current_section, "."); } strcat(current_section, name); } else if (strncmp(p, "/section", 8) == 0) { // End of a section char *p = strrchr(current_section, '.'); if (p != NULL) { *p = '\0'; } else { current_section[0] = '\0'; } } else if (strncmp(p, "property", 8) == 0) { // Property // Extract the name char *p2 = strstr(p, "name="); p2 += 6; char *p3 = strchr(p2, '"'); int len = p3 - p2; // The name is the (len) characters starting at (p2) char name[OCS_MGMT_MAX_NAME]; strncpy(name, p2, len); name[len] = '\0'; char long_name[OCS_MGMT_MAX_NAME]; strcpy(long_name, current_section); if (strlen(long_name) > 0) { strcat(long_name, "."); } strcat(long_name, name); obj = mgmt_new_object(); mgmt_object_add_property(obj, "name", long_name); mgmt_list_add(status_list, obj); } else { // Don't know what it is } p = strtok(NULL, "<"); } return status_list; } #endif