diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am index 26395333eb..035529a511 100644 --- a/include/crm/common/Makefile.am +++ b/include/crm/common/Makefile.am @@ -1,27 +1,27 @@ # # Copyright (C) 2004 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in headerdir=$(pkgincludedir)/crm/common header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h logging.h -noinst_HEADERS = ipcs.h internal.h +noinst_HEADERS = ipcs.h internal.h xml_internal.h if BUILD_CIBSECRETS noinst_HEADERS += cib_secrets.h endif diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h new file mode 100644 index 0000000000..970e2d9ff5 --- /dev/null +++ b/include/crm/common/xml_internal.h @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Jan Pokorny + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef CRM_COMMON_XML_INTERNAL__H +# define CRM_COMMON_XML_INTERNAL__H + +/** + * \file + * \brief Internal-only wrappers for and extensions to libxml2 (libxslt) + * \ingroup core + */ + +# include +# include +# include + +# include /* transitively imports qblog.h */ + + +/*! + * \brief Base for directing lib{xml2,xslt} log into standard libqb backend + * + * This macro implements the core of what can be needed for directing + * libxml2 or libxslt error messaging into standard, preconfigured + * libqb-backed log stream. + * + * It's a bit unfortunate that libxml2 (and more sparsely, also libxslt) + * emits a single message by chunks (location is emitted separatedly from + * the message itself), so we have to take the effort to combine these + * chunks back to single message. Whether to do this or not is driven + * with \p dechunk toggle. + * + * The form of a macro was chosen for implicit deriving of __FILE__, etc. + * and also because static dechunking buffer should be differentiated per + * library (here we assume different functions referring to this macro + * will not ever be using both at once), preferably also per-library + * context of use to avoid clashes altogether. + * + * Note that we cannot use qb_logt, because callsite data have to be known + * at the moment of compilation, which it is not always the case -- xml_log + * (and unfortunately there's no clear explanation of the fail to compile). + * + * Also note that there's no explicit guard against said libraries producing + * never-newline-terminated chunks (which would just keep consuming memory), + * as it's quite improbable. Termination of the program in between the + * same-message chunks will raise a flag with valgrind and the likes, though. + * + * \param[in] priority Syslog priority for the message to be logged + * \param[in] dechunk Whether to dechunk new-line terminated message + * \param[in] postemit Code to be executed once message is sent out + * \param[in] prefix How to prefix the message or NULL for raw passing + * \param[in] fmt Format string as with printf-like functions + * \param[in] ap Variable argument list to supplement \p fmt format string + */ +#define CRM_XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap) \ +do { \ + if (!(dechunk) && (prefix) == NULL) { /* quick pass */ \ + qb_log_from_external_source_va(__FUNCTION__, __FILE__, (fmt), \ + (priority), __LINE__, 0, (ap)); \ + (void) (postemit); \ + } else { \ + int CXLB_len = 0; \ + char *CXLB_buf = NULL; \ + static int CXLB_buffer_len = 0; \ + static char *CXLB_buffer = NULL; \ + \ + CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap)); \ + \ + if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) { \ + if (CXLB_len < 0) { \ + CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\ + } else if (CXLB_len > 0 /* && (dechunk) */ \ + && CXLB_buf[CXLB_len - 1] == '\n') { \ + CXLB_buf[CXLB_len - 1] = '\0'; \ + } \ + if (CXLB_buffer) { \ + qb_log_from_external_source(__FUNCTION__, __FILE__, "%s%s%s", \ + (priority), __LINE__, 0, \ + (prefix) != NULL ? (prefix) : "", \ + CXLB_buffer, CXLB_buf); \ + free(CXLB_buffer); \ + } else { \ + qb_log_from_external_source(__FUNCTION__, __FILE__, "%s%s", \ + (priority), __LINE__, 0, \ + (prefix) != NULL ? (prefix) : "", \ + CXLB_buf); \ + } \ + if (CXLB_len < 0) { \ + CXLB_buf = NULL; /* restore temporary override */ \ + } \ + CXLB_buffer = NULL; \ + CXLB_buffer_len = 0; \ + (void) (postemit); \ + \ + } else if (CXLB_buffer == NULL) { \ + CXLB_buffer_len = CXLB_len; \ + CXLB_buffer = CXLB_buf; \ + CXLB_buf = NULL; \ + \ + } else { \ + CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \ + memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len); \ + CXLB_buffer_len += CXLB_len; \ + CXLB_buffer[CXLB_buffer_len] = '\0'; \ + } \ + free(CXLB_buf); \ + } \ +} while (0) + +#endif