diff options
Diffstat (limited to 'runtime/errmsg.c')
-rw-r--r-- | runtime/errmsg.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/runtime/errmsg.c b/runtime/errmsg.c new file mode 100644 index 0000000..ecc0452 --- /dev/null +++ b/runtime/errmsg.c @@ -0,0 +1,288 @@ +/* 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 "rsyslog.h" +#include "obj.h" +#include "msg.h" +#include "errmsg.h" +#include "operatingstate.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. + */ + +static int fdOversizeMsgLog = -1; +static pthread_mutex_t oversizeMsgLogMut = PTHREAD_MUTEX_INITIALIZER; + +/* ------------------------------ methods ------------------------------ */ + +/* Resets the error message flag. Must be done before processing config + * files. + */ +void +resetErrMsgsFlag(void) +{ + bHadErrMsgs = 0; +} + +int +hadErrMsgs(void) +{ + return bHadErrMsgs; +} + +/* 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 + */ +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) + bHadErrMsgs = 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) { + strncpy(buf, "error message lost due to problem with vsnprintf", sizeof(buf)); + } + 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) { + strncpy(buf, "error message lost due to problem with vsnprintf", sizeof(buf)); + } + 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); + json = json_object_new_object(); + if(json == NULL) { + FINALIZE; + } + + getRawMsg(pMsg, &buf, &dummy); + jval = json_object_new_string((char*)buf); + json_object_object_add(json, "rawmsg", jval); + + getInputName(pMsg, &buf, &dummy); + 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); + } +} |