/* * OwnTracks Recorder * Copyright (C) 2015-2020 Jan-Piet Mens * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "utstring.h" #include "ctype.h" #include "udata.h" #include "misc.h" #include "util.h" char *bindump(char *buf, long buflen) { static UT_string *out = NULL; int i, ch; utstring_renew(out); for (i = 0; i < buflen; i++) { ch = buf[i]; if (isprint(ch)) { utstring_printf(out, "%c", ch); } else { utstring_printf(out, " %02X ", ch & 0xFF); } } return (UB(out)); } /* * At each received message, the recorder invokes this function with the * current epoch time and the topic being handled. Use this to update * a monitoring hoook. If we have Redis, use that exclusively. */ void monitorhook(struct udata *userdata, time_t now, char *topic) { // struct udata *ud = (struct udata *)userdata; /* TODO: add monitor hook to a "monitor" key in LMDB ? */ char mpath[BUFSIZ]; static UT_string *us = NULL; utstring_renew(us); utstring_printf(us, "%ld %s\n", (long)now, topic); snprintf(mpath, sizeof(mpath), "%s/monitor", STORAGEDIR); safewrite(mpath, UB(us)); } /* * Return a pointer to a static area containing the last monitor entry or NULL. */ char *monitor_get() { char mpath[BUFSIZ]; static char monitorline[BUFSIZ], *ret = NULL; FILE *fp; snprintf(mpath, sizeof(mpath), "%s/monitor", STORAGEDIR); if ((fp = fopen(mpath, "r")) != NULL) { if (fgets(monitorline, sizeof(monitorline), fp) != NULL) { char *bp = strchr(monitorline, '\n'); if (bp) *bp = 0; ret = monitorline; } fclose(fp); } return (ret); } /* * Set the value of configuration `property' to the optional default * at `def', then try to find it in the open config file at `cf', * and finally the environment. Return a new copy. */ static char *c_str(config_t *cf, char *property, char *def) { const char *value; char *val = def, *p; if (config_lookup_string(cf, property, &value) != CONFIG_FALSE) { val = (char *)value; } if ((p = getenv(property)) != NULL) { val = p; } return val ? strdup(val) : val; } static int c_int(config_t *cf, char *property, int def) { #if LIBCONFIG_VER_MAJOR == 1 # if LIBCONFIG_VER_MINOR >= 4 int ival; # endif # else long ival; #endif int val = def; char *p; if (config_lookup_int(cf, property, &ival) != CONFIG_FALSE) { val = (int)ival; } if ((p = getenv(property)) != NULL) { val = atol(p); } return val; } /* * Fill in some defaults */ void get_defaults(char *filename, struct udata *ud) { config_t cfg, *cf; char *v; int iv; if (access(filename, R_OK) == -1) { olog(LOG_ERR, "Cannot read defaults from %s: %s", filename, strerror(errno)); return; } config_init(cf = &cfg); if (!config_read_file(cf, filename)) { olog(LOG_ERR, "Syntax error in %s:%d - %s", filename, config_error_line(cf), config_error_text(cf)); config_destroy(cf); exit(2); } v = c_str(cf, "OTR_STORAGEDIR", STORAGEDEFAULT); strcpy(STORAGEDIR, v); if (ud == NULL) { /* being invoked by ocat; return */ return; } #if WITH_MQTT ud->hostname = c_str(cf, "OTR_HOST", "localhost"); ud->username = c_str(cf, "OTR_USER", NULL); ud->password = c_str(cf, "OTR_PASS", NULL); ud->clientid = c_str(cf, "OTR_CLIENTID", ud->clientid); ud->capath = c_str(cf, "OTR_CAPATH", NULL); ud->cafile = c_str(cf, "OTR_CAFILE", NULL); ud->certfile = c_str(cf, "OTR_CERTFILE", NULL); ud->keyfile = c_str(cf, "OTR_KEYFILE", NULL); ud->port = c_int(cf, "OTR_PORT", 1883); ud->qos = c_int(cf, "OTR_QOS", ud->qos); /* Topics is a blank-separated string of words; split and add to JSON array */ if ((v = c_str(cf, "OTR_TOPICS", NULL)) != NULL) { char *parts[40]; int np, n; if (ud->topics) json_delete(ud->topics); if ((np = splitter((char *)v, " ", parts)) < 1) { olog(LOG_ERR, "Illegal value in OTR_TOPICS"); exit(2); } ud->topics = json_mkarray(); for (n = 0; n < np; n++) { json_append_element(ud->topics, json_mkstring(parts[n])); } splitterfree(parts); } #endif /* WITH_MQTT */ ud->geokey = c_str(cf, "OTR_GEOKEY", NULL); iv = c_int(cf, "OTR_PRECISION", GHASHPREC); geohash_setprec(iv); #if WITH_HTTP ud->http_host = c_str(cf, "OTR_HTTPHOST", NULL); ud->http_logdir = c_str(cf, "OTR_HTTPLOGDIR", NULL); ud->browser_apikey = c_str(cf, "OTR_BROWSERAPIKEY", NULL); ud->http_port = c_int(cf, "OTR_HTTPPORT", ud->http_port); #ifdef WITH_SHARES ud->http_prefix = c_str(cf, "OTR_HTTPPREFIX", NULL); # endif /* WITH_SHARES */ #endif /* WITH_HTTP */ #if WITH_LUA ud->luascript = c_str(cf, "OTR_LUASCRIPT", NULL); #endif config_destroy(cf); }