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