pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
output_xml.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13 
14 #include <ctype.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <crm/crm.h>
19 #include <crm/common/output.h>
20 #include <crm/common/xml.h>
21 
22 typedef struct xml_private_s {
23  xmlNode *root;
24  GQueue *parent_q;
26 
27 static void
28 xml_free_priv(pcmk__output_t *out) {
29  xml_private_t *priv = out->priv;
30 
31  if (priv == NULL) {
32  return;
33  }
34 
35  xmlFreeNode(priv->root);
36  g_queue_free(priv->parent_q);
37  free(priv);
38 }
39 
40 static bool
41 xml_init(pcmk__output_t *out) {
42  xml_private_t *priv = NULL;
43 
44  /* If xml_init was previously called on this output struct, just return. */
45  if (out->priv != NULL) {
46  return true;
47  } else {
48  out->priv = calloc(1, sizeof(xml_private_t));
49  if (out->priv == NULL) {
50  return false;
51  }
52 
53  priv = out->priv;
54  }
55 
56  priv->root = create_xml_node(NULL, "pacemaker-result");
57  xmlSetProp(priv->root, (pcmkXmlStr) "api-version", (pcmkXmlStr) PCMK__API_VERSION);
58 
59  if (out->request != NULL) {
60  xmlSetProp(priv->root, (pcmkXmlStr) "request", (pcmkXmlStr) out->request);
61  }
62 
63  priv->parent_q = g_queue_new();
64  g_queue_push_tail(priv->parent_q, priv->root);
65 
66  return true;
67 }
68 
69 static void
70 xml_finish(pcmk__output_t *out, crm_exit_t exit_status) {
71  xmlNodePtr node;
72  char *rc_as_str = NULL;
73  char *buf = NULL;
74  xml_private_t *priv = out->priv;
75 
76  /* If root is NULL, xml_init failed and we are being called from pcmk__output_free
77  * in the pcmk__output_new path.
78  */
79  if (priv->root == NULL) {
80  return;
81  }
82 
83  rc_as_str = crm_itoa(exit_status);
84 
85  node = xmlNewTextChild(priv->root, NULL, (pcmkXmlStr) "status",
86  (pcmkXmlStr) crm_exit_str(exit_status));
87  xmlSetProp(node, (pcmkXmlStr) "code", (pcmkXmlStr) rc_as_str);
88 
90  fprintf(out->dest, "%s", buf);
91 
92  free(rc_as_str);
93  free(buf);
94 }
95 
96 static void
97 xml_reset(pcmk__output_t *out) {
98  char *buf = NULL;
99  xml_private_t *priv = out->priv;
100 
101  CRM_ASSERT(priv != NULL);
102 
103  buf = dump_xml_formatted_with_text(priv->root);
104  fprintf(out->dest, "%s", buf);
105 
106  free(buf);
107  xml_free_priv(out);
108  xml_init(out);
109 }
110 
111 static void
112 xml_subprocess_output(pcmk__output_t *out, int exit_status,
113  const char *proc_stdout, const char *proc_stderr) {
114  xmlNodePtr node, child_node;
115  char *rc_as_str = NULL;
116  xml_private_t *priv = out->priv;
117  CRM_ASSERT(priv != NULL);
118 
119  rc_as_str = crm_itoa(exit_status);
120 
121  node = xmlNewNode(g_queue_peek_tail(priv->parent_q), (pcmkXmlStr) "command");
122  xmlSetProp(node, (pcmkXmlStr) "code", (pcmkXmlStr) rc_as_str);
123 
124  if (proc_stdout != NULL) {
125  child_node = xmlNewTextChild(node, NULL, (pcmkXmlStr) "output",
126  (pcmkXmlStr) proc_stdout);
127  xmlSetProp(child_node, (pcmkXmlStr) "source", (pcmkXmlStr) "stdout");
128  }
129 
130  if (proc_stderr != NULL) {
131  child_node = xmlNewTextChild(node, NULL, (pcmkXmlStr) "output",
132  (pcmkXmlStr) proc_stderr);
133  xmlSetProp(node, (pcmkXmlStr) "source", (pcmkXmlStr) "stderr");
134  }
135 
136  pcmk__xml_add_node(out, node);
137  free(rc_as_str);
138 }
139 
140 G_GNUC_PRINTF(2, 3)
141 static void
142 xml_info(pcmk__output_t *out, const char *format, ...) {
143  /* This function intentially left blank */
144 }
145 
146 static void
147 xml_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
148  xmlNodePtr parent = NULL;
149  xmlNodePtr cdata_node = NULL;
150  xml_private_t *priv = out->priv;
151 
152  CRM_ASSERT(priv != NULL);
153 
154  parent = xmlNewChild(g_queue_peek_tail(priv->parent_q), NULL,
155  (pcmkXmlStr) name, NULL);
156  cdata_node = xmlNewCDataBlock(getDocPtr(parent), (pcmkXmlStr) buf, strlen(buf));
157  xmlAddChild(parent, cdata_node);
158 }
159 
160 static void
161 xml_begin_list(pcmk__output_t *out, const char *name,
162  const char *singular_noun, const char *plural_noun) {
163  xmlNodePtr list_node = NULL;
164  xml_private_t *priv = out->priv;
165 
166  CRM_ASSERT(priv != NULL);
167 
168  list_node = create_xml_node(g_queue_peek_tail(priv->parent_q), "list");
169  xmlSetProp(list_node, (pcmkXmlStr) "name", (pcmkXmlStr) name);
170  g_queue_push_tail(priv->parent_q, list_node);
171 }
172 
173 static void
174 xml_list_item(pcmk__output_t *out, const char *name, const char *content) {
175  xml_private_t *priv = out->priv;
176  xmlNodePtr item_node = NULL;
177 
178  CRM_ASSERT(priv != NULL);
179 
180  item_node = xmlNewChild(g_queue_peek_tail(priv->parent_q), NULL,
181  (pcmkXmlStr) "item", (pcmkXmlStr) content);
182  xmlSetProp(item_node, (pcmkXmlStr) "name", (pcmkXmlStr) name);
183 }
184 
185 static void
186 xml_end_list(pcmk__output_t *out) {
187  char *buf = NULL;
188  xml_private_t *priv = out->priv;
189  xmlNodePtr node;
190 
191  CRM_ASSERT(priv != NULL);
192 
193  node = g_queue_pop_tail(priv->parent_q);
194  buf = crm_strdup_printf("%lu", xmlChildElementCount(node));
195  xmlSetProp(node, (pcmkXmlStr) "count", (pcmkXmlStr) buf);
196  free(buf);
197 }
198 
200 pcmk__mk_xml_output(char **argv) {
201  pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
202 
203  if (retval == NULL) {
204  return NULL;
205  }
206 
207  retval->request = g_strjoinv(" ", argv);
208  retval->supports_quiet = false;
209 
210  retval->init = xml_init;
211  retval->free_priv = xml_free_priv;
212  retval->finish = xml_finish;
213  retval->reset = xml_reset;
214 
216  retval->message = pcmk__call_message;
217 
218  retval->subprocess_output = xml_subprocess_output;
219  retval->info = xml_info;
220  retval->output_xml = xml_output_xml;
221 
222  retval->begin_list = xml_begin_list;
223  retval->list_item = xml_list_item;
224  retval->end_list = xml_end_list;
225 
226  return retval;
227 }
228 
229 void
230 pcmk__xml_add_node(pcmk__output_t *out, xmlNodePtr node) {
231  xml_private_t *priv = out->priv;
232 
233  CRM_ASSERT(priv != NULL);
234  CRM_ASSERT(node != NULL);
235 
236  xmlAddChild(g_queue_peek_tail(priv->parent_q), node);
237 }
238 
239 void
240 pcmk__xml_push_parent(pcmk__output_t *out, xmlNodePtr parent) {
241  xml_private_t *priv = out->priv;
242 
243  CRM_ASSERT(priv != NULL);
244  CRM_ASSERT(parent != NULL);
245 
246  g_queue_push_tail(priv->parent_q, parent);
247 }
248 
249 void
251  xml_private_t *priv = out->priv;
252 
253  CRM_ASSERT(priv != NULL);
254  CRM_ASSERT(g_queue_get_length(priv->parent_q) > 0);
255 
256  g_queue_pop_tail(priv->parent_q);
257 }
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status)
Definition: output.h:214
bool(* init)(pcmk__output_t *out)
Definition: output.h:186
A dumping ground.
void void pcmk__xml_add_node(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:230
pcmk__output_t * pcmk__mk_xml_output(char **argv)
Definition: output_xml.c:200
Formatted output for pacemaker tools.
void(*) void(* output_xml)(pcmk__output_t *out, const char *name, const char *buf)
Definition: output.h:298
void pcmk__xml_push_parent(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:240
void(* register_message)(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition: output.h:244
void(* reset)(pcmk__output_t *out)
Definition: output.h:231
bool supports_quiet
Does this formatter support a special quiet mode?
Definition: output.h:145
GQueue * parent_q
Definition: output_xml.c:24
int(* message)(pcmk__output_t *out, const char *message_id,...)
Definition: output.h:262
void pcmk__xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:250
enum crm_exit_e crm_exit_t
xmlDoc * getDocPtr(xmlNode *node)
Definition: xml.c:1852
void(* list_item)(pcmk__output_t *out, const char *name, const char *content)
Definition: output.h:329
void * priv
Implementation-specific private data.
Definition: output.h:170
int pcmk__call_message(pcmk__output_t *out, const char *message_id,...)
Definition: output.c:117
char * request
A copy of the request that generated this output.
Definition: output.h:136
void(* end_list)(pcmk__output_t *out)
Definition: output.h:341
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:306
void(* begin_list)(pcmk__output_t *out, const char *name, const char *singular_noun, const char *plural_noun)
Definition: output.h:318
xmlNode * root
Definition: output_xml.c:23
void(* subprocess_output)(pcmk__output_t *out, int exit_status, const char *proc_stdout, const char *proc_stderr)
Definition: output.h:273
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1890
FILE * dest
Where output should be written.
Definition: output.h:153
const xmlChar * pcmkXmlStr
Definition: xml.h:51
void(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
Definition: output.h:288
#define CRM_ASSERT(expr)
Definition: results.h:42
void(* free_priv)(pcmk__output_t *out)
Definition: output.h:197
This structure contains everything that makes up a single output formatter.
Definition: output.h:124
struct xml_private_s xml_private_t
void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition: output.c:135
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
char * dump_xml_formatted_with_text(xmlNode *msg)
Definition: xml.c:3176
#define PCMK__API_VERSION
Definition: output.h:29