/
githubmirror
/
rsyslog
Обзор
Документация
Войти
/
githubmirror
/
rsyslog
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
runtime/errmsg.c
375 строк
14 KB
Rainer Gerhards
runtime: make error-message flag atomic
07 авг 2026, 10:42
07 авг 2026, 10:42
b84f25a
Код
Авторство
О чём код?
/* The errmsg object. * * Module begun 2008-03-05 by Rainer Gerhards, based on some code * from syslogd.c. I converted this module to lgpl and have checked that * all contributors agreed to that step. * Now moving to ASL 2.0, and contributor checks tell that there is no need * to take further case, as the code now boils to be either my own or, a few lines, * of the original BSD-licenses sysklogd code. rgerhards, 2012-01-16 * * Copyright 2008-2018 Adiscon GmbH. * * This file is part of the rsyslog runtime library. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * -or- * see COPYING.ASL20 in the source distribution * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <errno.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <limits.h> #include "rsyslog.h" #include "obj.h" #include "msg.h" #include "errmsg.h" #include "operatingstate.h" #include "atomic.h" #include "srUtils.h" #include "stringbuf.h" #include "rsconf.h" /* static data */ #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif static int bHadErrMsgs; /* indicates if we had error messages since reset of this flag * This is used to abort a run if the config is unclean. */ #ifndef HAVE_ATOMIC_BUILTINS static DEF_ATOMIC_HELPER_MUT(mutHadErrMsgs) = PTHREAD_MUTEX_INITIALIZER; #define MUT_HAD_ERR_MSGS &mutHadErrMsgs #else #define MUT_HAD_ERR_MSGS NULL #endif static int fdOversizeMsgLog = -1; static pthread_mutex_t oversizeMsgLogMut = PTHREAD_MUTEX_INITIALIZER; /* ------------------------------ methods ------------------------------ */ static rsRetVal oversizeJsonAddStringLen(struct json_object *const json, const char *const name, const uchar *const value, const rs_size_t valueLen) { struct json_object *jval = NULL; const uchar *const safeValue = (value == NULL) ? (const uchar *)"" : value; const size_t safeLen = (valueLen == (rs_size_t)-1) ? strlen((const char *)safeValue) : (size_t)valueLen; const int jsonLen = (safeLen > INT_MAX) ? INT_MAX : (int)safeLen; DEFiRet; CHKmalloc(jval = json_object_new_string_len((const char *)safeValue, jsonLen)); json_object_object_add(json, name, jval); finalize_it: RETiRet; } static rsRetVal oversizeJsonAddProp(struct json_object *const json, smsg_t *const pMsg, const char *const name, const propid_t propId, struct templateEntry *const pTpe) { msgPropDescr_t propDescr = {.id = propId, .name = NULL, .nameLen = 0}; struct syslogTime ttNow; uchar *value = NULL; rs_size_t valueLen = -1; unsigned short mustBeFreed = 0; DEFiRet; memset(&ttNow, 0, sizeof(ttNow)); value = MsgGetProp(pMsg, pTpe, &propDescr, &valueLen, &mustBeFreed, &ttNow); CHKiRet(oversizeJsonAddStringLen(json, name, value, valueLen)); finalize_it: if (mustBeFreed) { free(value); } RETiRet; } static rsRetVal oversizeJsonAddMsg(struct json_object *const json, const smsg_t *const pMsg) { uchar *msg = (uchar *)""; rs_size_t msgLen = 0; if (pMsg->pszRawMsg != NULL && pMsg->offMSG >= 0 && pMsg->offMSG <= pMsg->iLenRawMsg && pMsg->iLenMSG > 0 && pMsg->iLenMSG <= pMsg->iLenRawMsg - pMsg->offMSG) { msg = pMsg->pszRawMsg + pMsg->offMSG; msgLen = pMsg->iLenMSG; } return oversizeJsonAddStringLen(json, "msg", msg, msgLen); } static rsRetVal oversizeJsonFromMsg(struct json_object **const json, const smsg_t *const pMsg) { struct templateEntry dateTpe; uchar *value = NULL; int valueLen = 0; DEFiRet; memset(&dateTpe, 0, sizeof(dateTpe)); dateTpe.data.field.eDateFormat = tplFmtRFC3339Date; CHKmalloc(*json = json_object_new_object()); CHKiRet(oversizeJsonAddMsg(*json, pMsg)); getRawMsg(pMsg, &value, &valueLen); CHKiRet(oversizeJsonAddStringLen(*json, "rawmsg", value, valueLen)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "timereported", PROP_TIMESTAMP, &dateTpe)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "hostname", PROP_HOSTNAME, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "syslogtag", PROP_SYSLOGTAG, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "inputname", PROP_INPUTNAME, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "fromhost", PROP_FROMHOST, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "fromhost-ip", PROP_FROMHOST_IP, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "fromhost-port", PROP_FROMHOST_PORT, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "pri", PROP_PRI, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "syslogfacility", PROP_SYSLOGFACILITY, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "syslogseverity", PROP_SYSLOGSEVERITY, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "timegenerated", PROP_TIMEGENERATED, &dateTpe)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "programname", PROP_PROGRAMNAME, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "protocol-version", PROP_PROTOCOL_VERSION, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "structured-data", PROP_STRUCTURED_DATA, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "app-name", PROP_APP_NAME, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "procid", PROP_PROCID, NULL)); CHKiRet(oversizeJsonAddProp(*json, (smsg_t *)pMsg, "msgid", PROP_MSGID, NULL)); #ifdef USE_LIBUUID if (pMsg->pszUUID == NULL) { json_object_object_add(*json, "uuid", NULL); } else { CHKiRet(oversizeJsonAddStringLen(*json, "uuid", pMsg->pszUUID, (rs_size_t)-1)); } #endif if (pMsg->json != NULL) { json_object_object_add(*json, "$!", json_object_get(pMsg->json)); } finalize_it: RETiRet; } /* Resets the error message flag. Must be done before processing config * files. */ void resetErrMsgsFlag(void) { ATOMIC_STORE_32BIT(&bHadErrMsgs, MUT_HAD_ERR_MSGS, 0); } int hadErrMsgs(void) { return ATOMIC_LOAD_32BIT(&bHadErrMsgs, MUT_HAD_ERR_MSGS); } /** @internal * Build and emit a single diagnostic line. * * - If iErrno != 0, append strerror(iErrno). * - If iErrCode is neither NO_ERRCODE nor RS_RET_ERR, append a help URL. * - Truncate to the configured max line length. * - Set the "had error" flag for LOG_ERR. */ static void doLogMsg(const int iErrno, const int iErrCode, const int severity, const char *msg) { char buf[2048]; char errStr[1024]; dbgprintf("Called LogMsg, msg: %s\n", msg); osf_write(OSF_TAG_MSG, msg); if (iErrno != 0) { rs_strerror_r(iErrno, errStr, sizeof(errStr)); if (iErrCode == NO_ERRCODE || iErrCode == RS_RET_ERR) { snprintf(buf, sizeof(buf), "%s: %s [v%s]", msg, errStr, VERSION); } else { snprintf(buf, sizeof(buf), "%s: %s [v%s try https://www.rsyslog.com/e/%d ]", msg, errStr, VERSION, iErrCode * -1); } } else { if (iErrCode == NO_ERRCODE || iErrCode == RS_RET_ERR) { snprintf(buf, sizeof(buf), "%s [v%s]", msg, VERSION); } else { snprintf(buf, sizeof(buf), "%s [v%s try https://www.rsyslog.com/e/%d ]", msg, VERSION, iErrCode * -1); } } buf[sizeof(buf) - 1] = '\0'; /* just to be on the safe side... */ errno = 0; const int msglen = (int)strlen(buf); if (msglen > glblGetMaxLine(ourConf)) { /* in extreme cases, our error messages may be longer than the configured * max message size. If so, we just truncate without further indication, as * anything else would probably lead to a death loop on error messages. * Note that we do not split, as we really do not anticipate there is * much value in supporting extremely short max message sizes - we assume * it's just a testbench thing. -- rgerhards, 2018-05-11 */ buf[glblGetMaxLine(ourConf)] = '\0'; /* space must be available! */ } glblErrLogger(severity, iErrCode, (uchar *)buf); if (severity == LOG_ERR) ATOMIC_STORE_32BIT(&bHadErrMsgs, MUT_HAD_ERR_MSGS, 1); } /* We now receive three parameters: one is the internal error code * which will also become the error message number, the second is * errno - if it is non-zero, the corresponding error message is included * in the text and finally the message text itself. Note that it is not * 100% clean to use the internal errcode, as it may be reached from * multiple actual error causes. However, it is much better than having * no error code at all (and in most cases, a single internal error code * maps to a specific error event). * rgerhards, 2008-06-27 */ void __attribute__((format(printf, 3, 4))) LogError(const int iErrno, const int iErrCode, const char *fmt, ...) { va_list ap; char buf[2048]; int lenBuf; va_start(ap, fmt); lenBuf = vsnprintf(buf, sizeof(buf), fmt, ap); if (lenBuf < 0) { memcpy(buf, "error message lost due to problem with vsnprintf", sizeof("error message lost due to problem with vsnprintf")); } va_end(ap); buf[sizeof(buf) - 1] = '\0'; /* just to be on the safe side... */ doLogMsg(iErrno, iErrCode, LOG_ERR, buf); } /* We now receive three parameters: one is the internal error code * which will also become the error message number, the second is * errno - if it is non-zero, the corresponding error message is included * in the text and finally the message text itself. Note that it is not * 100% clean to use the internal errcode, as it may be reached from * multiple actual error causes. However, it is much better than having * no error code at all (and in most cases, a single internal error code * maps to a specific error event). * rgerhards, 2008-06-27 */ void __attribute__((format(printf, 4, 5))) LogMsg( const int iErrno, const int iErrCode, const int severity, const char *fmt, ...) { va_list ap; char buf[2048]; int lenBuf; va_start(ap, fmt); lenBuf = vsnprintf(buf, sizeof(buf), fmt, ap); if (lenBuf < 0) { memcpy(buf, "error message lost due to problem with vsnprintf", sizeof("error message lost due to problem with vsnprintf")); } va_end(ap); buf[sizeof(buf) - 1] = '\0'; /* just to be on the safe side... */ doLogMsg(iErrno, iErrCode, severity, buf); } /* Write an oversize message to the oversize message error log. * We do NOT handle errors during writing that log other than emitting * yet another error message. The reason is that there really is nothing * else that we could do in that case. * rgerhards, 2018-05-03 */ rsRetVal ATTR_NONNULL() writeOversizeMessageLog(const smsg_t *const pMsg) { struct json_object *json = NULL; char *rendered = NULL; struct json_object *jval; uchar *buf; size_t toWrite; ssize_t wrRet; int dummy; int mutexLocked = 0; DEFiRet; ISOBJ_TYPE_assert(pMsg, msg); if (glblGetOversizeMsgErrorFile(runConf) == NULL) { FINALIZE; } pthread_mutex_lock(&oversizeMsgLogMut); mutexLocked = 1; if (fdOversizeMsgLog == -1) { fdOversizeMsgLog = open((char *)glblGetOversizeMsgErrorFile(runConf), O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (fdOversizeMsgLog == -1) { LogError(errno, RS_RET_ERR, "error opening oversize message log file %s", glblGetOversizeMsgErrorFile(runConf)); FINALIZE; } } assert(fdOversizeMsgLog != -1); CHKiRet(oversizeJsonFromMsg(&json, pMsg)); /* Preserve the historical oversize errorfile field name while also * emitting the regular full-message JSON field "inputname". */ getInputName(pMsg, &buf, &dummy); CHKmalloc(jval = json_object_new_string((char *)buf)); json_object_object_add(json, "input", jval); CHKmalloc(rendered = strdup((char *)fjson_object_to_json_string(json))); toWrite = strlen(rendered) + 1; /* Note: we overwrite the '\0' terminator with '\n' -- so we avoid * calling malloc() -- write() does NOT need '\0'! */ rendered[toWrite - 1] = '\n'; /* NO LONGER A STRING! */ wrRet = write(fdOversizeMsgLog, rendered, toWrite); if (wrRet != (ssize_t)toWrite) { LogError(errno, RS_RET_IO_ERROR, "error writing oversize message log file %s, write returned %lld", glblGetOversizeMsgErrorFile(runConf), (long long)wrRet); } finalize_it: free(rendered); if (mutexLocked) { pthread_mutex_unlock(&oversizeMsgLogMut); } if (json != NULL) { fjson_object_put(json); } RETiRet; } void errmsgDoHUP(void) { pthread_mutex_lock(&oversizeMsgLogMut); if (fdOversizeMsgLog != -1) { close(fdOversizeMsgLog); fdOversizeMsgLog = -1; } pthread_mutex_unlock(&oversizeMsgLogMut); } void errmsgExit(void) { if (fdOversizeMsgLog != -1) { close(fdOversizeMsgLog); } }