summaryrefslogtreecommitdiffstats
path: root/runtime/errmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/errmsg.c')
-rw-r--r--runtime/errmsg.c288
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);
+ }
+}