pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
nvpair.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <glib.h>
17 #include <libxml/tree.h>
18 
19 #include <crm/crm.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/xml.h>
24 #include "crmcommon_private.h"
25 
26 /*
27  * This file isolates handling of three types of name/value pairs:
28  *
29  * - pcmk_nvpair_t data type
30  * - XML attributes (<TAG ... NAME=VALUE ...>)
31  * - XML nvpair elements (<nvpair id=ID name=NAME value=VALUE>)
32  */
33 
34 // pcmk_nvpair_t handling
35 
47 static pcmk_nvpair_t *
48 pcmk__new_nvpair(const char *name, const char *value)
49 {
50  pcmk_nvpair_t *nvpair = NULL;
51 
53 
54  nvpair = calloc(1, sizeof(pcmk_nvpair_t));
55  CRM_ASSERT(nvpair);
56 
57  nvpair->name = strdup(name);
58  nvpair->value = value? strdup(value) : NULL;
59  return nvpair;
60 }
61 
68 static void
69 pcmk__free_nvpair(gpointer data)
70 {
71  if (data) {
72  pcmk_nvpair_t *nvpair = data;
73 
74  free(nvpair->name);
75  free(nvpair->value);
76  free(nvpair);
77  }
78 }
79 
91 GSList *
92 pcmk_prepend_nvpair(GSList *nvpairs, const char *name, const char *value)
93 {
94  return g_slist_prepend(nvpairs, pcmk__new_nvpair(name, value));
95 }
96 
102 void
103 pcmk_free_nvpairs(GSList *nvpairs)
104 {
105  g_slist_free_full(nvpairs, pcmk__free_nvpair);
106 }
107 
117 static gint
118 pcmk__compare_nvpair(gconstpointer a, gconstpointer b)
119 {
120  int rc = 0;
121  const pcmk_nvpair_t *pair_a = a;
122  const pcmk_nvpair_t *pair_b = b;
123 
124  CRM_ASSERT(a != NULL);
125  CRM_ASSERT(pair_a->name != NULL);
126 
127  CRM_ASSERT(b != NULL);
128  CRM_ASSERT(pair_b->name != NULL);
129 
130  rc = strcmp(pair_a->name, pair_b->name);
131  if (rc < 0) {
132  return -1;
133  } else if (rc > 0) {
134  return 1;
135  }
136  return 0;
137 }
138 
146 GSList *
147 pcmk_sort_nvpairs(GSList *list)
148 {
149  return g_slist_sort(list, pcmk__compare_nvpair);
150 }
151 
161 GSList *
163 {
164  GSList *result = NULL;
165 
166  for (xmlAttrPtr iter = pcmk__first_xml_attr(xml); iter != NULL;
167  iter = iter->next) {
168 
169  result = pcmk_prepend_nvpair(result,
170  (const char *) iter->name,
171  (const char *) pcmk__xml_attr_value(iter));
172  }
173  return result;
174 }
175 
186 static void
187 pcmk__nvpair_add_xml_attr(gpointer data, gpointer user_data)
188 {
189  pcmk_nvpair_t *pair = data;
190  xmlNode *parent = user_data;
191 
192  crm_xml_add(parent, pair->name, pair->value);
193 }
194 
201 void
202 pcmk_nvpairs2xml_attrs(GSList *list, xmlNode *xml)
203 {
204  g_slist_foreach(list, pcmk__nvpair_add_xml_attr, xml);
205 }
206 
207 // convenience function for name=value strings
208 
220 int
221 pcmk_scan_nvpair(const char *input, char **name, char **value)
222 {
223 #ifdef SSCANF_HAS_M
224  *name = NULL;
225  *value = NULL;
226  if (sscanf(input, "%m[^=]=%m[^\n]", name, value) <= 0) {
227  return -pcmk_err_bad_nvpair;
228  }
229 #else
230  char *sep = NULL;
231  *name = NULL;
232  *value = NULL;
233 
234  sep = strstr(optarg, "=");
235  if (sep == NULL) {
236  return -pcmk_err_bad_nvpair;
237  }
238 
239  *name = strndup(input, sep-input);
240 
241  if (*name == NULL) {
242  return -ENOMEM;
243  }
244 
245  /* If the last char in optarg is =, the user gave no
246  * value for the option. Leave it as NULL.
247  */
248  if (*(sep+1) != '\0') {
249  *value = strdup(sep+1);
250 
251  if (*value == NULL) {
252  return -ENOMEM;
253  }
254  }
255 #endif
256 
257  if (*name != NULL && *value != NULL) {
258  return 2;
259  } else if (*name != NULL || *value != NULL) {
260  return 1;
261  } else {
262  return -pcmk_err_bad_nvpair;
263  }
264 }
265 
281 char *
282 pcmk_format_nvpair(const char *name, const char *value, const char *units) {
283  return crm_strdup_printf("%s=\"%s%s\"", name, value, units ? units : "");
284 }
285 
297 char *
298 pcmk_format_named_time(const char *name, time_t epoch_time) {
299  const char *now_str = pcmk__epoch2str(&epoch_time);
300 
301  return crm_strdup_printf("%s=\"%s\"", name, now_str ? now_str : "");
302 }
303 
304 // XML attribute handling
305 
316 const char *
317 crm_xml_add(xmlNode *node, const char *name, const char *value)
318 {
319  bool dirty = FALSE;
320  xmlAttr *attr = NULL;
321 
322  CRM_CHECK(node != NULL, return NULL);
323  CRM_CHECK(name != NULL, return NULL);
324 
325  if (value == NULL) {
326  return NULL;
327  }
328 #if XML_PARANOIA_CHECKS
329  {
330  const char *old_value = NULL;
331 
332  old_value = crm_element_value(node, name);
333 
334  /* Could be re-setting the same value */
335  CRM_CHECK(old_value != value,
336  crm_err("Cannot reset %s with crm_xml_add(%s)", name, value);
337  return value);
338  }
339 #endif
340 
341  if (pcmk__tracking_xml_changes(node, FALSE)) {
342  const char *old = crm_element_value(node, name);
343 
344  if (old == NULL || value == NULL || strcmp(old, value) != 0) {
345  dirty = TRUE;
346  }
347  }
348 
349  if (dirty && (pcmk__check_acl(node, name, xpf_acl_create) == FALSE)) {
350  crm_trace("Cannot add %s=%s to %s", name, value, node->name);
351  return NULL;
352  }
353 
354  attr = xmlSetProp(node, (pcmkXmlStr) name, (pcmkXmlStr) value);
355  if (dirty) {
357  }
358 
359  CRM_CHECK(attr && attr->children && attr->children->content, return NULL);
360  return (char *)attr->children->content;
361 }
362 
373 const char *
374 crm_xml_replace(xmlNode *node, const char *name, const char *value)
375 {
376  bool dirty = FALSE;
377  xmlAttr *attr = NULL;
378  const char *old_value = NULL;
379 
380  CRM_CHECK(node != NULL, return NULL);
381  CRM_CHECK(name != NULL && name[0] != 0, return NULL);
382 
383  old_value = crm_element_value(node, name);
384 
385  /* Could be re-setting the same value */
386  CRM_CHECK(old_value != value, return value);
387 
388  if (pcmk__check_acl(node, name, xpf_acl_write) == FALSE) {
389  /* Create a fake object linked to doc->_private instead? */
390  crm_trace("Cannot replace %s=%s to %s", name, value, node->name);
391  return NULL;
392 
393  } else if (old_value && !value) {
394  xml_remove_prop(node, name);
395  return NULL;
396  }
397 
398  if (pcmk__tracking_xml_changes(node, FALSE)) {
399  if (!old_value || !value || !strcmp(old_value, value)) {
400  dirty = TRUE;
401  }
402  }
403 
404  attr = xmlSetProp(node, (pcmkXmlStr) name, (pcmkXmlStr) value);
405  if (dirty) {
407  }
408  CRM_CHECK(attr && attr->children && attr->children->content, return NULL);
409  return (char *) attr->children->content;
410 }
411 
424 const char *
425 crm_xml_add_int(xmlNode *node, const char *name, int value)
426 {
427  char *number = crm_itoa(value);
428  const char *added = crm_xml_add(node, name, number);
429 
430  free(number);
431  return added;
432 }
433 
446 const char *
447 crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
448 {
449  char *number = crm_strdup_printf("%u", ms);
450  const char *added = crm_xml_add(node, name, number);
451 
452  free(number);
453  return added;
454 }
455 
456 // Maximum size of null-terminated string representation of 64-bit integer
457 // -9223372036854775808
458 #define LLSTRSIZE 21
459 
474 const char *
475 crm_xml_add_ll(xmlNode *xml, const char *name, long long value)
476 {
477  char s[LLSTRSIZE] = { '\0', };
478 
479  if (snprintf(s, LLSTRSIZE, "%lld", (long long) value) == LLSTRSIZE) {
480  return NULL;
481  }
482  return crm_xml_add(xml, name, s);
483 }
484 
498 const char *
499 crm_xml_add_timeval(xmlNode *xml, const char *name_sec, const char *name_usec,
500  const struct timeval *value)
501 {
502  const char *added = NULL;
503 
504  if (xml && name_sec && value) {
505  added = crm_xml_add_ll(xml, name_sec, (long long) value->tv_sec);
506  if (added && name_usec) {
507  // Any error is ignored (we successfully added seconds)
508  crm_xml_add_ll(xml, name_usec, (long long) value->tv_usec);
509  }
510  }
511  return added;
512 }
513 
522 const char *
523 crm_element_value(const xmlNode *data, const char *name)
524 {
525  xmlAttr *attr = NULL;
526 
527  if (data == NULL) {
528  crm_err("Couldn't find %s in NULL", name ? name : "<null>");
529  CRM_LOG_ASSERT(data != NULL);
530  return NULL;
531 
532  } else if (name == NULL) {
533  crm_err("Couldn't find NULL in %s", crm_element_name(data));
534  return NULL;
535  }
536 
537  /* The first argument to xmlHasProp() has always been const,
538  * but libxml2 <2.9.2 didn't declare that, so cast it
539  */
540  attr = xmlHasProp((xmlNode *) data, (pcmkXmlStr) name);
541  if (!attr || !attr->children) {
542  return NULL;
543  }
544  return (const char *) attr->children->content;
545 }
546 
558 int
559 crm_element_value_int(const xmlNode *data, const char *name, int *dest)
560 {
561  const char *value = NULL;
562 
563  CRM_CHECK(dest != NULL, return -1);
564  value = crm_element_value(data, name);
565  if (value) {
566  errno = 0;
567  *dest = crm_parse_int(value, NULL);
568  if (errno == 0) {
569  return 0;
570  }
571  }
572  return -1;
573 }
574 
586 int
587 crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
588 {
589  const char *value = NULL;
590 
591  CRM_CHECK(dest != NULL, return -1);
592  value = crm_element_value(data, name);
593  if (value) {
594  errno = 0;
595  *dest = crm_parse_ll(value, NULL);
596  if (errno == 0) {
597  return 0;
598  }
599  }
600  return -1;
601 }
602 
614 int
615 crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
616 {
617  const char *value = NULL;
618  long long value_ll;
619 
620  CRM_CHECK(dest != NULL, return -1);
621  *dest = 0;
622 
623  value = crm_element_value(data, name);
624  if (value == NULL) {
625  return pcmk_ok;
626  }
627 
628  errno = 0;
629  value_ll = crm_parse_ll(value, NULL);
630  if ((errno != 0) || (value_ll < 0) || (value_ll > G_MAXUINT)) {
631  return -1;
632  }
633 
634  *dest = (guint) value_ll;
635  return pcmk_ok;
636 }
637 
649 int
650 crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
651 {
652  long long value_ll = 0;
653 
654  if (crm_element_value_ll(xml, name, &value_ll) < 0) {
655  return -1;
656  }
657 
658  /* Unfortunately, we can't do any bounds checking, since time_t has neither
659  * standardized bounds nor constants defined for them.
660  */
661  *dest = (time_t) value_ll;
662  return pcmk_ok;
663 }
664 
678 int
679 crm_element_value_timeval(const xmlNode *xml, const char *name_sec,
680  const char *name_usec, struct timeval *dest)
681 {
682  long long value_i = 0;
683 
684  CRM_CHECK(dest != NULL, return -EINVAL);
685  dest->tv_sec = 0;
686  dest->tv_usec = 0;
687 
688  if (xml == NULL) {
689  return pcmk_ok;
690  }
691 
692  /* Unfortunately, we can't do any bounds checking, since there are no
693  * constants provided for the bounds of time_t and suseconds_t, and
694  * calculating them isn't worth the effort. If there are XML values
695  * beyond the native sizes, there will probably be worse problems anyway.
696  */
697 
698  // Parse seconds
699  errno = 0;
700  if (crm_element_value_ll(xml, name_sec, &value_i) < 0) {
701  return -errno;
702  }
703  dest->tv_sec = (time_t) value_i;
704 
705  // Parse microseconds
706  if (crm_element_value_ll(xml, name_usec, &value_i) < 0) {
707  return -errno;
708  }
709  dest->tv_usec = (suseconds_t) value_i;
710 
711  return pcmk_ok;
712 }
713 
725 char *
726 crm_element_value_copy(const xmlNode *data, const char *name)
727 {
728  char *value_copy = NULL;
729  const char *value = crm_element_value(data, name);
730 
731  if (value != NULL) {
732  value_copy = strdup(value);
733  }
734  return value_copy;
735 }
736 
750 void
751 hash2smartfield(gpointer key, gpointer value, gpointer user_data)
752 {
753  const char *name = key;
754  const char *s_value = value;
755 
756  xmlNode *xml_node = user_data;
757 
758  if (isdigit(name[0])) {
759  xmlNode *tmp = create_xml_node(xml_node, XML_TAG_PARAM);
760 
762  crm_xml_add(tmp, XML_NVPAIR_ATTR_VALUE, s_value);
763 
764  } else if (crm_element_value(xml_node, name) == NULL) {
765  crm_xml_add(xml_node, name, s_value);
766  crm_trace("dumped: %s=%s", name, s_value);
767 
768  } else {
769  crm_trace("duplicate: %s=%s", name, s_value);
770  }
771 }
772 
784 void
785 hash2field(gpointer key, gpointer value, gpointer user_data)
786 {
787  const char *name = key;
788  const char *s_value = value;
789 
790  xmlNode *xml_node = user_data;
791 
792  if (crm_element_value(xml_node, name) == NULL) {
793  crm_xml_add(xml_node, name, s_value);
794 
795  } else {
796  crm_trace("duplicate: %s=%s", name, s_value);
797  }
798 }
799 
812 void
813 hash2metafield(gpointer key, gpointer value, gpointer user_data)
814 {
815  char *crm_name = NULL;
816 
817  if (key == NULL || value == NULL) {
818  return;
819  }
820 
821  /* Filter out cluster-generated attributes that contain a '#' or ':'
822  * (like fail-count and last-failure).
823  */
824  for (crm_name = key; *crm_name; ++crm_name) {
825  if ((*crm_name == '#') || (*crm_name == ':')) {
826  return;
827  }
828  }
829 
830  crm_name = crm_meta_name(key);
831  hash2field(crm_name, value, user_data);
832  free(crm_name);
833 }
834 
835 // nvpair handling
836 
847 xmlNode *
848 crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name,
849  const char *value)
850 {
851  xmlNode *nvp;
852 
853  /* id can be NULL so we auto-generate one, and name can be NULL if this
854  * will be used to delete a name/value pair by ID, but both can't be NULL
855  */
856  CRM_CHECK(id || name, return NULL);
857 
858  nvp = create_xml_node(parent, XML_CIB_TAG_NVPAIR);
859  CRM_CHECK(nvp, return NULL);
860 
861  if (id) {
862  crm_xml_add(nvp, XML_ATTR_ID, id);
863  } else {
864  const char *parent_id = ID(parent);
865 
866  crm_xml_set_id(nvp, "%s-%s",
867  (parent_id? parent_id : XML_CIB_TAG_NVPAIR), name);
868  }
870  crm_xml_add(nvp, XML_NVPAIR_ATTR_VALUE, value);
871  return nvp;
872 }
873 
885 void
886 hash2nvpair(gpointer key, gpointer value, gpointer user_data)
887 {
888  const char *name = key;
889  const char *s_value = value;
890  xmlNode *xml_node = user_data;
891 
892  crm_create_nvpair_xml(xml_node, name, name, s_value);
893  crm_trace("dumped: name=%s value=%s", name, s_value);
894 }
895 
910 GHashTable *
911 xml2list(xmlNode *parent)
912 {
913  xmlNode *child = NULL;
914  xmlAttrPtr pIter = NULL;
915  xmlNode *nvpair_list = NULL;
916  GHashTable *nvpair_hash = crm_str_table_new();
917 
918  CRM_CHECK(parent != NULL, return nvpair_hash);
919 
920  nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
921  if (nvpair_list == NULL) {
922  crm_trace("No attributes in %s", crm_element_name(parent));
923  crm_log_xml_trace(parent, "No attributes for resource op");
924  }
925 
926  crm_log_xml_trace(nvpair_list, "Unpacking");
927 
928  for (pIter = pcmk__first_xml_attr(nvpair_list); pIter != NULL;
929  pIter = pIter->next) {
930 
931  const char *p_name = (const char *)pIter->name;
932  const char *p_value = pcmk__xml_attr_value(pIter);
933 
934  crm_trace("Added %s=%s", p_name, p_value);
935 
936  g_hash_table_insert(nvpair_hash, strdup(p_name), strdup(p_value));
937  }
938 
939  for (child = pcmk__xml_first_child(nvpair_list); child != NULL;
940  child = pcmk__xml_next(child)) {
941 
942  if (strcmp((const char *)child->name, XML_TAG_PARAM) == 0) {
943  const char *key = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
944  const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
945 
946  crm_trace("Added %s=%s", key, value);
947  if (key != NULL && value != NULL) {
948  g_hash_table_insert(nvpair_hash, strdup(key), strdup(value));
949  }
950  }
951  }
952 
953  return nvpair_hash;
954 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:447
GSList * pcmk_prepend_nvpair(GSList *nvpairs, const char *name, const char *value)
Prepend a name/value pair to a list.
Definition: nvpair.c:92
A dumping ground.
char * name
Definition: nvpair.h:29
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: nvpair.c:587
GSList * pcmk_xml_attrs2nvpairs(xmlNode *xml)
Create a list of name/value pairs from an XML node's attributes.
Definition: nvpair.c:162
char * value
Definition: nvpair.h:30
G_GNUC_INTERNAL void pcmk__mark_xml_attr_dirty(xmlAttr *a)
Definition: xml.c:174
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:615
#define XML_TAG_ATTRS
Definition: msg_xml.h:172
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:134
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:346
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:199
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:167
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
Definition: nvpair.c:848
char * strndup(const char *str, size_t len)
char * crm_meta_name(const char *field)
Definition: utils.c:457
int crm_element_value_timeval(const xmlNode *xml, const char *name_sec, const char *name_usec, struct timeval *dest)
Retrieve the value of XML second/microsecond attributes as time.
Definition: nvpair.c:679
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
Definition: acl.c:615
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry, as meta-attribute name.
Definition: nvpair.c:813
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:911
int rc
Definition: pcmk_fence.c:35
void pcmk_nvpairs2xml_attrs(GSList *list, xmlNode *xml)
Add XML attributes based on a list of name/value pairs.
Definition: nvpair.c:202
#define XML_ATTR_ID
Definition: msg_xml.h:96
char * pcmk_format_nvpair(const char *name, const char *value, const char *units)
Definition: nvpair.c:282
#define crm_trace(fmt, args...)
Definition: logging.h:353
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:785
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:103
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:751
Wrappers for and extensions to libxml2.
char * pcmk_format_named_time(const char *name, time_t epoch_time)
Definition: nvpair.c:298
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
#define LLSTRSIZE
Definition: nvpair.c:458
void hash2nvpair(gpointer key, gpointer value, gpointer user_data)
Add XML nvpair element based on hash table entry.
Definition: nvpair.c:886
const char * pcmk__epoch2str(time_t *when)
Definition: iso8601.c:1715
GSList * pcmk_sort_nvpairs(GSList *list)
Sort a list of name/value pairs.
Definition: nvpair.c:147
const xmlChar * pcmkXmlStr
Definition: xml.h:51
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Replace an XML attribute with specified name and (possibly NULL) value.
Definition: nvpair.c:374
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
Definition: strings.c:107
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:425
void crm_xml_set_id(xmlNode *xml, const char *format,...) __attribute__((__format__(__printf__
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition: nvpair.c:650
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2019
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:317
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:347
const char * crm_xml_add_ll(xmlNode *xml, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition: nvpair.c:475
char data[0]
Definition: internal.h:90
#define pcmk_ok
Definition: results.h:67
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:726
const char * crm_xml_add_timeval(xmlNode *xml, const char *name_sec, const char *name_usec, const struct timeval *value)
Create XML attributes for seconds and microseconds.
Definition: nvpair.c:499
#define crm_log_xml_trace(xml, text)
Definition: logging.h:361
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
Definition: nvpair.c:447
G_GNUC_INTERNAL bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
Definition: xml.c:52
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:559
#define ID(x)
Definition: msg_xml.h:425
char * name
Definition: pcmk_fence.c:31
int pcmk_scan_nvpair(const char *input, char **name, char **value)
Extract the name and value from an input string formatted as "name=value". If unable to extract them,...
Definition: nvpair.c:221
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define pcmk_err_bad_nvpair
Definition: results.h:90
#define XML_TAG_PARAM
Definition: msg_xml.h:177