root/lib/common/output.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcmk__output_formatters
  2. pcmk__output_free
  3. pcmk__output_new
  4. pcmk__register_format
  5. pcmk__register_formats
  6. pcmk__unregister_formats
  7. pcmk__call_message
  8. pcmk__register_message
  9. pcmk__register_messages
  10. pcmk__output_and_clear_error
  11. pcmk__xml_output_new
  12. pcmk__xml_output_finish
  13. pcmk__log_output_new

   1 /*
   2  * Copyright 2019-2022 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 static GHashTable *formatters = NULL;
  17 
  18 #if defined(PCMK__UNIT_TESTING)
  19 GHashTable *
  20 pcmk__output_formatters(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
  21     return formatters;
  22 }
  23 #endif
  24 
  25 void
  26 pcmk__output_free(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
  27     if (out == NULL) {
  28         return;
  29     }
  30 
  31     out->free_priv(out);
  32 
  33     if (out->messages != NULL) {
  34         g_hash_table_destroy(out->messages);
  35     }
  36 
  37     g_free(out->request);
  38     free(out);
  39 }
  40 
  41 int
  42 pcmk__output_new(pcmk__output_t **out, const char *fmt_name, const char *filename,
     /* [previous][next][first][last][top][bottom][index][help] */
  43                  char **argv) {
  44     pcmk__output_factory_t create = NULL;
  45 
  46     CRM_ASSERT(formatters != NULL && out != NULL);
  47 
  48     /* If no name was given, just try "text".  It's up to each tool to register
  49      * what it supports so this also may not be valid.
  50      */
  51     if (fmt_name == NULL) {
  52         create = g_hash_table_lookup(formatters, "text");
  53     } else {
  54         create = g_hash_table_lookup(formatters, fmt_name);
  55     }
  56 
  57     if (create == NULL) {
  58         return pcmk_rc_unknown_format;
  59     }
  60 
  61     *out = create(argv);
  62     if (*out == NULL) {
  63         return ENOMEM;
  64     }
  65 
  66     if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) {
  67         (*out)->dest = stdout;
  68     } else {
  69         (*out)->dest = fopen(filename, "w");
  70         if ((*out)->dest == NULL) {
  71             pcmk__output_free(*out);
  72             *out = NULL;
  73             return errno;
  74         }
  75     }
  76 
  77     (*out)->quiet = false;
  78     (*out)->messages = pcmk__strkey_table(free, NULL);
  79 
  80     if ((*out)->init(*out) == false) {
  81         pcmk__output_free(*out);
  82         return ENOMEM;
  83     }
  84 
  85     setenv("OCF_OUTPUT_FORMAT", (*out)->fmt_name, 1);
  86 
  87     return pcmk_rc_ok;
  88 }
  89 
  90 int
  91 pcmk__register_format(GOptionGroup *group, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
  92                       pcmk__output_factory_t create,
  93                       const GOptionEntry *options)
  94 {
  95     CRM_ASSERT(create != NULL && !pcmk__str_empty(name));
  96 
  97     if (formatters == NULL) {
  98         formatters = pcmk__strkey_table(free, NULL);
  99     }
 100 
 101     if (options != NULL && group != NULL) {
 102         g_option_group_add_entries(group, options);
 103     }
 104 
 105     g_hash_table_insert(formatters, strdup(name), create);
 106     return pcmk_rc_ok;
 107 }
 108 
 109 void
 110 pcmk__register_formats(GOptionGroup *group,
     /* [previous][next][first][last][top][bottom][index][help] */
 111                        const pcmk__supported_format_t *formats)
 112 {
 113     if (formats == NULL) {
 114         return;
 115     }
 116     for (const pcmk__supported_format_t *entry = formats; entry->name != NULL;
 117          entry++) {
 118         pcmk__register_format(group, entry->name, entry->create, entry->options);
 119     }
 120 }
 121 
 122 void
 123 pcmk__unregister_formats() {
     /* [previous][next][first][last][top][bottom][index][help] */
 124     if (formatters != NULL) {
 125         g_hash_table_destroy(formatters);
 126         formatters = NULL;
 127     }
 128 }
 129 
 130 int
 131 pcmk__call_message(pcmk__output_t *out, const char *message_id, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
 132     va_list args;
 133     int rc = pcmk_rc_ok;
 134     pcmk__message_fn_t fn;
 135 
 136     CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id));
 137 
 138     fn = g_hash_table_lookup(out->messages, message_id);
 139     if (fn == NULL) {
 140         crm_debug("Called unknown output message '%s' for format '%s'",
 141                   message_id, out->fmt_name);
 142         return EINVAL;
 143     }
 144 
 145     va_start(args, message_id);
 146     rc = fn(out, args);
 147     va_end(args);
 148 
 149     return rc;
 150 }
 151 
 152 void
 153 pcmk__register_message(pcmk__output_t *out, const char *message_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 154                        pcmk__message_fn_t fn) {
 155     CRM_ASSERT(out != NULL && !pcmk__str_empty(message_id) && fn != NULL);
 156 
 157     g_hash_table_replace(out->messages, strdup(message_id), fn);
 158 }
 159 
 160 void
 161 pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     for (const pcmk__message_entry_t *entry = table; entry->message_id != NULL;
 164          entry++) {
 165         if (pcmk__strcase_any_of(entry->fmt_name, "default", out->fmt_name, NULL)) {
 166             pcmk__register_message(out, entry->message_id, entry->fn);
 167         }
 168     }
 169 }
 170 
 171 void
 172 pcmk__output_and_clear_error(GError *error, pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174     if (error == NULL) {
 175         return;
 176     }
 177 
 178     if (out != NULL) {
 179         out->err(out, "%s: %s", g_get_prgname(), error->message);
 180     } else {
 181         fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message);
 182     }
 183 
 184     g_clear_error(&error);
 185 }
 186 
 187 /*!
 188  * \internal
 189  * \brief Create an XML-only output object
 190  *
 191  * Create an output object that supports only the XML format, and free
 192  * existing XML if supplied (particularly useful for libpacemaker public API
 193  * functions that want to free any previous result supplied by the caller).
 194  *
 195  * \param[out]     out  Where to put newly created output object
 196  * \param[in,out]  xml  If non-NULL, this will be freed
 197  *
 198  * \return Standard Pacemaker return code
 199  */
 200 int
 201 pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml) {
     /* [previous][next][first][last][top][bottom][index][help] */
 202     pcmk__supported_format_t xml_format[] = {
 203         PCMK__SUPPORTED_FORMAT_XML,
 204         { NULL, NULL, NULL }
 205     };
 206 
 207     if (*xml != NULL) {
 208         xmlFreeNode(*xml);
 209         *xml = NULL;
 210     }
 211     pcmk__register_formats(NULL, xml_format);
 212     return pcmk__output_new(out, "xml", NULL, NULL);
 213 }
 214 
 215 /*!
 216  * \internal
 217  * \brief  Finish and free an XML-only output object
 218  *
 219  * \param[in,out] out  Output object to free
 220  * \param[out]    xml  If not NULL, where to store XML output
 221  */
 222 void
 223 pcmk__xml_output_finish(pcmk__output_t *out, xmlNodePtr *xml) {
     /* [previous][next][first][last][top][bottom][index][help] */
 224     out->finish(out, 0, FALSE, (void **) xml);
 225     pcmk__output_free(out);
 226 }
 227 
 228 /*!
 229  * \internal
 230  * \brief Create a new output object using the "log" format
 231  *
 232  * \param[out] out  Where to store newly allocated output object
 233  *
 234  * \return Standard Pacemaker return code
 235  */
 236 int
 237 pcmk__log_output_new(pcmk__output_t **out)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     int rc = pcmk_rc_ok;
 240     const char* argv[] = { "", NULL };
 241     pcmk__supported_format_t formats[] = {
 242         PCMK__SUPPORTED_FORMAT_LOG,
 243         { NULL, NULL, NULL }
 244     };
 245 
 246     pcmk__register_formats(NULL, formats);
 247     rc = pcmk__output_new(out, "log", NULL, (char **) argv);
 248     if ((rc != pcmk_rc_ok) || (*out == NULL)) {
 249         crm_err("Can't log certain messages due to internal error: %s",
 250                 pcmk_rc_str(rc));
 251         return rc;
 252     }
 253     return pcmk_rc_ok;
 254 }

/* [previous][next][first][last][top][bottom][index][help] */