Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
elxu_mgmt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include "elxu_mgmt.h"
34 
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
42 
43 #include <ocs_ioctl.h>
44 #include <libxml/tree.h>
45 #include <libxml/xpath.h>
46 
47 #include <elxu_device.h>
48 
49 static void display_mgmt_list(elxu_device_t *device);
50 static void parse_node(mgmt_list_t *list, xmlNodePtr node);
51 
52 /* Functions for manipulating lists, objects, and properties */
53 static mgmt_list_t *parse_list(char *buf);
54 
55 #define INFO_BUFFER_SIZE 1024*1024
56 #define OCS_MGMT_MAX_NAME 128
57 #define EBUSY 16
58 
60 {
61  display_mgmt_list(device);
62 }
63 
64 static void display_mgmt_list(elxu_device_t *device)
65 {
66  mgmt_list_t *status_list;
67  mgmt_object_t *obj;
68 
69  printf("Mgmt values:\n");
70 
71  status_list = mgmt_get_all(device);
72 
73  obj = status_list->head;
74 
75  while (obj) {
76  mgmt_property_t *prop;
77 
78  prop = obj->head;
79  while (prop) {
80  if (strstr(prop->access, "r")) {
81  printf("%s (%s) = %s\n", prop->name, prop->access, prop->value);
82  } else {
83  printf("%s (%s)\n", prop->name, prop->access);
84  }
85 
86  prop = prop->next;
87  }
88  obj = obj->next;
89  }
90  mgmt_delete_list(status_list);
91 }
92 
93 /**
94  * @brief mgmt_new_list: Create a new empty linked list
95  */
97 {
98  mgmt_list_t *ret;
99 
100  ret = malloc(sizeof(mgmt_list_t));
101  if (ret != NULL) {
102  ret->head = NULL;
103  }
104 
105  return ret;
106 }
107 
108 /**
109  * @brief mgmt_delete_list Delete a linked list and free its contents
110  */
112 {
113  mgmt_object_t *node;
114  mgmt_object_t *next;
115 
116  if (list != NULL) {
117  node = list->head;
118  while (node != NULL) {
119  next = node->next;
120  mgmt_delete_object(node);
121  node = next;
122  }
123 
124  free(list);
125  }
126 }
127 
128 /**
129  * @brief mgmt_list_add: Add an object to the tail of a list
130  */
132 {
133  mgmt_object_t *node;
134 
135  object->next = NULL;
136 
137  if (list != NULL) {
138  if (list->head == NULL) {
139  list->head = object;
140  return;
141  }
142 
143  node = list->head;
144  while (node->next != NULL) {
145  node = node->next;
146  }
147 
148  node->next = object;
149  }
150 }
151 
152 /**
153  * @brief Remove an object from a list
154  *
155  * @par Description
156  * Given a list and a property name, remove the first object found with that
157  * property name from the list.
158  *
159  * @param list The list to operate on.
160  * @param name The name of a property to remove.
161  *
162  * @return Returns a pointer to the removed object if found, NULL if not found.
163  */
165 {
166  mgmt_object_t *node;
167  mgmt_object_t *result;
168  mgmt_object_t *previous;
169 
170  result = NULL;
171  previous = NULL;
172 
173  if (list == NULL) {
174  return NULL;
175  }
176 
177  if ((name == NULL) || (strlen(name) < 1)) {
178  return NULL;
179  }
180 
181  node = list->head;
182 
183  while (node) {
184  if (strcmp(node->head->name, name) == 0) {
185  /* Found the object */
186  result = node;
187 
188  if (previous == NULL) {
189  /* Found it at the head of the list */
190  list->head = node->next;
191  } else {
192  /* Not at the head of the list */
193  previous->next = node->next;
194  }
195 
196  break;
197  }
198 
199  previous = node;
200  node = node->next;
201  }
202 
203  return result;
204 }
205 
207 {
208  return (list->head == NULL);
209 }
210 
212 {
213  mgmt_list_t *new_list;
214  mgmt_object_t *obj;
215  mgmt_object_t *smallest_obj;
216  char *smallest_name;
217 
218  new_list = mgmt_new_list();
219 
220  while (!mgmt_list_is_empty(list)) {
221  /* Find the smallest in the list */
222  obj = list->head;
223  smallest_obj = obj;
224  smallest_name = obj->head->name;
225 
226  while (obj) {
227  if (strcmp(obj->head->name, smallest_name) < 0) {
228  smallest_name = obj->head->name;
229  smallest_obj = obj;
230  }
231 
232  obj = obj->next;
233  }
234 
235  /* Remove the smallest from the list */
236  mgmt_list_remove(list, smallest_obj->head->name);
237 
238  /* Add it to the new list */
239  mgmt_list_add(new_list, smallest_obj);
240  }
241 
242  /* At this point all items have been removed from list and placed on new_list in order */
243 
244  /* Swap the lists */
245  list->head = new_list->head;
246  new_list->head = NULL;
247 
248  mgmt_delete_list(new_list);
249 }
250 
251 /**
252  * @brief mgmt_new_property: Create a new property with the given name and value
253  *
254  */
255 mgmt_property_t *mgmt_new_property(char *name, char *value, char *access)
256 {
257  mgmt_property_t *ret;
258 
259  ret = malloc(sizeof(mgmt_property_t));
260  if (ret != NULL) {
261  ret->name = strdup(name);
262  ret->value = strdup(value);
263  ret->access = strdup(access);
264  ret->next = NULL;
265  }
266 
267  return ret;
268 }
269 
270 /**
271  * @brief mgmt_delete_property: delete a property, freeing the name and value
272  */
274 {
275  if (prop != NULL) {
276  if (prop->name != NULL) {
277  free(prop->name);
278  }
279  if (prop->value != NULL) {
280  free(prop->value);
281  }
282 
283  free(prop);
284  }
285 }
286 
287 /**
288  * @brief mgmt_new_object: Create a new mgmt object
289  */
291 {
292  mgmt_object_t *ret;
293 
294  ret = malloc(sizeof(mgmt_object_t));
295  if (ret != NULL) {
296  ret->head = NULL;
297  ret->next = NULL;
298  }
299 
300  return ret;
301 }
302 
303 /**
304  * @brief mgmt_delete_object: Delete a mgmt object
305  *
306  * Since an object is just a list of properties we just delete the list
307  */
309 {
310  mgmt_property_t *prop;
311  mgmt_property_t *next;
312 
313  if (obj != NULL) {
314  prop = obj->head;
315  while (prop) {
316  next = prop->next;
317  mgmt_delete_property(prop);
318  prop = next;
319 
320  }
321 
322  free(obj);
323  }
324 }
325 
326 /**
327  * @brief mgmt_object_add_property: Add a name/value pair to an object as a new property
328  */
329 void mgmt_object_add_property(mgmt_object_t *obj, char *name, char *value, char *access)
330 {
331  mgmt_property_t *prop;
332  mgmt_property_t *node;
333 
334  if (obj == NULL) {
335  return;
336  }
337 
338  prop = mgmt_new_property(name, value, access);
339  if (prop != NULL) {
340  if (obj->head == NULL) {
341  obj->head = prop;
342  return;
343  }
344 
345  node = obj->head;
346  while (node->next != NULL) {
347  node = node->next;
348  }
349 
350  node->next = prop;
351  }
352 }
353 
354 char* mgmt_get_value(elxu_device_t *device, char *name)
355 {
356  int rval;
357  char *buf = calloc(INFO_BUFFER_SIZE, sizeof(char));
358  static char result[INFO_BUFFER_SIZE];
360  xmlDocPtr doc;
361  xmlXPathContextPtr xpathCtx;
362  xmlXPathObjectPtr xpathObj;
363  char xmlExpr[1024];
364 
365  result[0] = '\0';
366 
367  req.name = (uint8_t *)name;
368  req.value = (uint8_t *) buf;
370  req.status = 0;
371 
372  rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_GET, &req);
373  if (rval) {
374  if (req.status == -EBUSY) {
375  printf("Error: Device is busy in performing other operations. Please retry the command\n");
376  }
377  free(buf);
378  return result;
379  }
380 
381  doc = xmlParseMemory(buf, strlen(buf));
382  if (doc == NULL) {
383  // Failed to parse the XML result
384  free(buf);
385  return result;
386  }
387  xpathCtx = xmlXPathNewContext(doc);
388  if (xpathCtx == NULL) {
389  xmlFreeDoc(doc);
390  free(buf);
391  return result;
392  }
393 
394  if (strchr(name, '[')) {
395  /*
396  * If the name has predicates in it we need to change the format
397  * to the correct XPath format. That's because in the mgmt API
398  * when we ask for domain[0] we want the domain with an instance
399  * number of 0. In XPath indexes start with 1, and they are numbered
400  * sequentially. So domain[1] would be the first domain found, not
401  * the one with an instance number of 1.
402  *
403  * To fix this, anything in the name of the form "name[n]" needs to
404  * be changed to "name[@instance='n']"
405  */
406  char *src;
407  char *dest;
408 
409  dest = xmlExpr;
410  src = name;
411 
412  while (*src != '\0') {
413  if (*src == '[') {
414  *dest++ = *src++;
415  strcpy(dest, "@instance='");
416  dest += strlen("@instance='");
417  while (*src != ']') {
418  *dest++ = *src++;
419  }
420  *dest++ = '\'';
421  } else {
422  *dest++ = *src++;
423  }
424  }
425  *dest = '\0';
426  } else {
427  /* Simple case - no predicates in the name, just use it as-is */
428  sprintf(xmlExpr, "//%s", name);
429  }
430 
431  xpathObj = xmlXPathEval((xmlChar *)xmlExpr, xpathCtx);
432  if (xpathObj == NULL) {
433  xmlXPathFreeContext(xpathCtx);
434  xmlFreeDoc(doc);
435  free(buf);
436  return result;
437  }
438 
439  strncpy(result, (char *)xmlXPathCastNodeSetToString(xpathObj->nodesetval) , sizeof(result) - 1);
440 
441  xmlXPathFreeContext(xpathCtx);
442  xmlFreeDoc(doc);
443  free(buf);
444  return result;
445 }
446 
447 int mgmt_set_value(elxu_device_t *device, char *name, char *value)
448 {
450  int rc;
451 
452  req.name = (uint8_t *) name;
453  req.value = (uint8_t *) value;
454 
455  rc = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_SET, &req);
456  if (rc == 0) {
457  rc = req.result;
458  if (rc == -EBUSY) {
459  printf("Device is busy in performing other operations. Please retry the command\n");
460  }
461  }
462 
463  return rc;
464 }
465 
466 int mgmt_exec(elxu_device_t *device, char *name, void* arg_in, int arg_in_len, void* arg_out, int arg_out_len)
467 {
468  ocs_ioctl_action_t req;
469 
470  req.name = (uint8_t *)name;
471  req.arg_in = arg_in;
472  req.arg_in_length = arg_in_len;
473  req.arg_out = arg_out;
474  req.arg_out_length = arg_out_len;
475 
476  if (elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_EXEC, &req) != 0) {
477  perror("ioctl");
478  }
479  return req.result;
480 }
481 
483 {
484  char *buf = calloc(INFO_BUFFER_SIZE, sizeof(char));
486  int rval;
487  mgmt_list_t *status_list;
488 
489  // Send the MGMT_GET_ALL ioctl to get all mgmt values
490  req.user_buffer = (uint8_t *) buf;
492 
493  rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_MGMT_GET_ALL, &req);
494 
495  if (rval < 0) {
496  perror("ioctl");
497  }
498 
499  buf[req.bytes_written] = '\0';
500 
501  status_list = parse_list(buf);
502 
503  free(buf);
504  return status_list;
505 }
506 
507 static mgmt_list_t *parse_list(char *buf)
508 {
509  mgmt_list_t *status_list;
510 
511  xmlDocPtr doc;
512  xmlNodePtr cur;
513 
514 
515  /* Create a list to store the values that we get back */
516  status_list = mgmt_new_list();
517 
518  doc = xmlParseMemory(buf, strlen(buf));
519  if (doc == NULL) {
520  // Failed to parse the XML result
521  return status_list;
522  }
523  cur = xmlDocGetRootElement(doc);
524 
525  parse_node(status_list, cur);
526 
527  xmlFreeDoc(doc);
528  return status_list;
529 }
530 
531 static void parse_node(mgmt_list_t *list, xmlNodePtr node)
532 {
533  int numChildren;
534  mgmt_object_t *obj;
535  char long_name[OCS_MGMT_MAX_NAME];
536  char *value = calloc(INFO_BUFFER_SIZE, sizeof(char));
537  char *access;
538 
539  numChildren = xmlChildElementCount(node);
540  if (numChildren == 0) {
541  /* Leaf */
542  strncpy(long_name, (char *)xmlGetNodePath(node) , sizeof(long_name) - 1);
543  strncpy(value, (char *)xmlNodeGetContent(node) , INFO_BUFFER_SIZE - 1);
544  access = (char *)xmlGetProp(node, (xmlChar *)"mode");
545  if (access == NULL) {
546  access = "";
547  }
548 
549  obj = mgmt_new_object();
550  mgmt_object_add_property(obj, long_name, value, access);
551  mgmt_list_add(list, obj);
552  } else {
553  // Iterate over children, recursively parsing each
554  xmlNodePtr child;
555 
556  child = xmlFirstElementChild(node);
557  while (child) {
558  parse_node(list, child);
559  child = xmlNextElementSibling(child);
560  }
561  }
562  free(value);
563 }
564 
565 #if 0
566  current_section[0] = '\0';
567 
568 
569 
570  /* Parse the values
571  * We're looking for the beginning of a section:
572  * <section name="foo">
573  * Or the end of a section:
574  * </section>
575  * Or a property:
576  * <property name="foo" />
577  */
578  p = strtok(buf, "<");
579  while (p) {
580 
581  if (strncmp(p, "section", 7) == 0) {
582  // Beginning of a section
583  // Extract the name
584  char *p2 = strstr(p, "name=");
585  p2 += 6;
586  char *p3 = strchr(p2, '"');
587  int len = p3 - p2;
588  // The name is the (len) characters starting at (p2)
589  char name[OCS_MGMT_MAX_NAME];
590  strncpy(name, p2, len);
591  name[len] = '\0';
592 
593  if (strlen(current_section) != 0) {
594  strcat(current_section, ".");
595  }
596  strcat(current_section, name);
597 
598  } else if (strncmp(p, "/section", 8) == 0) {
599  // End of a section
600  char *p = strrchr(current_section, '.');
601  if (p != NULL) {
602  *p = '\0';
603  } else {
604  current_section[0] = '\0';
605  }
606  } else if (strncmp(p, "property", 8) == 0) {
607  // Property
608  // Extract the name
609  char *p2 = strstr(p, "name=");
610  p2 += 6;
611  char *p3 = strchr(p2, '"');
612  int len = p3 - p2;
613  // The name is the (len) characters starting at (p2)
614  char name[OCS_MGMT_MAX_NAME];
615  strncpy(name, p2, len);
616  name[len] = '\0';
617 
618  char long_name[OCS_MGMT_MAX_NAME];
619  strcpy(long_name, current_section);
620  if (strlen(long_name) > 0) {
621  strcat(long_name, ".");
622  }
623  strcat(long_name, name);
624 
625  obj = mgmt_new_object();
626  mgmt_object_add_property(obj, "name", long_name);
627  mgmt_list_add(status_list, obj);
628  } else {
629  // Don't know what it is
630  }
631 
632  p = strtok(NULL, "<");
633  }
634 
635  return status_list;
636 }
637 #endif
mgmt_property_t * mgmt_new_property(char *name, char *value, char *access)
mgmt_new_property: Create a new property with the given name and value
Definition: elxu_mgmt.c:255
static void display_mgmt_list(elxu_device_t *device)
Definition: elxu_mgmt.c:64
struct mgmt_object * head
Definition: elxu_mgmt.h:62
void mgmt_delete_object(mgmt_object_t *obj)
mgmt_delete_object: Delete a mgmt object
Definition: elxu_mgmt.c:308
mgmt_object_t * mgmt_new_object()
mgmt_new_object: Create a new mgmt object
Definition: elxu_mgmt.c:290
uint32_t arg_in_length
Definition: ocs_ioctl.h:358
char * value
Definition: elxu_mgmt.h:45
struct mgmt_property * next
Definition: elxu_mgmt.h:47
#define OCS_IOCTL_CMD_MGMT_SET
Definition: ocs_ioctl.h:492
#define INFO_BUFFER_SIZE
Definition: elxu_mgmt.c:55
#define OCS_MGMT_MAX_NAME
Definition: elxu_mgmt.c:56
#define OCS_IOCTL_CMD_MGMT_GET
Definition: ocs_ioctl.h:490
int mgmt_exec(elxu_device_t *device, char *name, void *arg_in, int arg_in_len, void *arg_out, int arg_out_len)
Definition: elxu_mgmt.c:466
static mgmt_list_t * parse_list(char *buf)
Definition: elxu_mgmt.c:507
void elxu_mgmt_info(elxu_device_t *device)
Definition: elxu_mgmt.c:59
#define EBUSY
Definition: elxu_mgmt.c:57
static void parse_node(mgmt_list_t *list, xmlNodePtr node)
Definition: elxu_mgmt.c:531
int elxu_ioctl_device(elxu_device_t *device, int req, void *arg)
Send an ioctl to a device.
Definition: elxu_device.c:322
void mgmt_delete_property(mgmt_property_t *prop)
mgmt_delete_property: delete a property, freeing the name and value
Definition: elxu_mgmt.c:273
uint8_t * name
Definition: ocs_ioctl.h:356
mgmt_object_t * mgmt_list_remove(mgmt_list_t *list, char *name)
Remove an object from a list.
Definition: elxu_mgmt.c:164
struct mgmt_object * next
Definition: elxu_mgmt.h:55
int mgmt_set_value(elxu_device_t *device, char *name, char *value)
Definition: elxu_mgmt.c:447
#define OCS_IOCTL_CMD_MGMT_GET_ALL
Definition: ocs_ioctl.h:491
#define OCS_IOCTL_CMD_MGMT_EXEC
Definition: ocs_ioctl.h:494
void mgmt_delete_list(mgmt_list_t *list)
mgmt_delete_list Delete a linked list and free its contents
Definition: elxu_mgmt.c:111
mgmt_list is a linked list of objects
Definition: elxu_mgmt.h:61
void mgmt_object_add_property(mgmt_object_t *obj, char *name, char *value, char *access)
mgmt_object_add_property: Add a name/value pair to an object as a new property
Definition: elxu_mgmt.c:329
char * access
Definition: elxu_mgmt.h:46
mgmt_list_t * mgmt_get_all(elxu_device_t *device)
Definition: elxu_mgmt.c:482
mgmt_object is a list of properties
Definition: elxu_mgmt.h:53
mgmt_list_t * mgmt_new_list()
mgmt_new_list: Create a new empty linked list
Definition: elxu_mgmt.c:96
OCS_CTL_CMD_GET_STATUS, OCS_CTL_CMD_GET_CONFIG.
Definition: ocs_ioctl.h:336
void mgmt_list_sort(mgmt_list_t *list)
Definition: elxu_mgmt.c:211
mgmt_property is a name / value pair
Definition: elxu_mgmt.h:43
int mgmt_list_is_empty(mgmt_list_t *list)
Definition: elxu_mgmt.c:206
uint32_t value_length
Definition: ocs_ioctl.h:345
uint32_t arg_out_length
Definition: ocs_ioctl.h:360
struct mgmt_property * head
Definition: elxu_mgmt.h:54
char * mgmt_get_value(elxu_device_t *device, char *name)
Definition: elxu_mgmt.c:354
void mgmt_list_add(mgmt_list_t *list, mgmt_object_t *object)
mgmt_list_add: Add an object to the tail of a list
Definition: elxu_mgmt.c:131