This source file includes following definitions.
- pcmk__new_nvpair
- pcmk__free_nvpair
- pcmk_prepend_nvpair
- pcmk_free_nvpairs
- pcmk__compare_nvpair
- pcmk_sort_nvpairs
- pcmk_xml_attrs2nvpairs
- pcmk__nvpair_add_xml_attr
- pcmk_nvpairs2xml_attrs
- pcmk__scan_nvpair
- pcmk__format_nvpair
- pcmk__format_named_time
- crm_xml_add
- crm_xml_replace
- crm_xml_add_int
- crm_xml_add_ms
- crm_xml_add_ll
- crm_xml_add_timeval
- crm_element_value
- crm_element_value_int
- crm_element_value_ll
- crm_element_value_ms
- crm_element_value_epoch
- crm_element_value_timeval
- crm_element_value_copy
- hash2smartfield
- hash2field
- hash2metafield
- crm_create_nvpair_xml
- hash2nvpair
- xml2list
- pcmk__xe_set_bool_attr
- pcmk__xe_get_bool_attr
- pcmk__xe_attr_is_true
- pcmk_scan_nvpair
- pcmk_format_nvpair
- pcmk_format_named_time
1
2
3
4
5
6
7
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>
22 #include <crm/common/xml_internal.h>
23 #include "crmcommon_private.h"
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 static pcmk_nvpair_t *
47 pcmk__new_nvpair(const char *name, const char *value)
48 {
49 pcmk_nvpair_t *nvpair = NULL;
50
51 CRM_ASSERT(name);
52
53 nvpair = calloc(1, sizeof(pcmk_nvpair_t));
54 CRM_ASSERT(nvpair);
55
56 pcmk__str_update(&nvpair->name, name);
57 pcmk__str_update(&nvpair->value, value);
58 return nvpair;
59 }
60
61
62
63
64
65
66
67 static void
68 pcmk__free_nvpair(gpointer data)
69 {
70 if (data) {
71 pcmk_nvpair_t *nvpair = data;
72
73 free(nvpair->name);
74 free(nvpair->value);
75 free(nvpair);
76 }
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90 GSList *
91 pcmk_prepend_nvpair(GSList *nvpairs, const char *name, const char *value)
92 {
93 return g_slist_prepend(nvpairs, pcmk__new_nvpair(name, value));
94 }
95
96
97
98
99
100
101 void
102 pcmk_free_nvpairs(GSList *nvpairs)
103 {
104 g_slist_free_full(nvpairs, pcmk__free_nvpair);
105 }
106
107
108
109
110
111
112
113
114
115
116 static gint
117 pcmk__compare_nvpair(gconstpointer a, gconstpointer b)
118 {
119 int rc = 0;
120 const pcmk_nvpair_t *pair_a = a;
121 const pcmk_nvpair_t *pair_b = b;
122
123 CRM_ASSERT(a != NULL);
124 CRM_ASSERT(pair_a->name != NULL);
125
126 CRM_ASSERT(b != NULL);
127 CRM_ASSERT(pair_b->name != NULL);
128
129 rc = strcmp(pair_a->name, pair_b->name);
130 if (rc < 0) {
131 return -1;
132 } else if (rc > 0) {
133 return 1;
134 }
135 return 0;
136 }
137
138
139
140
141
142
143
144
145 GSList *
146 pcmk_sort_nvpairs(GSList *list)
147 {
148 return g_slist_sort(list, pcmk__compare_nvpair);
149 }
150
151
152
153
154
155
156
157
158
159
160 GSList *
161 pcmk_xml_attrs2nvpairs(const xmlNode *xml)
162 {
163 GSList *result = NULL;
164
165 for (xmlAttrPtr iter = pcmk__xe_first_attr(xml); iter != NULL;
166 iter = iter->next) {
167
168 result = pcmk_prepend_nvpair(result,
169 (const char *) iter->name,
170 (const char *) pcmk__xml_attr_value(iter));
171 }
172 return result;
173 }
174
175
176
177
178
179
180
181
182
183
184
185 static void
186 pcmk__nvpair_add_xml_attr(gpointer data, gpointer user_data)
187 {
188 pcmk_nvpair_t *pair = data;
189 xmlNode *parent = user_data;
190
191 crm_xml_add(parent, pair->name, pair->value);
192 }
193
194
195
196
197
198
199
200 void
201 pcmk_nvpairs2xml_attrs(GSList *list, xmlNode *xml)
202 {
203 g_slist_foreach(list, pcmk__nvpair_add_xml_attr, xml);
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 int
221 pcmk__scan_nvpair(const char *input, char **name, char **value)
222 {
223 #ifdef HAVE_SSCANF_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
246
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 char *
284 pcmk__format_nvpair(const char *name, const char *value, const char *units)
285 {
286 return crm_strdup_printf("%s=\"%s%s\"", name, value, units ? units : "");
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 char *
303 pcmk__format_named_time(const char *name, time_t epoch_time)
304 {
305 const char *now_str = pcmk__epoch2str(&epoch_time);
306
307 return crm_strdup_printf("%s=\"%s\"", name, now_str ? now_str : "");
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322 const char *
323 crm_xml_add(xmlNode *node, const char *name, const char *value)
324 {
325 bool dirty = FALSE;
326 xmlAttr *attr = NULL;
327
328 CRM_CHECK(node != NULL, return NULL);
329 CRM_CHECK(name != NULL, return NULL);
330
331 if (value == NULL) {
332 return NULL;
333 }
334
335 if (pcmk__tracking_xml_changes(node, FALSE)) {
336 const char *old = crm_element_value(node, name);
337
338 if (old == NULL || value == NULL || strcmp(old, value) != 0) {
339 dirty = TRUE;
340 }
341 }
342
343 if (dirty && (pcmk__check_acl(node, name, pcmk__xf_acl_create) == FALSE)) {
344 crm_trace("Cannot add %s=%s to %s", name, value, node->name);
345 return NULL;
346 }
347
348 attr = xmlSetProp(node, (pcmkXmlStr) name, (pcmkXmlStr) value);
349 if (dirty) {
350 pcmk__mark_xml_attr_dirty(attr);
351 }
352
353 CRM_CHECK(attr && attr->children && attr->children->content, return NULL);
354 return (char *)attr->children->content;
355 }
356
357
358
359
360
361
362
363
364
365
366
367 const char *
368 crm_xml_replace(xmlNode *node, const char *name, const char *value)
369 {
370 bool dirty = FALSE;
371 xmlAttr *attr = NULL;
372 const char *old_value = NULL;
373
374 CRM_CHECK(node != NULL, return NULL);
375 CRM_CHECK(name != NULL && name[0] != 0, return NULL);
376
377 old_value = crm_element_value(node, name);
378
379
380 CRM_CHECK(old_value != value, return value);
381
382 if (pcmk__check_acl(node, name, pcmk__xf_acl_write) == FALSE) {
383
384 crm_trace("Cannot replace %s=%s to %s", name, value, node->name);
385 return NULL;
386
387 } else if (old_value && !value) {
388 xml_remove_prop(node, name);
389 return NULL;
390 }
391
392 if (pcmk__tracking_xml_changes(node, FALSE)) {
393 if (!old_value || !value || !strcmp(old_value, value)) {
394 dirty = TRUE;
395 }
396 }
397
398 attr = xmlSetProp(node, (pcmkXmlStr) name, (pcmkXmlStr) value);
399 if (dirty) {
400 pcmk__mark_xml_attr_dirty(attr);
401 }
402 CRM_CHECK(attr && attr->children && attr->children->content, return NULL);
403 return (char *) attr->children->content;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418 const char *
419 crm_xml_add_int(xmlNode *node, const char *name, int value)
420 {
421 char *number = pcmk__itoa(value);
422 const char *added = crm_xml_add(node, name, number);
423
424 free(number);
425 return added;
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440 const char *
441 crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
442 {
443 char *number = crm_strdup_printf("%u", ms);
444 const char *added = crm_xml_add(node, name, number);
445
446 free(number);
447 return added;
448 }
449
450
451
452 #define LLSTRSIZE 21
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468 const char *
469 crm_xml_add_ll(xmlNode *xml, const char *name, long long value)
470 {
471 char s[LLSTRSIZE] = { '\0', };
472
473 if (snprintf(s, LLSTRSIZE, "%lld", (long long) value) == LLSTRSIZE) {
474 return NULL;
475 }
476 return crm_xml_add(xml, name, s);
477 }
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492 const char *
493 crm_xml_add_timeval(xmlNode *xml, const char *name_sec, const char *name_usec,
494 const struct timeval *value)
495 {
496 const char *added = NULL;
497
498 if (xml && name_sec && value) {
499 added = crm_xml_add_ll(xml, name_sec, (long long) value->tv_sec);
500 if (added && name_usec) {
501
502 crm_xml_add_ll(xml, name_usec, (long long) value->tv_usec);
503 }
504 }
505 return added;
506 }
507
508
509
510
511
512
513
514
515
516 const char *
517 crm_element_value(const xmlNode *data, const char *name)
518 {
519 xmlAttr *attr = NULL;
520
521 if (data == NULL) {
522 crm_err("Couldn't find %s in NULL", name ? name : "<null>");
523 CRM_LOG_ASSERT(data != NULL);
524 return NULL;
525
526 } else if (name == NULL) {
527 crm_err("Couldn't find NULL in %s", crm_element_name(data));
528 return NULL;
529 }
530
531
532
533
534 attr = xmlHasProp((xmlNode *) data, (pcmkXmlStr) name);
535 if (!attr || !attr->children) {
536 return NULL;
537 }
538 return (const char *) attr->children->content;
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552 int
553 crm_element_value_int(const xmlNode *data, const char *name, int *dest)
554 {
555 const char *value = NULL;
556
557 CRM_CHECK(dest != NULL, return -1);
558 value = crm_element_value(data, name);
559 if (value) {
560 long long value_ll;
561
562 if ((pcmk__scan_ll(value, &value_ll, 0LL) != pcmk_rc_ok)
563 || (value_ll < INT_MIN) || (value_ll > INT_MAX)) {
564 *dest = PCMK__PARSE_INT_DEFAULT;
565 } else {
566 *dest = (int) value_ll;
567 return 0;
568 }
569 }
570 return -1;
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584 int
585 crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
586 {
587 const char *value = NULL;
588
589 CRM_CHECK(dest != NULL, return -1);
590 value = crm_element_value(data, name);
591 if ((value != NULL)
592 && (pcmk__scan_ll(value, dest, PCMK__PARSE_INT_DEFAULT) == pcmk_rc_ok)) {
593 return 0;
594 }
595 return -1;
596 }
597
598
599
600
601
602
603
604
605
606
607
608
609 int
610 crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
611 {
612 const char *value = NULL;
613 long long value_ll;
614
615 CRM_CHECK(dest != NULL, return -1);
616 *dest = 0;
617 value = crm_element_value(data, name);
618 if ((pcmk__scan_ll(value, &value_ll, 0LL) != pcmk_rc_ok)
619 || (value_ll < 0) || (value_ll > G_MAXUINT)) {
620 return -1;
621 }
622 *dest = (guint) value_ll;
623 return pcmk_ok;
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637 int
638 crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
639 {
640 long long value_ll = 0;
641
642 if (crm_element_value_ll(xml, name, &value_ll) < 0) {
643 return -1;
644 }
645
646
647
648
649 *dest = (time_t) value_ll;
650 return pcmk_ok;
651 }
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666 int
667 crm_element_value_timeval(const xmlNode *xml, const char *name_sec,
668 const char *name_usec, struct timeval *dest)
669 {
670 long long value_i = 0;
671
672 CRM_CHECK(dest != NULL, return -EINVAL);
673 dest->tv_sec = 0;
674 dest->tv_usec = 0;
675
676 if (xml == NULL) {
677 return pcmk_ok;
678 }
679
680
681
682
683
684
685
686
687 errno = 0;
688 if (crm_element_value_ll(xml, name_sec, &value_i) < 0) {
689 return -errno;
690 }
691 dest->tv_sec = (time_t) value_i;
692
693
694 if (crm_element_value_ll(xml, name_usec, &value_i) < 0) {
695 return -errno;
696 }
697 dest->tv_usec = (suseconds_t) value_i;
698
699 return pcmk_ok;
700 }
701
702
703
704
705
706
707
708
709
710
711
712
713 char *
714 crm_element_value_copy(const xmlNode *data, const char *name)
715 {
716 char *value_copy = NULL;
717
718 pcmk__str_update(&value_copy, crm_element_value(data, name));
719 return value_copy;
720 }
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735 void
736 hash2smartfield(gpointer key, gpointer value, gpointer user_data)
737 {
738 const char *name = key;
739 const char *s_value = value;
740
741 xmlNode *xml_node = user_data;
742
743 if (isdigit(name[0])) {
744 xmlNode *tmp = create_xml_node(xml_node, XML_TAG_PARAM);
745
746 crm_xml_add(tmp, XML_NVPAIR_ATTR_NAME, name);
747 crm_xml_add(tmp, XML_NVPAIR_ATTR_VALUE, s_value);
748
749 } else if (crm_element_value(xml_node, name) == NULL) {
750 crm_xml_add(xml_node, name, s_value);
751 crm_trace("dumped: %s=%s", name, s_value);
752
753 } else {
754 crm_trace("duplicate: %s=%s", name, s_value);
755 }
756 }
757
758
759
760
761
762
763
764
765
766
767
768
769 void
770 hash2field(gpointer key, gpointer value, gpointer user_data)
771 {
772 const char *name = key;
773 const char *s_value = value;
774
775 xmlNode *xml_node = user_data;
776
777 if (crm_element_value(xml_node, name) == NULL) {
778 crm_xml_add(xml_node, name, s_value);
779
780 } else {
781 crm_trace("duplicate: %s=%s", name, s_value);
782 }
783 }
784
785
786
787
788
789
790
791
792
793
794
795
796
797 void
798 hash2metafield(gpointer key, gpointer value, gpointer user_data)
799 {
800 char *crm_name = NULL;
801
802 if (key == NULL || value == NULL) {
803 return;
804 }
805
806
807
808
809 for (crm_name = key; *crm_name; ++crm_name) {
810 if ((*crm_name == '#') || (*crm_name == ':')) {
811 return;
812 }
813 }
814
815 crm_name = crm_meta_name(key);
816 hash2field(crm_name, value, user_data);
817 free(crm_name);
818 }
819
820
821
822
823
824
825
826
827
828
829
830
831
832 xmlNode *
833 crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name,
834 const char *value)
835 {
836 xmlNode *nvp;
837
838
839
840
841 CRM_CHECK(id || name, return NULL);
842
843 nvp = create_xml_node(parent, XML_CIB_TAG_NVPAIR);
844 CRM_CHECK(nvp, return NULL);
845
846 if (id) {
847 crm_xml_add(nvp, XML_ATTR_ID, id);
848 } else {
849 const char *parent_id = ID(parent);
850
851 crm_xml_set_id(nvp, "%s-%s",
852 (parent_id? parent_id : XML_CIB_TAG_NVPAIR), name);
853 }
854 crm_xml_add(nvp, XML_NVPAIR_ATTR_NAME, name);
855 crm_xml_add(nvp, XML_NVPAIR_ATTR_VALUE, value);
856 return nvp;
857 }
858
859
860
861
862
863
864
865
866
867
868
869
870 void
871 hash2nvpair(gpointer key, gpointer value, gpointer user_data)
872 {
873 const char *name = key;
874 const char *s_value = value;
875 xmlNode *xml_node = user_data;
876
877 crm_create_nvpair_xml(xml_node, name, name, s_value);
878 crm_trace("dumped: name=%s value=%s", name, s_value);
879 }
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895 GHashTable *
896 xml2list(const xmlNode *parent)
897 {
898 xmlNode *child = NULL;
899 xmlAttrPtr pIter = NULL;
900 xmlNode *nvpair_list = NULL;
901 GHashTable *nvpair_hash = pcmk__strkey_table(free, free);
902
903 CRM_CHECK(parent != NULL, return nvpair_hash);
904
905 nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
906 if (nvpair_list == NULL) {
907 crm_trace("No attributes in %s", crm_element_name(parent));
908 crm_log_xml_trace(parent, "No attributes for resource op");
909 }
910
911 crm_log_xml_trace(nvpair_list, "Unpacking");
912
913 for (pIter = pcmk__xe_first_attr(nvpair_list); pIter != NULL;
914 pIter = pIter->next) {
915
916 const char *p_name = (const char *)pIter->name;
917 const char *p_value = pcmk__xml_attr_value(pIter);
918
919 crm_trace("Added %s=%s", p_name, p_value);
920
921 g_hash_table_insert(nvpair_hash, strdup(p_name), strdup(p_value));
922 }
923
924 for (child = pcmk__xml_first_child(nvpair_list); child != NULL;
925 child = pcmk__xml_next(child)) {
926
927 if (strcmp((const char *)child->name, XML_TAG_PARAM) == 0) {
928 const char *key = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
929 const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
930
931 crm_trace("Added %s=%s", key, value);
932 if (key != NULL && value != NULL) {
933 g_hash_table_insert(nvpair_hash, strdup(key), strdup(value));
934 }
935 }
936 }
937
938 return nvpair_hash;
939 }
940
941 void
942 pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
943 {
944 crm_xml_add(node, name, value ? XML_BOOLEAN_TRUE : XML_BOOLEAN_FALSE);
945 }
946
947 int
948 pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
949 {
950 const char *xml_value = NULL;
951 int ret, rc;
952
953 if (node == NULL) {
954 return ENODATA;
955 } else if (name == NULL || value == NULL) {
956 return EINVAL;
957 }
958
959 xml_value = crm_element_value(node, name);
960
961 if (xml_value == NULL) {
962 return ENODATA;
963 }
964
965 rc = crm_str_to_boolean(xml_value, &ret);
966 if (rc == 1) {
967 *value = ret;
968 return pcmk_rc_ok;
969 } else {
970 return pcmk_rc_unknown_format;
971 }
972 }
973
974 bool
975 pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
976 {
977 bool value = false;
978 int rc;
979
980 rc = pcmk__xe_get_bool_attr(node, name, &value);
981 return rc == pcmk_rc_ok && value == true;
982 }
983
984
985
986
987 #include <crm/common/util_compat.h>
988
989 int
990 pcmk_scan_nvpair(const char *input, char **name, char **value)
991 {
992 return pcmk__scan_nvpair(input, name, value);
993 }
994
995 char *
996 pcmk_format_nvpair(const char *name, const char *value,
997 const char *units)
998 {
999 return pcmk__format_nvpair(name, value, units);
1000 }
1001
1002 char *
1003 pcmk_format_named_time(const char *name, time_t epoch_time)
1004 {
1005 return pcmk__format_named_time(name, epoch_time);
1006 }
1007
1008
1009