This source file includes following definitions.
- pcmk__log_xmllib_err
- show_xml_comment
- show_xml_element
- show_xml_node
- pcmk__xml_show
- show_xml_changes_recursive
- pcmk__xml_show_changes
- log_data_element
- xml_log_changes
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <libxml/tree.h>
13
14 #include <crm/crm.h>
15 #include <crm/common/xml.h>
16 #include <crm/common/xml_internal.h>
17 #include "crmcommon_private.h"
18
19 static int show_xml_node(pcmk__output_t *out, GString *buffer,
20 const char *prefix, const xmlNode *data, int depth,
21 uint32_t options);
22
23
24 void
25 pcmk__log_xmllib_err(void *ctx, const char *fmt, ...)
26 {
27 va_list ap;
28
29 va_start(ap, fmt);
30 pcmk__if_tracing(
31 {
32 PCMK__XML_LOG_BASE(LOG_ERR, TRUE,
33 crm_abort(__FILE__, __PRETTY_FUNCTION__,
34 __LINE__, "xml library error", TRUE,
35 TRUE),
36 "XML Error: ", fmt, ap);
37 },
38 {
39 PCMK__XML_LOG_BASE(LOG_ERR, TRUE, 0, "XML Error: ", fmt, ap);
40 }
41 );
42 va_end(ap);
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 static int
59 show_xml_comment(pcmk__output_t *out, const xmlNode *data, int depth,
60 uint32_t options)
61 {
62 if (pcmk_is_set(options, pcmk__xml_fmt_open)) {
63 int width = pcmk_is_set(options, pcmk__xml_fmt_pretty)? (2 * depth) : 0;
64
65 return out->info(out, "%*s<!--%s-->",
66 width, "", (const char *) data->content);
67 }
68 return pcmk_rc_no_output;
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 static int
91 show_xml_element(pcmk__output_t *out, GString *buffer, const char *prefix,
92 const xmlNode *data, int depth, uint32_t options)
93 {
94 int spaces = pcmk_is_set(options, pcmk__xml_fmt_pretty)? (2 * depth) : 0;
95 int rc = pcmk_rc_no_output;
96
97 if (pcmk_is_set(options, pcmk__xml_fmt_open)) {
98 const char *hidden = crm_element_value(data, PCMK__XA_HIDDEN);
99
100 g_string_truncate(buffer, 0);
101
102 for (int lpc = 0; lpc < spaces; lpc++) {
103 g_string_append_c(buffer, ' ');
104 }
105 pcmk__g_strcat(buffer, "<", data->name, NULL);
106
107 for (const xmlAttr *attr = pcmk__xe_first_attr(data); attr != NULL;
108 attr = attr->next) {
109 xml_node_private_t *nodepriv = attr->_private;
110 const char *p_name = (const char *) attr->name;
111 const char *p_value = pcmk__xml_attr_value(attr);
112 gchar *p_copy = NULL;
113
114 if (pcmk_is_set(nodepriv->flags, pcmk__xf_deleted)) {
115 continue;
116 }
117
118
119 if (pcmk_any_flags_set(options,
120 pcmk__xml_fmt_diff_plus
121 |pcmk__xml_fmt_diff_minus)
122 && (strcmp(PCMK__XA_CRM_DIFF_MARKER, p_name) == 0)) {
123 continue;
124 }
125
126 if ((hidden != NULL) && (p_name[0] != '\0')
127 && (strstr(hidden, p_name) != NULL)) {
128
129 p_value = "*****";
130
131 } else {
132 p_copy = pcmk__xml_escape(p_value, true);
133 p_value = p_copy;
134 }
135
136 pcmk__g_strcat(buffer, " ", p_name, "=\"",
137 pcmk__s(p_value, "<null>"), "\"", NULL);
138 g_free(p_copy);
139 }
140
141 if ((data->children != NULL)
142 && pcmk_is_set(options, pcmk__xml_fmt_children)) {
143 g_string_append_c(buffer, '>');
144
145 } else {
146 g_string_append(buffer, "/>");
147 }
148
149 rc = out->info(out, "%s%s%s",
150 pcmk__s(prefix, ""), pcmk__str_empty(prefix)? "" : " ",
151 buffer->str);
152 }
153
154 if (data->children == NULL) {
155 return rc;
156 }
157
158 if (pcmk_is_set(options, pcmk__xml_fmt_children)) {
159 for (const xmlNode *child = pcmk__xml_first_child(data); child != NULL;
160 child = pcmk__xml_next(child)) {
161
162 int temp_rc = show_xml_node(out, buffer, prefix, child, depth + 1,
163 options
164 |pcmk__xml_fmt_open
165 |pcmk__xml_fmt_close);
166 rc = pcmk__output_select_rc(rc, temp_rc);
167 }
168 }
169
170 if (pcmk_is_set(options, pcmk__xml_fmt_close)) {
171 int temp_rc = out->info(out, "%s%s%*s</%s>",
172 pcmk__s(prefix, ""),
173 pcmk__str_empty(prefix)? "" : " ",
174 spaces, "", data->name);
175 rc = pcmk__output_select_rc(rc, temp_rc);
176 }
177
178 return rc;
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 static int
201 show_xml_node(pcmk__output_t *out, GString *buffer, const char *prefix,
202 const xmlNode *data, int depth, uint32_t options)
203 {
204 switch (data->type) {
205 case XML_COMMENT_NODE:
206 return show_xml_comment(out, data, depth, options);
207 case XML_ELEMENT_NODE:
208 return show_xml_element(out, buffer, prefix, data, depth, options);
209 default:
210 return pcmk_rc_no_output;
211 }
212 }
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 int
229 pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data,
230 int depth, uint32_t options)
231 {
232 int rc = pcmk_rc_no_output;
233 GString *buffer = NULL;
234
235 pcmk__assert(out != NULL);
236 CRM_CHECK(depth >= 0, depth = 0);
237
238 if (data == NULL) {
239 return rc;
240 }
241
242
243
244
245 buffer = g_string_sized_new(1024);
246 rc = show_xml_node(out, buffer, prefix, data, depth, options);
247 g_string_free(buffer, TRUE);
248
249 return rc;
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 static int
266 show_xml_changes_recursive(pcmk__output_t *out, const xmlNode *data, int depth,
267 uint32_t options)
268 {
269
270
271
272 xml_node_private_t *nodepriv = (xml_node_private_t *) data->_private;
273 int rc = pcmk_rc_no_output;
274 int temp_rc = pcmk_rc_no_output;
275
276 if (pcmk_all_flags_set(nodepriv->flags, pcmk__xf_dirty|pcmk__xf_created)) {
277
278 return pcmk__xml_show(out, PCMK__XML_PREFIX_CREATED, data, depth,
279 options
280 |pcmk__xml_fmt_open
281 |pcmk__xml_fmt_children
282 |pcmk__xml_fmt_close);
283 }
284
285 if (pcmk_is_set(nodepriv->flags, pcmk__xf_dirty)) {
286
287 bool pretty = pcmk_is_set(options, pcmk__xml_fmt_pretty);
288 int spaces = pretty? (2 * depth) : 0;
289 const char *prefix = PCMK__XML_PREFIX_MODIFIED;
290
291 if (pcmk_is_set(nodepriv->flags, pcmk__xf_moved)) {
292 prefix = PCMK__XML_PREFIX_MOVED;
293 }
294
295
296 rc = pcmk__xml_show(out, prefix, data, depth,
297 options|pcmk__xml_fmt_open);
298
299
300 for (const xmlAttr *attr = pcmk__xe_first_attr(data); attr != NULL;
301 attr = attr->next) {
302 const char *name = (const char *) attr->name;
303
304 nodepriv = attr->_private;
305
306 if (pcmk_is_set(nodepriv->flags, pcmk__xf_deleted)) {
307 const char *value = pcmk__xml_attr_value(attr);
308
309 temp_rc = out->info(out, "%s %*s @%s=%s",
310 PCMK__XML_PREFIX_DELETED, spaces, "", name,
311 value);
312
313 } else if (pcmk_is_set(nodepriv->flags, pcmk__xf_dirty)) {
314 const char *value = pcmk__xml_attr_value(attr);
315
316 if (pcmk_is_set(nodepriv->flags, pcmk__xf_created)) {
317 prefix = PCMK__XML_PREFIX_CREATED;
318
319 } else if (pcmk_is_set(nodepriv->flags, pcmk__xf_modified)) {
320 prefix = PCMK__XML_PREFIX_MODIFIED;
321
322 } else if (pcmk_is_set(nodepriv->flags, pcmk__xf_moved)) {
323 prefix = PCMK__XML_PREFIX_MOVED;
324
325 } else {
326 prefix = PCMK__XML_PREFIX_MODIFIED;
327 }
328
329 temp_rc = out->info(out, "%s %*s @%s=%s",
330 prefix, spaces, "", name, value);
331 }
332 rc = pcmk__output_select_rc(rc, temp_rc);
333 }
334
335
336 for (const xmlNode *child = pcmk__xml_first_child(data); child != NULL;
337 child = pcmk__xml_next(child)) {
338 temp_rc = show_xml_changes_recursive(out, child, depth + 1,
339 options);
340 rc = pcmk__output_select_rc(rc, temp_rc);
341 }
342
343
344 temp_rc = pcmk__xml_show(out, PCMK__XML_PREFIX_MODIFIED, data, depth,
345 options|pcmk__xml_fmt_close);
346 return pcmk__output_select_rc(rc, temp_rc);
347 }
348
349
350 for (const xmlNode *child = pcmk__xml_first_child(data); child != NULL;
351 child = pcmk__xml_next(child)) {
352 temp_rc = show_xml_changes_recursive(out, child, depth + 1, options);
353 rc = pcmk__output_select_rc(rc, temp_rc);
354 }
355 return rc;
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369 int
370 pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
371 {
372 xml_doc_private_t *docpriv = NULL;
373 int rc = pcmk_rc_no_output;
374 int temp_rc = pcmk_rc_no_output;
375
376 pcmk__assert((out != NULL) && (xml != NULL) && (xml->doc != NULL));
377
378 docpriv = xml->doc->_private;
379 if (!pcmk_is_set(docpriv->flags, pcmk__xf_dirty)) {
380 return rc;
381 }
382
383 for (const GList *iter = docpriv->deleted_objs; iter != NULL;
384 iter = iter->next) {
385 const pcmk__deleted_xml_t *deleted_obj = iter->data;
386
387 if (deleted_obj->position >= 0) {
388 temp_rc = out->info(out, PCMK__XML_PREFIX_DELETED " %s (%d)",
389 deleted_obj->path, deleted_obj->position);
390 } else {
391 temp_rc = out->info(out, PCMK__XML_PREFIX_DELETED " %s",
392 deleted_obj->path);
393 }
394 rc = pcmk__output_select_rc(rc, temp_rc);
395 }
396
397 temp_rc = show_xml_changes_recursive(out, xml, 0, pcmk__xml_fmt_pretty);
398 return pcmk__output_select_rc(rc, temp_rc);
399 }
400
401
402
403
404 #include <crm/common/logging_compat.h>
405 #include <crm/common/xml_compat.h>
406
407 void
408 log_data_element(int log_level, const char *file, const char *function,
409 int line, const char *prefix, const xmlNode *data, int depth,
410 int legacy_options)
411 {
412 uint32_t options = 0;
413 pcmk__output_t *out = NULL;
414
415
416 log_level = pcmk__clip_log_level(log_level);
417
418 if (data == NULL) {
419 do_crm_log(log_level, "%s%sNo data to dump as XML",
420 pcmk__s(prefix, ""), pcmk__str_empty(prefix)? "" : " ");
421 return;
422 }
423
424 switch (log_level) {
425 case LOG_NEVER:
426 return;
427 case LOG_STDOUT:
428 CRM_CHECK(pcmk__text_output_new(&out, NULL) == pcmk_rc_ok, return);
429 break;
430 default:
431 CRM_CHECK(pcmk__log_output_new(&out) == pcmk_rc_ok, return);
432 pcmk__output_set_log_level(out, log_level);
433 break;
434 }
435
436
437
438
439
440
441
442 if (pcmk_is_set(legacy_options, xml_log_option_filtered)) {
443 options |= pcmk__xml_fmt_filtered;
444 }
445 if (pcmk_is_set(legacy_options, xml_log_option_formatted)) {
446 options |= pcmk__xml_fmt_pretty;
447 }
448 if (pcmk_is_set(legacy_options, xml_log_option_open)) {
449 options |= pcmk__xml_fmt_open;
450 }
451 if (pcmk_is_set(legacy_options, xml_log_option_children)) {
452 options |= pcmk__xml_fmt_children;
453 }
454 if (pcmk_is_set(legacy_options, xml_log_option_close)) {
455 options |= pcmk__xml_fmt_close;
456 }
457 if (pcmk_is_set(legacy_options, xml_log_option_text)) {
458 options |= pcmk__xml_fmt_text;
459 }
460 if (pcmk_is_set(legacy_options, xml_log_option_diff_plus)) {
461 options |= pcmk__xml_fmt_diff_plus;
462 }
463 if (pcmk_is_set(legacy_options, xml_log_option_diff_minus)) {
464 options |= pcmk__xml_fmt_diff_minus;
465 }
466 if (pcmk_is_set(legacy_options, xml_log_option_diff_short)) {
467 options |= pcmk__xml_fmt_diff_short;
468 }
469
470
471 if (pcmk_is_set(legacy_options, xml_log_option_dirty_add)) {
472 CRM_CHECK(depth >= 0, depth = 0);
473 show_xml_changes_recursive(out, data, depth, options);
474 goto done;
475 }
476
477 if (pcmk_is_set(options, pcmk__xml_fmt_pretty)
478 && ((data->children == NULL)
479 || (crm_element_value(data, PCMK__XA_CRM_DIFF_MARKER) != NULL))) {
480
481 if (pcmk_is_set(options, pcmk__xml_fmt_diff_plus)) {
482 legacy_options |= xml_log_option_diff_all;
483 prefix = PCMK__XML_PREFIX_CREATED;
484
485 } else if (pcmk_is_set(options, pcmk__xml_fmt_diff_minus)) {
486 legacy_options |= xml_log_option_diff_all;
487 prefix = PCMK__XML_PREFIX_DELETED;
488 }
489 }
490
491 if (pcmk_is_set(options, pcmk__xml_fmt_diff_short)
492 && !pcmk_is_set(legacy_options, xml_log_option_diff_all)) {
493
494 if (!pcmk_any_flags_set(options,
495 pcmk__xml_fmt_diff_plus
496 |pcmk__xml_fmt_diff_minus)) {
497
498 goto done;
499 }
500
501
502 for (const xmlNode *child = pcmk__xml_first_child(data); child != NULL;
503 child = pcmk__xml_next(child)) {
504 log_data_element(log_level, file, function, line, prefix, child,
505 depth + 1, options);
506 }
507
508 } else {
509 pcmk__xml_show(out, prefix, data, depth,
510 options
511 |pcmk__xml_fmt_open
512 |pcmk__xml_fmt_children
513 |pcmk__xml_fmt_close);
514 }
515
516 done:
517 out->finish(out, CRM_EX_OK, true, NULL);
518 pcmk__output_free(out);
519 }
520
521 void
522 xml_log_changes(uint8_t log_level, const char *function, const xmlNode *xml)
523 {
524 pcmk__output_t *out = NULL;
525 int rc = pcmk_rc_ok;
526
527 switch (log_level) {
528 case LOG_NEVER:
529 return;
530 case LOG_STDOUT:
531 CRM_CHECK(pcmk__text_output_new(&out, NULL) == pcmk_rc_ok, return);
532 break;
533 default:
534 CRM_CHECK(pcmk__log_output_new(&out) == pcmk_rc_ok, return);
535 pcmk__output_set_log_level(out, log_level);
536 break;
537 }
538 rc = pcmk__xml_show_changes(out, xml);
539 out->finish(out, pcmk_rc2exitc(rc), true, NULL);
540 pcmk__output_free(out);
541 }
542
543
544