pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
output.c
Go to the documentation of this file.
1/*
2 * Copyright 2019-2024 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#include <crm_internal.h>
11
12#include <crm/common/util.h>
13#include <crm/common/xml.h>
14#include <libxml/tree.h>
15
16#include "crmcommon_private.h"
17
18static GHashTable *formatters = NULL;
19
20#if defined(PCMK__UNIT_TESTING)
21// LCOV_EXCL_START
22GHashTable *
23pcmk__output_formatters(void) {
24 return formatters;
25}
26// LCOV_EXCL_STOP
27#endif
28
29void
31 if (out == NULL) {
32 return;
33 }
34
35 out->free_priv(out);
36
37 if (out->messages != NULL) {
38 g_hash_table_destroy(out->messages);
39 }
40
41 g_free(out->request);
42 free(out);
43}
44
62int
63pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name,
64 const char *filename, char **argv)
65{
66 pcmk__output_factory_t create = NULL;
67
68 CRM_ASSERT(formatters != NULL && out != NULL);
69
70 /* If no name was given, just try "text". It's up to each tool to register
71 * what it supports so this also may not be valid.
72 */
73 if (fmt_name == NULL) {
74 create = g_hash_table_lookup(formatters, "text");
75 } else {
76 create = g_hash_table_lookup(formatters, fmt_name);
77 }
78
79 if (create == NULL) {
81 }
82
83 *out = create(argv);
84 if (*out == NULL) {
85 return ENOMEM;
86 }
87
88 if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) {
89 (*out)->dest = stdout;
90 } else {
91 (*out)->dest = fopen(filename, "w");
92 if ((*out)->dest == NULL) {
94 *out = NULL;
95 return errno;
96 }
97 }
98
99 (*out)->quiet = false;
100 (*out)->messages = pcmk__strkey_table(free, NULL);
101
102 if ((*out)->init(*out) == false) {
103 pcmk__output_free(*out);
104 return ENOMEM;
105 }
106
107 setenv("OCF_OUTPUT_FORMAT", (*out)->fmt_name, 1);
108
109 return pcmk_rc_ok;
110}
111
112int
113pcmk__output_new(pcmk__output_t **out, const char *fmt_name,
114 const char *filename, char **argv)
115{
116 int rc = pcmk__bare_output_new(out, fmt_name, filename, argv);
117
118 if (rc == pcmk_rc_ok) {
119 // Register libcrmcommon messages
122 }
123 return rc;
124}
125
126int
127pcmk__register_format(GOptionGroup *group, const char *name,
129 const GOptionEntry *options)
130{
131 char *name_copy = NULL;
132
133 CRM_ASSERT(create != NULL && !pcmk__str_empty(name));
134
135 name_copy = strdup(name);
136 if (name_copy == NULL) {
137 return ENOMEM;
138 }
139
140 if (formatters == NULL) {
141 formatters = pcmk__strkey_table(free, NULL);
142 }
143
144 if (options != NULL && group != NULL) {
145 g_option_group_add_entries(group, options);
146 }
147
148 g_hash_table_insert(formatters, name_copy, create);
149 return pcmk_rc_ok;
150}
151
152void
153pcmk__register_formats(GOptionGroup *group,
154 const pcmk__supported_format_t *formats)
155{
156 if (formats == NULL) {
157 return;
158 }
159 for (const pcmk__supported_format_t *entry = formats; entry->name != NULL;
160 entry++) {
161 pcmk__register_format(group, entry->name, entry->create, entry->options);
162 }
163}
164
165void
167 if (formatters != NULL) {
168 g_hash_table_destroy(formatters);
169 formatters = NULL;
170 }
171}
172
173int
174pcmk__call_message(pcmk__output_t *out, const char *message_id, ...) {
175 va_list args;
176 int rc = pcmk_rc_ok;
178
179 CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id));
180
181 fn = g_hash_table_lookup(out->messages, message_id);
182 if (fn == NULL) {
183 crm_debug("Called unknown output message '%s' for format '%s'",
184 message_id, out->fmt_name);
185 return EINVAL;
186 }
187
188 va_start(args, message_id);
189 rc = fn(out, args);
190 va_end(args);
191
192 return rc;
193}
194
195void
196pcmk__register_message(pcmk__output_t *out, const char *message_id,
198 CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id) && fn != NULL);
199
200 g_hash_table_replace(out->messages, pcmk__str_copy(message_id), fn);
201}
202
203void
205{
206 for (const pcmk__message_entry_t *entry = table; entry->message_id != NULL;
207 entry++) {
208 if (pcmk__strcase_any_of(entry->fmt_name, "default", out->fmt_name, NULL)) {
209 pcmk__register_message(out, entry->message_id, entry->fn);
210 }
211 }
212}
213
214void
216{
217 if (error == NULL || *error == NULL) {
218 return;
219 }
220
221 if (out != NULL) {
222 out->err(out, "%s: %s", g_get_prgname(), (*error)->message);
223 } else {
224 fprintf(stderr, "%s: %s\n", g_get_prgname(), (*error)->message);
225 }
226
227 g_clear_error(error);
228}
229
243int
244pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml) {
245 pcmk__supported_format_t xml_format[] = {
247 { NULL, NULL, NULL }
248 };
249
250 if (xml == NULL) {
251 return EINVAL;
252 }
253
254 if (*xml != NULL) {
255 xmlFreeNode(*xml);
256 *xml = NULL;
257 }
258 pcmk__register_formats(NULL, xml_format);
259 return pcmk__output_new(out, "xml", NULL, NULL);
260}
261
270void
272 xmlNodePtr *xml)
273{
274 if (out == NULL) {
275 return;
276 }
277
278 out->finish(out, exit_status, FALSE, (void **) xml);
280}
281
290int
292{
293 int rc = pcmk_rc_ok;
294 const char* argv[] = { "", NULL };
295 pcmk__supported_format_t formats[] = {
297 { NULL, NULL, NULL }
298 };
299
300 pcmk__register_formats(NULL, formats);
301 rc = pcmk__output_new(out, "log", NULL, (char **) argv);
302 if ((rc != pcmk_rc_ok) || (*out == NULL)) {
303 crm_err("Can't log certain messages due to internal error: %s",
304 pcmk_rc_str(rc));
305 return rc;
306 }
307 return pcmk_rc_ok;
308}
309
319int
320pcmk__text_output_new(pcmk__output_t **out, const char *filename)
321{
322 int rc = pcmk_rc_ok;
323 const char* argv[] = { "", NULL };
324 pcmk__supported_format_t formats[] = {
326 { NULL, NULL, NULL }
327 };
328
329 pcmk__register_formats(NULL, formats);
330 rc = pcmk__output_new(out, "text", filename, (char **) argv);
331 if ((rc != pcmk_rc_ok) || (*out == NULL)) {
332 crm_err("Can't create text output object to internal error: %s",
333 pcmk_rc_str(rc));
334 return rc;
335 }
336 return pcmk_rc_ok;
337}
const char * name
Definition cib.c:26
Utility functions.
G_GNUC_INTERNAL void pcmk__register_option_messages(pcmk__output_t *out)
G_GNUC_INTERNAL void pcmk__register_patchset_messages(pcmk__output_t *out)
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition output.c:271
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition output.c:204
int pcmk__register_format(GOptionGroup *group, const char *name, pcmk__output_factory_t create, const GOptionEntry *options)
Definition output.c:127
void pcmk__output_free(pcmk__output_t *out)
Definition output.c:30
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:244
void pcmk__register_formats(GOptionGroup *group, const pcmk__supported_format_t *formats)
Definition output.c:153
int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv)
Definition output.c:113
int pcmk__call_message(pcmk__output_t *out, const char *message_id,...)
Definition output.c:174
void pcmk__output_and_clear_error(GError **error, pcmk__output_t *out)
Definition output.c:215
void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition output.c:196
int pcmk__log_output_new(pcmk__output_t **out)
Definition output.c:291
int pcmk__text_output_new(pcmk__output_t **out, const char *filename)
Definition output.c:320
int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv)
Definition output.c:63
void pcmk__unregister_formats(void)
Definition output.c:166
int(* pcmk__message_fn_t)(pcmk__output_t *out, va_list args)
#define PCMK__SUPPORTED_FORMAT_XML
#define PCMK__SUPPORTED_FORMAT_TEXT
#define PCMK__SUPPORTED_FORMAT_LOG
pcmk__output_t *(* pcmk__output_factory_t)(char **argv)
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:501
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_unknown_format
Definition results.h:155
enum crm_exit_e crm_exit_t
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:683
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1026
@ pcmk__str_null_matches
#define pcmk__str_copy(str)
const char * message_id
The message to be handled.
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
GHashTable * messages
Custom messages that are currently registered on this formatter.
const char * fmt_name
The name of this output formatter.
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
bool quiet
Should this formatter supress most output?
void(* free_priv)(pcmk__output_t *out)
gchar * request
A copy of the request that generated this output.
int(*) int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
const char * name
The name of this output formatter, which should match the fmt_name parameter in some pcmk__output_t s...
Wrappers for and extensions to libxml2.