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