1 /* 2 * Copyright 2017 Jan Pokorny <jpokorny@redhat.com> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This software is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 #ifndef CRM_COMMON_XML_INTERNAL__H 19 # define CRM_COMMON_XML_INTERNAL__H 20 21 /* 22 * Internal-only wrappers for and extensions to libxml2 (libxslt) 23 */ 24 25 # include <stdlib.h> 26 # include <stdio.h> 27 # include <string.h> 28 29 # include <crm/crm.h> /* transitively imports qblog.h */ 30 31 32 /*! 33 * \brief Base for directing lib{xml2,xslt} log into standard libqb backend 34 * 35 * This macro implements the core of what can be needed for directing 36 * libxml2 or libxslt error messaging into standard, preconfigured 37 * libqb-backed log stream. 38 * 39 * It's a bit unfortunate that libxml2 (and more sparsely, also libxslt) 40 * emits a single message by chunks (location is emitted separatedly from 41 * the message itself), so we have to take the effort to combine these 42 * chunks back to single message. Whether to do this or not is driven 43 * with \p dechunk toggle. 44 * 45 * The form of a macro was chosen for implicit deriving of __FILE__, etc. 46 * and also because static dechunking buffer should be differentiated per 47 * library (here we assume different functions referring to this macro 48 * will not ever be using both at once), preferably also per-library 49 * context of use to avoid clashes altogether. 50 * 51 * Note that we cannot use qb_logt, because callsite data have to be known 52 * at the moment of compilation, which it is not always the case -- xml_log 53 * (and unfortunately there's no clear explanation of the fail to compile). 54 * 55 * Also note that there's no explicit guard against said libraries producing 56 * never-newline-terminated chunks (which would just keep consuming memory), 57 * as it's quite improbable. Termination of the program in between the 58 * same-message chunks will raise a flag with valgrind and the likes, though. 59 * 60 * \param[in] priority Syslog priority for the message to be logged 61 * \param[in] dechunk Whether to dechunk new-line terminated message 62 * \param[in] postemit Code to be executed once message is sent out 63 * \param[in] prefix How to prefix the message or NULL for raw passing 64 * \param[in] fmt Format string as with printf-like functions 65 * \param[in] ap Variable argument list to supplement \p fmt format string 66 */ 67 #define CRM_XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap) \ 68 do { \ 69 if (!(dechunk) && (prefix) == NULL) { /* quick pass */ \ 70 qb_log_from_external_source_va(__FUNCTION__, __FILE__, (fmt), \ 71 (priority), __LINE__, 0, (ap)); \ 72 (void) (postemit); \ 73 } else { \ 74 int CXLB_len = 0; \ 75 char *CXLB_buf = NULL; \ 76 static int CXLB_buffer_len = 0; \ 77 static char *CXLB_buffer = NULL; \ 78 \ 79 CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap)); \ 80 \ 81 if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) { \ 82 if (CXLB_len < 0) { \ 83 CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\ 84 } else if (CXLB_len > 0 /* && (dechunk) */ \ 85 && CXLB_buf[CXLB_len - 1] == '\n') { \ 86 CXLB_buf[CXLB_len - 1] = '\0'; \ 87 } \ 88 if (CXLB_buffer) { \ 89 qb_log_from_external_source(__FUNCTION__, __FILE__, "%s%s%s", \ 90 (priority), __LINE__, 0, \ 91 (prefix) != NULL ? (prefix) : "", \ 92 CXLB_buffer, CXLB_buf); \ 93 free(CXLB_buffer); \ 94 } else { \ 95 qb_log_from_external_source(__FUNCTION__, __FILE__, "%s%s", \ 96 (priority), __LINE__, 0, \ 97 (prefix) != NULL ? (prefix) : "", \ 98 CXLB_buf); \ 99 } \ 100 if (CXLB_len < 0) { \ 101 CXLB_buf = NULL; /* restore temporary override */ \ 102 } \ 103 CXLB_buffer = NULL; \ 104 CXLB_buffer_len = 0; \ 105 (void) (postemit); \ 106 \ 107 } else if (CXLB_buffer == NULL) { \ 108 CXLB_buffer_len = CXLB_len; \ 109 CXLB_buffer = CXLB_buf; \ 110 CXLB_buf = NULL; \ 111 \ 112 } else { \ 113 CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \ 114 memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len); \ 115 CXLB_buffer_len += CXLB_len; \ 116 CXLB_buffer[CXLB_buffer_len] = '\0'; \ 117 } \ 118 free(CXLB_buf); \ 119 } \ 120 } while (0) 121 122 #endif