This source file includes following definitions.
- xml_show_patchset_header
- xml_show_patchset_v1_recursive
- xml_show_patchset_v1
- xml_show_patchset_v2
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- pcmk__register_patchset_messages
- xml_log_patchset
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/msg_xml.h>
13
14 #include "crmcommon_private.h"
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 static int
41 xml_show_patchset_header(pcmk__output_t *out, const xmlNode *patchset)
42 {
43 int rc = pcmk_rc_no_output;
44 int add[] = { 0, 0, 0 };
45 int del[] = { 0, 0, 0 };
46
47 xml_patch_versions(patchset, add, del);
48
49 if ((add[0] != del[0]) || (add[1] != del[1]) || (add[2] != del[2])) {
50 const char *fmt = crm_element_value(patchset, PCMK_XA_FORMAT);
51 const char *digest = crm_element_value(patchset, XML_ATTR_DIGEST);
52
53 out->info(out, "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
54 rc = out->info(out, "Diff: +++ %d.%d.%d %s",
55 add[0], add[1], add[2], digest);
56
57 } else if ((add[0] != 0) || (add[1] != 0) || (add[2] != 0)) {
58 rc = out->info(out, "Local-only Change: %d.%d.%d",
59 add[0], add[1], add[2]);
60 }
61
62 return rc;
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 static int
80 xml_show_patchset_v1_recursive(pcmk__output_t *out, const char *prefix,
81 const xmlNode *data, int depth, uint32_t options)
82 {
83 if ((data->children == NULL)
84 || (crm_element_value(data, XML_DIFF_MARKER) != NULL)) {
85
86
87 options &= ~pcmk__xml_fmt_diff_short;
88
89 if (pcmk_is_set(options, pcmk__xml_fmt_diff_plus)) {
90 prefix = PCMK__XML_PREFIX_CREATED;
91 } else {
92 prefix = PCMK__XML_PREFIX_DELETED;
93 }
94 }
95
96 if (pcmk_is_set(options, pcmk__xml_fmt_diff_short)) {
97 int rc = pcmk_rc_no_output;
98
99
100 for (const xmlNode *child = pcmk__xml_first_child(data); child != NULL;
101 child = pcmk__xml_next(child)) {
102 int temp_rc = xml_show_patchset_v1_recursive(out, prefix, child,
103 depth + 1, options);
104 rc = pcmk__output_select_rc(rc, temp_rc);
105 }
106 return rc;
107 }
108
109 return pcmk__xml_show(out, prefix, data, depth,
110 options
111 |pcmk__xml_fmt_open
112 |pcmk__xml_fmt_children
113 |pcmk__xml_fmt_close);
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131 static int
132 xml_show_patchset_v1(pcmk__output_t *out, const xmlNode *patchset,
133 uint32_t options)
134 {
135 const xmlNode *removed = NULL;
136 const xmlNode *added = NULL;
137 const xmlNode *child = NULL;
138 bool is_first = true;
139 int rc = xml_show_patchset_header(out, patchset);
140
141
142
143
144
145
146 removed = find_xml_node(patchset, XML_TAG_DIFF_REMOVED, FALSE);
147 for (child = pcmk__xml_first_child(removed); child != NULL;
148 child = pcmk__xml_next(child)) {
149 int temp_rc = xml_show_patchset_v1_recursive(out, "- ", child, 0,
150 options
151 |pcmk__xml_fmt_diff_minus);
152 rc = pcmk__output_select_rc(rc, temp_rc);
153
154 if (is_first) {
155 is_first = false;
156 } else {
157 rc = pcmk__output_select_rc(rc, out->info(out, " --- "));
158 }
159 }
160
161 is_first = true;
162 added = find_xml_node(patchset, XML_TAG_DIFF_ADDED, FALSE);
163 for (child = pcmk__xml_first_child(added); child != NULL;
164 child = pcmk__xml_next(child)) {
165 int temp_rc = xml_show_patchset_v1_recursive(out, "+ ", child, 0,
166 options
167 |pcmk__xml_fmt_diff_plus);
168 rc = pcmk__output_select_rc(rc, temp_rc);
169
170 if (is_first) {
171 is_first = false;
172 } else {
173 rc = pcmk__output_select_rc(rc, out->info(out, " +++ "));
174 }
175 }
176
177 return rc;
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 static int
195 xml_show_patchset_v2(pcmk__output_t *out, const xmlNode *patchset)
196 {
197 int rc = xml_show_patchset_header(out, patchset);
198 int temp_rc = pcmk_rc_no_output;
199
200 for (const xmlNode *change = pcmk__xml_first_child(patchset);
201 change != NULL; change = pcmk__xml_next(change)) {
202 const char *op = crm_element_value(change, XML_DIFF_OP);
203 const char *xpath = crm_element_value(change, XML_DIFF_PATH);
204
205 if (op == NULL) {
206 continue;
207 }
208
209 if (strcmp(op, "create") == 0) {
210 char *prefix = crm_strdup_printf(PCMK__XML_PREFIX_CREATED " %s: ",
211 xpath);
212
213 temp_rc = pcmk__xml_show(out, prefix, change->children, 0,
214 pcmk__xml_fmt_pretty|pcmk__xml_fmt_open);
215 rc = pcmk__output_select_rc(rc, temp_rc);
216
217
218 for (char *ch = prefix + 2; *ch != '\0'; ch++) {
219 *ch = ' ';
220 }
221
222 temp_rc = pcmk__xml_show(out, prefix, change->children, 0,
223 pcmk__xml_fmt_pretty
224 |pcmk__xml_fmt_children
225 |pcmk__xml_fmt_close);
226 rc = pcmk__output_select_rc(rc, temp_rc);
227 free(prefix);
228
229 } else if (strcmp(op, "move") == 0) {
230 const char *position = crm_element_value(change, XML_DIFF_POSITION);
231
232 temp_rc = out->info(out,
233 PCMK__XML_PREFIX_MOVED " %s moved to offset %s",
234 xpath, position);
235 rc = pcmk__output_select_rc(rc, temp_rc);
236
237 } else if (strcmp(op, "modify") == 0) {
238 xmlNode *clist = first_named_child(change, XML_DIFF_LIST);
239 GString *buffer_set = NULL;
240 GString *buffer_unset = NULL;
241
242 for (const xmlNode *child = pcmk__xml_first_child(clist);
243 child != NULL; child = pcmk__xml_next(child)) {
244 const char *name = crm_element_value(child, "name");
245
246 op = crm_element_value(child, XML_DIFF_OP);
247 if (op == NULL) {
248 continue;
249 }
250
251 if (strcmp(op, "set") == 0) {
252 const char *value = crm_element_value(child, "value");
253
254 pcmk__add_separated_word(&buffer_set, 256, "@", ", ");
255 pcmk__g_strcat(buffer_set, name, "=", value, NULL);
256
257 } else if (strcmp(op, "unset") == 0) {
258 pcmk__add_separated_word(&buffer_unset, 256, "@", ", ");
259 g_string_append(buffer_unset, name);
260 }
261 }
262
263 if (buffer_set != NULL) {
264 temp_rc = out->info(out, "+ %s: %s", xpath, buffer_set->str);
265 rc = pcmk__output_select_rc(rc, temp_rc);
266 g_string_free(buffer_set, TRUE);
267 }
268
269 if (buffer_unset != NULL) {
270 temp_rc = out->info(out, "-- %s: %s",
271 xpath, buffer_unset->str);
272 rc = pcmk__output_select_rc(rc, temp_rc);
273 g_string_free(buffer_unset, TRUE);
274 }
275
276 } else if (strcmp(op, "delete") == 0) {
277 int position = -1;
278
279 crm_element_value_int(change, XML_DIFF_POSITION, &position);
280 if (position >= 0) {
281 temp_rc = out->info(out, "-- %s (%d)", xpath, position);
282 } else {
283 temp_rc = out->info(out, "-- %s", xpath);
284 }
285 rc = pcmk__output_select_rc(rc, temp_rc);
286 }
287 }
288
289 return rc;
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306 PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
307 static int
308 xml_patchset_default(pcmk__output_t *out, va_list args)
309 {
310 const xmlNode *patchset = va_arg(args, const xmlNode *);
311
312 int format = 1;
313
314 if (patchset == NULL) {
315 crm_trace("Empty patch");
316 return pcmk_rc_no_output;
317 }
318
319 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
320 switch (format) {
321 case 1:
322 return xml_show_patchset_v1(out, patchset, pcmk__xml_fmt_pretty);
323 case 2:
324 return xml_show_patchset_v2(out, patchset);
325 default:
326 crm_err("Unknown patch format: %d", format);
327 return pcmk_rc_bad_xml_patch;
328 }
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
346 static int
347 xml_patchset_log(pcmk__output_t *out, va_list args)
348 {
349 static struct qb_log_callsite *patchset_cs = NULL;
350
351 const xmlNode *patchset = va_arg(args, const xmlNode *);
352
353 uint8_t log_level = pcmk__output_get_log_level(out);
354 int format = 1;
355
356 if (log_level == LOG_NEVER) {
357 return pcmk_rc_no_output;
358 }
359
360 if (patchset == NULL) {
361 crm_trace("Empty patch");
362 return pcmk_rc_no_output;
363 }
364
365 if (patchset_cs == NULL) {
366 patchset_cs = qb_log_callsite_get(__func__, __FILE__, "xml-patchset",
367 log_level, __LINE__,
368 crm_trace_nonlog);
369 }
370
371 if (!crm_is_callsite_active(patchset_cs, log_level, crm_trace_nonlog)) {
372
373 return pcmk_rc_no_output;
374 }
375
376 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
377 switch (format) {
378 case 1:
379 if (log_level < LOG_DEBUG) {
380 return xml_show_patchset_v1(out, patchset,
381 pcmk__xml_fmt_pretty
382 |pcmk__xml_fmt_diff_short);
383 }
384 return xml_show_patchset_v1(out, patchset, pcmk__xml_fmt_pretty);
385 case 2:
386 return xml_show_patchset_v2(out, patchset);
387 default:
388 crm_err("Unknown patch format: %d", format);
389 return pcmk_rc_bad_xml_patch;
390 }
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407 PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
408 static int
409 xml_patchset_xml(pcmk__output_t *out, va_list args)
410 {
411 const xmlNode *patchset = va_arg(args, const xmlNode *);
412
413 if (patchset != NULL) {
414 char *buf = dump_xml_formatted_with_text(patchset);
415
416 out->output_xml(out, "xml-patchset", buf);
417 free(buf);
418 return pcmk_rc_ok;
419 }
420 crm_trace("Empty patch");
421 return pcmk_rc_no_output;
422 }
423
424 static pcmk__message_entry_t fmt_functions[] = {
425 { "xml-patchset", "default", xml_patchset_default },
426 { "xml-patchset", "log", xml_patchset_log },
427 { "xml-patchset", "xml", xml_patchset_xml },
428
429 { NULL, NULL, NULL }
430 };
431
432
433
434
435
436
437
438 void
439 pcmk__register_patchset_messages(pcmk__output_t *out) {
440 pcmk__register_messages(out, fmt_functions);
441 }
442
443
444
445
446 #include <crm/common/xml_compat.h>
447
448 void
449 xml_log_patchset(uint8_t log_level, const char *function,
450 const xmlNode *patchset)
451 {
452
453
454
455
456
457
458
459
460 static struct qb_log_callsite *patchset_cs = NULL;
461
462 pcmk__output_t *out = NULL;
463 int format = 1;
464 int rc = pcmk_rc_no_output;
465
466 switch (log_level) {
467 case LOG_NEVER:
468 return;
469 case LOG_STDOUT:
470 CRM_CHECK(pcmk__text_output_new(&out, NULL) == pcmk_rc_ok, return);
471 break;
472 default:
473 if (patchset_cs == NULL) {
474 patchset_cs = qb_log_callsite_get(__func__, __FILE__,
475 "xml-patchset", log_level,
476 __LINE__, crm_trace_nonlog);
477 }
478 if (!crm_is_callsite_active(patchset_cs, log_level,
479 crm_trace_nonlog)) {
480 return;
481 }
482 CRM_CHECK(pcmk__log_output_new(&out) == pcmk_rc_ok, return);
483 pcmk__output_set_log_level(out, log_level);
484 break;
485 }
486
487 if (patchset == NULL) {
488
489 crm_trace("Empty patch");
490 goto done;
491 }
492
493 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
494 switch (format) {
495 case 1:
496 if (log_level < LOG_DEBUG) {
497 rc = xml_show_patchset_v1(out, patchset,
498 pcmk__xml_fmt_pretty
499 |pcmk__xml_fmt_diff_short);
500 } else {
501 rc = xml_show_patchset_v1(out, patchset, pcmk__xml_fmt_pretty);
502 }
503 break;
504 case 2:
505 rc = xml_show_patchset_v2(out, patchset);
506 break;
507 default:
508 crm_err("Unknown patch format: %d", format);
509 rc = pcmk_rc_bad_xml_patch;
510 break;
511 }
512
513 done:
514 out->finish(out, pcmk_rc2exitc(rc), true, NULL);
515 pcmk__output_free(out);
516 }
517
518
519