summaryrefslogtreecommitdiffstats
path: root/runtime/timezones.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/timezones.c')
-rw-r--r--runtime/timezones.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/runtime/timezones.c b/runtime/timezones.c
new file mode 100644
index 0000000..e1e0394
--- /dev/null
+++ b/runtime/timezones.c
@@ -0,0 +1,205 @@
+/* timezones.c
+ * Support for timezones in RainerScript.
+ *
+ * Copyright 2022 Attila Lakatos and 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 <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "rsyslog.h"
+#include "unicode-helper.h"
+#include "errmsg.h"
+#include "parserif.h"
+#include "rainerscript.h"
+#include "srUtils.h"
+#include "rsconf.h"
+
+
+static struct cnfparamdescr timezonecnfparamdescr[] = {
+ { "id", eCmdHdlrString, CNFPARAM_REQUIRED},
+ { "offset", eCmdHdlrGetWord, CNFPARAM_REQUIRED }
+};
+static struct cnfparamblk timezonepblk = {
+ CNFPARAMBLK_VERSION,
+ sizeof(timezonecnfparamdescr)/sizeof(struct cnfparamdescr),
+ timezonecnfparamdescr
+};
+
+/* Note: this function is NOT thread-safe!
+ * This is currently not needed as used only during
+ * initialization.
+ */
+static rsRetVal
+addTimezoneInfo(rsconf_t *cnf, uchar *tzid, char offsMode, int8_t offsHour, int8_t offsMin)
+{
+ DEFiRet;
+ tzinfo_t *newti;
+ CHKmalloc(newti = realloc(cnf->timezones.tzinfos, (cnf->timezones.ntzinfos+1)*sizeof(tzinfo_t)));
+ if((newti[cnf->timezones.ntzinfos].id = strdup((char*)tzid)) == NULL) {
+ free(newti);
+ DBGPRINTF("addTimezoneInfo: strdup failed with OOM\n");
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+ newti[cnf->timezones.ntzinfos].offsMode = offsMode;
+ newti[cnf->timezones.ntzinfos].offsHour = offsHour;
+ newti[cnf->timezones.ntzinfos].offsMin = offsMin;
+ ++cnf->timezones.ntzinfos, cnf->timezones.tzinfos = newti;
+finalize_it:
+ RETiRet;
+}
+
+void
+glblProcessTimezone(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ uchar *id = NULL;
+ uchar *offset = NULL;
+ char offsMode;
+ int8_t offsHour;
+ int8_t offsMin;
+ int i;
+
+ pvals = nvlstGetParams(o->nvlst, &timezonepblk, NULL);
+ if(pvals == NULL) {
+ LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing timezone "
+ "config parameters");
+ goto done;
+ }
+ if(Debug) {
+ dbgprintf("timezone param blk after glblProcessTimezone:\n");
+ cnfparamsPrint(&timezonepblk, pvals);
+ }
+
+ for(i = 0 ; i < timezonepblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(timezonepblk.descr[i].name, "id")) {
+ id = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(timezonepblk.descr[i].name, "offset")) {
+ offset = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else {
+ dbgprintf("glblProcessTimezone: program error, non-handled "
+ "param '%s'\n", timezonepblk.descr[i].name);
+ }
+ }
+
+ /* note: the following two checks for NULL are not strictly necessary
+ * as these are required parameters for the config block. But we keep
+ * them to make the clang static analyzer happy, which also helps
+ * guard against logic errors.
+ */
+ if(offset == NULL) {
+ parser_errmsg("offset parameter missing (logic error?), timezone config ignored");
+ goto done;
+ }
+ if(id == NULL) {
+ parser_errmsg("id parameter missing (logic error?), timezone config ignored");
+ goto done;
+ }
+
+ if( strlen((char*)offset) != 6
+ || !(offset[0] == '-' || offset[0] == '+')
+ || !(isdigit(offset[1]) && isdigit(offset[2]))
+ || offset[3] != ':'
+ || !(isdigit(offset[4]) && isdigit(offset[5]))
+ ) {
+ parser_errmsg("timezone offset has invalid format. Must be +/-hh:mm, e.g. \"-07:00\".");
+ goto done;
+ }
+
+ offsHour = (offset[1] - '0') * 10 + offset[2] - '0';
+ offsMin = (offset[4] - '0') * 10 + offset[5] - '0';
+ offsMode = offset[0];
+
+ if(offsHour > 12 || offsMin > 59) {
+ parser_errmsg("timezone offset outside of supported range (hours 0..12, minutes 0..59)");
+ goto done;
+ }
+
+ addTimezoneInfo(loadConf, id, offsMode, offsHour, offsMin);
+
+done:
+ cnfparamvalsDestruct(pvals, &timezonepblk);
+ free(id);
+ free(offset);
+}
+
+/* comparison function for qsort() and string array compare
+ * this is for the string lookup table type
+ */
+static int
+qs_arrcmp_tzinfo(const void *s1, const void *s2)
+{
+ return strcmp(((tzinfo_t*)s1)->id, ((tzinfo_t*)s2)->id);
+}
+
+void sortTimezones(rsconf_t *cnf)
+{
+ if (cnf->timezones.ntzinfos > 0) {
+ qsort(cnf->timezones.tzinfos, cnf->timezones.ntzinfos,
+ sizeof(tzinfo_t), qs_arrcmp_tzinfo);
+ }
+}
+
+void
+displayTimezones(rsconf_t *cnf)
+{
+ if(!Debug)
+ return;
+ for(int i = 0 ; i < cnf->timezones.ntzinfos ; ++i)
+ dbgprintf("tzinfo: '%s':%c%2.2d:%2.2d\n",
+ cnf->timezones.tzinfos[i].id, cnf->timezones.tzinfos[i].offsMode,
+ cnf->timezones.tzinfos[i].offsHour, cnf->timezones.tzinfos[i].offsMin);
+}
+
+static int
+bs_arrcmp_tzinfo(const void *s1, const void *s2)
+{
+ return strcmp((char*)s1, (char*)((tzinfo_t*)s2)->id);
+}
+
+/* returns matching timezone info or NULL if no entry exists */
+tzinfo_t*
+glblFindTimezone(rsconf_t *cnf, char *id)
+{
+ return (tzinfo_t*) bsearch(
+ id, cnf->timezones.tzinfos, cnf->timezones.ntzinfos, sizeof(tzinfo_t), bs_arrcmp_tzinfo);
+}
+
+static void
+freeTimezone(tzinfo_t *tzinfo)
+{
+ free(tzinfo->id);
+}
+
+void
+freeTimezones(rsconf_t *cnf)
+{
+ for(int i = 0; i < cnf->timezones.ntzinfos ; ++i)
+ freeTimezone(&cnf->timezones.tzinfos[i]);
+ if (cnf->timezones.ntzinfos > 0)
+ free(cnf->timezones.tzinfos);
+ cnf->timezones.tzinfos = NULL;
+}