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