pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
output.c
Go to the documentation of this file.
1/*
2 * Copyright 2019-2023 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)
21GHashTable *
22pcmk__output_formatters(void) {
23 return formatters;
24}
25#endif
26
27void
29 if (out == NULL) {
30 return;
31 }
32
33 out->free_priv(out);
34
35 if (out->messages != NULL) {
36 g_hash_table_destroy(out->messages);
37 }
38
39 g_free(out->request);
40 free(out);
41}
42
60int
61pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name,
62 const char *filename, char **argv)
63{
64 pcmk__output_factory_t create = NULL;
65
66 CRM_ASSERT(formatters != NULL && out != NULL);
67
68 /* If no name was given, just try "text". It's up to each tool to register
69 * what it supports so this also may not be valid.
70 */
71 if (fmt_name == NULL) {
72 create = g_hash_table_lookup(formatters, "text");
73 } else {
74 create = g_hash_table_lookup(formatters, fmt_name);
75 }
76
77 if (create == NULL) {
79 }
80
81 *out = create(argv);
82 if (*out == NULL) {
83 return ENOMEM;
84 }
85
86 if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) {
87 (*out)->dest = stdout;
88 } else {
89 (*out)->dest = fopen(filename, "w");
90 if ((*out)->dest == NULL) {
92 *out = NULL;
93 return errno;
94 }
95 }
96
97 (*out)->quiet = false;
98 (*out)->messages = pcmk__strkey_table(free, NULL);
99
100 if ((*out)->init(*out) == false) {
101 pcmk__output_free(*out);
102 return ENOMEM;
103 }
104
105 setenv("OCF_OUTPUT_FORMAT", (*out)->fmt_name, 1);
106
107 return pcmk_rc_ok;
108}
109
110int
111pcmk__output_new(pcmk__output_t **out, const char *fmt_name,
112 const char *filename, char **argv)
113{
114 int rc = pcmk__bare_output_new(out, fmt_name, filename, argv);
115
116 if (rc == pcmk_rc_ok) {
117 /* Register libcrmcommon messages (currently they exist only for
118 * patchset)
119 */
121 }
122 return rc;
123}
124
125int
126pcmk__register_format(GOptionGroup *group, const char *name,
128 const GOptionEntry *options)
129{
130 CRM_ASSERT(create != NULL && !pcmk__str_empty(name));
131
132 if (formatters == NULL) {
133 formatters = pcmk__strkey_table(free, NULL);
134 }
135
136 if (options != NULL && group != NULL) {
137 g_option_group_add_entries(group, options);
138 }
139
140 g_hash_table_insert(formatters, strdup(name), create);
141 return pcmk_rc_ok;
142}
143
144void
145pcmk__register_formats(GOptionGroup *group,
146 const pcmk__supported_format_t *formats)
147{
148 if (formats == NULL) {
149 return;
150 }
151 for (const pcmk__supported_format_t *entry = formats; entry->name != NULL;
152 entry++) {
153 pcmk__register_format(group, entry->name, entry->create, entry->options);
154 }
155}
156
157void
159 if (formatters != NULL) {
160 g_hash_table_destroy(formatters);
161 formatters = NULL;
162 }
163}
164
165int
166pcmk__call_message(pcmk__output_t *out, const char *message_id, ...) {
167 va_list args;
168 int rc = pcmk_rc_ok;
170
171 CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id));
172
173 fn = g_hash_table_lookup(out->messages, message_id);
174 if (fn == NULL) {
175 crm_debug("Called unknown output message '%s' for format '%s'",
176 message_id, out->fmt_name);
177 return EINVAL;
178 }
179
180 va_start(args, message_id);
181 rc = fn(out, args);
182 va_end(args);
183
184 return rc;
185}
186
187void
188pcmk__register_message(pcmk__output_t *out, const char *message_id,
190 CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id) && fn != NULL);
191
192 g_hash_table_replace(out->messages, strdup(message_id), fn);
193}
194
195void
197{
198 for (const pcmk__message_entry_t *entry = table; entry->message_id != NULL;
199 entry++) {
200 if (pcmk__strcase_any_of(entry->fmt_name, "default", out->fmt_name, NULL)) {
201 pcmk__register_message(out, entry->message_id, entry->fn);
202 }
203 }
204}
205
206void
208{
209 if (error == NULL || *error == NULL) {
210 return;
211 }
212
213 if (out != NULL) {
214 out->err(out, "%s: %s", g_get_prgname(), (*error)->message);
215 } else {
216 fprintf(stderr, "%s: %s\n", g_get_prgname(), (*error)->message);
217 }
218
219 g_clear_error(error);
220}
221
235int
236pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml) {
237 pcmk__supported_format_t xml_format[] = {
239 { NULL, NULL, NULL }
240 };
241
242 if (*xml != NULL) {
243 xmlFreeNode(*xml);
244 *xml = NULL;
245 }
246 pcmk__register_formats(NULL, xml_format);
247 return pcmk__output_new(out, "xml", NULL, NULL);
248}
249
257void
259 out->finish(out, 0, FALSE, (void **) xml);
261}
262
271int
273{
274 int rc = pcmk_rc_ok;
275 const char* argv[] = { "", NULL };
276 pcmk__supported_format_t formats[] = {
278 { NULL, NULL, NULL }
279 };
280
281 pcmk__register_formats(NULL, formats);
282 rc = pcmk__output_new(out, "log", NULL, (char **) argv);
283 if ((rc != pcmk_rc_ok) || (*out == NULL)) {
284 crm_err("Can't log certain messages due to internal error: %s",
285 pcmk_rc_str(rc));
286 return rc;
287 }
288 return pcmk_rc_ok;
289}
290
300int
301pcmk__text_output_new(pcmk__output_t **out, const char *filename)
302{
303 int rc = pcmk_rc_ok;
304 const char* argv[] = { "", NULL };
305 pcmk__supported_format_t formats[] = {
307 { NULL, NULL, NULL }
308 };
309
310 pcmk__register_formats(NULL, formats);
311 rc = pcmk__output_new(out, "text", filename, (char **) argv);
312 if ((rc != pcmk_rc_ok) || (*out == NULL)) {
313 crm_err("Can't create text output object to internal error: %s",
314 pcmk_rc_str(rc));
315 return rc;
316 }
317 return pcmk_rc_ok;
318}
const char * name
Definition cib.c:24
Utility functions.
G_GNUC_INTERNAL void pcmk__register_patchset_messages(pcmk__output_t *out)
#define crm_debug(fmt, args...)
Definition logging.h:380
#define crm_err(fmt, args...)
Definition logging.h:375
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition output.c:196
int pcmk__register_format(GOptionGroup *group, const char *name, pcmk__output_factory_t create, const GOptionEntry *options)
Definition output.c:126
void pcmk__output_free(pcmk__output_t *out)
Definition output.c:28
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:236
void pcmk__register_formats(GOptionGroup *group, const pcmk__supported_format_t *formats)
Definition output.c:145
int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv)
Definition output.c:111
int pcmk__call_message(pcmk__output_t *out, const char *message_id,...)
Definition output.c:166
void pcmk__output_and_clear_error(GError **error, pcmk__output_t *out)
Definition output.c:207
void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition output.c:188
int pcmk__log_output_new(pcmk__output_t **out)
Definition output.c:272
int pcmk__text_output_new(pcmk__output_t **out, const char *filename)
Definition output.c:301
void pcmk__xml_output_finish(pcmk__output_t *out, xmlNodePtr *xml)
Definition output.c:258
int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv)
Definition output.c:61
void pcmk__unregister_formats(void)
Definition output.c:158
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)
int setenv(const char *name, const char *value, int why)
#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:488
@ pcmk_rc_ok
Definition results.h:151
@ pcmk_rc_unknown_format
Definition results.h:145
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:611
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ pcmk__str_null_matches
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.