Extensible config 39/121339/16
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Thu, 20 Apr 2017 14:35:55 +0000 (16:35 +0200)
committerMichal Bloch <m.bloch@samsung.com>
Thu, 20 Apr 2017 17:44:05 +0000 (19:44 +0200)
 * reader config now prefix based instead of indexed
 * extra config can now be read from a directory
   (has to be named same as conf file + ".d")

Change-Id: I2bf3d31526d1fc40fbf20a2ad7b4a62282c2423d
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
[ Reworked file and directory read functions. ]
Signed-off-by: Karol Lewandowski <k.lewandowsk@samsung.com>
13 files changed:
Makefile.am
configs/dlog.conf.logger
configs/dlog.conf.pipe
include/logcommon.h
include/logconfig.h
packaging/dlog.spec
src/logger/logger.c
src/shared/logcommon.c
src/shared/logconfig.c
src/tests/config.c
src/tests/test.conf
src/tests/test.conf.d/test.conf [new file with mode: 0644]
src/tests/test.conf.d/test.invalid [new file with mode: 0644]

index 4017010..a383b5b 100644 (file)
@@ -79,6 +79,7 @@ dlogctrl_LDFLAGS = \
 
 dlogctrl_SOURCES = \
        src/shared/logconfig.c \
+       src/shared/logcommon.c \
        src/logctrl/logctrl.c
 
 TESTS = \
@@ -93,7 +94,7 @@ check_PROGRAMS = \
        src/tests/pipe_message \
        src/tests/filters
 
-src_tests_config_SOURCES = src/tests/config.c src/shared/logconfig.c
+src_tests_config_SOURCES = src/tests/config.c src/shared/logconfig.c src/shared/logcommon.c
 src_tests_config_CFLAGS = $(AM_CFLAGS)
 src_tests_config_LDFLAGS = $(AM_LDFLAGS)
 
index fa6cafc..ba40c24 100644 (file)
@@ -21,8 +21,8 @@ kmsg_ctl_sock_owner=log
 kmsg_write_sock_owner=log
 kmsg_ctl_sock_group=log
 kmsg_write_sock_group=log
-dlog_logger_conf_0=dlogutil -b system -r 2048 -n 1 -f /var/log/dlog/system -v recv_realtime *:I
-dlog_logger_conf_1=dlogutil -b main -r 1024 -n 1 -f /var/log/dlog/main -v recv_realtime *:W
-dlog_logger_conf_2=dlogutil -b radio -r 256 -n 1 -f /var/log/dlog/radio -v recv_realtime
-dlog_logger_conf_3=dlogutil -b kmsg -r 1024 -n 1 -f /var/log/dlog/kernel -v rwtime
+dlog_logger_conf_system=dlogutil -b system -r 2048 -n 1 -f /var/log/dlog/system -v recv_realtime *:I
+dlog_logger_conf_main=dlogutil -b main -r 1024 -n 1 -f /var/log/dlog/main -v recv_realtime *:W
+dlog_logger_conf_radio=dlogutil -b radio -r 256 -n 1 -f /var/log/dlog/radio -v recv_realtime
+dlog_logger_conf_kmsg=dlogutil -b kmsg -r 1024 -n 1 -f /var/log/dlog/kernel -v rwtime
 util_sorting_buffer_size=8192
index dd879a6..7885e23 100644 (file)
@@ -77,10 +77,10 @@ radio_size=1048576
 kmsg_size=1048576
 
 # Passive logging to file done by the daemon.
-dlog_logger_conf_0=dlogutil -b system -r 2048 -n 1 -f /var/log/dlog/system.raw -v recv_realtime *:I
-dlog_logger_conf_1=dlogutil -b main -r 1024 -n 1 -f /var/log/dlog/main.raw -v recv_realtime *:W
-dlog_logger_conf_2=dlogutil -b radio -r 256 -n 1 -f /var/log/dlog/radio.raw -v recv_realtime
-dlog_logger_conf_3=dlogutil -b kmsg -r 256 -n 1 -f /var/log/dlog/kernel -v rwtime
+dlog_logger_conf_system=dlogutil -b system -r 2048 -n 1 -f /var/log/dlog/system.raw -v recv_realtime *:I
+dlog_logger_conf_main=dlogutil -b main -r 1024 -n 1 -f /var/log/dlog/main.raw -v recv_realtime *:W
+dlog_logger_conf_radio=dlogutil -b radio -r 256 -n 1 -f /var/log/dlog/radio.raw -v recv_realtime
+dlog_logger_conf_kmsg=dlogutil -b kmsg -r 256 -n 1 -f /var/log/dlog/kernel -v rwtime
 
 ##### Settings used by dlogutil
 
index 45b582e..a039ed1 100644 (file)
@@ -54,4 +54,6 @@ static inline int max_int(int a, int b) { return a > b ? a : b; }
 static inline int min_int(int a, int b) { return a < b ? a : b; }
 static inline int clamp_int(int i, int min, int max) { return min_int(max, max_int(min, i)); }
 
+int str_ends_with(const char *str, const char *suffix);
+
 #endif /* _LOGCOMMON_H */
index 16bc7c4..10a550a 100644 (file)
@@ -27,6 +27,7 @@
 #endif
 
 #define DEFAULT_CONFIG_PATH    TZ_SYS_ETC"/dlog.conf"
+#define DEFAULT_CONFIG_SUFFIX  ".conf"
 
 struct log_conf_entry;
 
index 68d2951..941e127 100644 (file)
@@ -120,6 +120,8 @@ mkdir -p %{buildroot}%{upgrade_file_path}/data
 install -m 0644 configs/dlog.conf.pipe %{buildroot}%{upgrade_file_path}/data/dlog.conf.pipe
 install -m 0644 configs/dlog.conf.logger %{buildroot}%{upgrade_file_path}/data/dlog.conf.logger
 
+mkdir -p %{buildroot}%{TZ_SYS_ETC}/dlog.conf.d
+
 %post
 systemctl daemon-reload
 
@@ -176,6 +178,7 @@ ln %{upgrade_file_path}/data/dlog.conf.pipe %{upgrade_file_path}/data/dlog.conf
 # For upgrade
 %{upgrade_file_path}/scripts/210.dlog_upgrade.sh
 %{upgrade_file_path}/data/dlog.conf.pipe
+%attr(644,log,log) %{TZ_SYS_ETC}/dlog.conf.d/
 
 %files -n libdlog-devel
 %{_includedir}/dlog/dlog.h
index 29b01f1..92d0ddc 100644 (file)
@@ -96,6 +96,7 @@ enum {
 #define FILE_PATH_SIZE (256)
 #define MAX_CONNECTION_Q 100
 #define DELIMITER " "
+#define CONF_PREFIX "dlog_logger_conf_"
 
 enum { INTERVAL_MIN = 0, INTERVAL_MAX = 3600 };
 enum { BUFFER_MIN = 0, BUFFER_MAX = 65535 };
@@ -1829,33 +1830,41 @@ end:
 }
 
 /**
+ * @brief Parse logfile line
+ * @detail Parses a logfile config line
+ * @param[in] key Config entry key
+ * @param[in] value Config entry value
+ * @param[in] userdata Userdata
+ */
+void parse_logfile_config(char const *key, char const *value, void *userdata)
+{
+       assert(userdata);
+
+       if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
+               return;
+
+       struct reader *rd = NULL;
+       int r = parse_command_line(value, NULL, &rd);
+       if (r < 0)
+               return;
+       assert(rd);
+
+       struct logger_config_data *lcd = (struct logger_config_data *) userdata;
+       rd->next = lcd->readers;
+       lcd->readers = rd;
+}
+
+/**
  * @brief Parse configs
  * @details configure the logger server
  * @param[out] data Parsed data
  * @param[in] config Configuration file
  * @return 0 on success, else -errno
  */
-static int logger_parse_configs(struct logger_config_data * data, struct log_config* config)
+static int logger_parse_configs(struct logger_config_data *data, struct log_config *config)
 {
-       char conf_key[MAX_CONF_KEY_LEN];
-       int i = 0;
-
        data->readers = NULL;
-
-       while (1) {
-               snprintf(conf_key, MAX_CONF_KEY_LEN, "dlog_logger_conf_%d", i++);
-               const char * conf_val = log_config_get(config, conf_key);
-               if (!conf_val)
-                       break;
-               struct reader * rd;
-               int r = parse_command_line(conf_val, NULL, &rd);
-               if (r < 0)
-                       return r;
-
-               rd->next = data->readers;
-               data->readers = rd;
-       }
-
+       log_config_foreach(config, parse_logfile_config, data);
        return 0;
 }
 
index 3fc4b05..9e9c1a0 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <logcommon.h>
+#include <assert.h>
 
 /**
  * @addtogroup SHARED_FUNCTIONS
@@ -147,6 +148,28 @@ int recv_file_descriptor(int socket)
                return -EIO;
 }
 
+
+/**
+ * @brief String suffix comparison
+ * @details Checks whether a string ends with given suffix
+ * @param[in] str The string to check
+ * @param[in] suffix The suffix
+ * @return 1 if yes, 0 if no
+ */
+int str_ends_with(const char *str, const char *suffix)
+{
+       assert(str);
+       assert(suffix);
+
+       const int str_len = strlen(str);
+       const int suffix_len = strlen(suffix);
+
+       if (str_len < suffix_len)
+               return 0;
+
+       return (str_len >= suffix_len) && !strcmp(str + str_len - suffix_len, suffix);
+}
+
 /**
  * @}
  */
index 855d316..0f1ad03 100644 (file)
@@ -1,8 +1,14 @@
+#include <assert.h>
 #include <logconfig.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <logcommon.h>
 
 /**
  * @addtogroup SHARED_FUNCTIONS
@@ -72,36 +78,64 @@ int log_config_set(struct log_config* c, const char* key, const char* value)
        return 0;
 }
 
-/**
- * @brief Read the config
- * @details Read the entire configuration.
- * @param[in] config The config to fill
- * @remarks The path defaults can be overridden with the DLOG_CONFIG_PATH env var
- * @return 0 on success, -errno on failure
- * @see log_config_free
- * @see log_config_write
- */
-int log_config_read(struct log_config* config)
+static void log_config_read_file_internal(struct log_config *config, FILE *fp)
 {
-       char const * override;
-       char const * backend;
+       assert(config);
+       assert(fp);
 
-       config->begin = config->last = NULL;
+       char line[MAX_CONF_ENTRY_LEN];
+       while (fgets(line, MAX_CONF_ENTRY_LEN, fp)) {
+               int len = strlen(line);
+               char key[MAX_CONF_KEY_LEN];
+
+               if (len <= 1 || line[0] == '#')
+                       continue;
+
+               if (line[len - 1] == '\n')
+                       line[len - 1] = '\0';
+
+               char *tok = strchr(line, '=');
+               if (!tok || (tok - line > MAX_CONF_KEY_LEN))
+                       continue;
+               ++tok;
+
+               snprintf(key, tok - line, "%s", line);
+               if (!log_config_set(config, key, tok))
+                       log_config_push(config, key, tok);
 
-       override = getenv("DLOG_CONFIG_PATH");
-       if (override)
-               return log_config_read_file(config, override);
-       int ret = log_config_read_file(config, DEFAULT_CONFIG_PATH);
-       if (ret < 0)
-               return ret;
-
-       backend = log_config_get(config, "backend");
-       if (!backend) {
-               log_config_free(config);
-               return -ENOENT;
        }
+}
 
-       return 0;
+static void log_config_read_dir(struct log_config *config, const char *dir_path)
+{
+       assert(config);
+       assert(dir_path);
+
+       DIR *dir = opendir(dir_path);
+       if (dir) {
+               struct dirent *de;
+               while ((de = readdir(dir))) {
+                       /* FIXME: sort entries alphanumerically */
+
+                       if (de->d_type != DT_REG)
+                               continue;
+
+                       if (!str_ends_with(de->d_name, DEFAULT_CONFIG_SUFFIX))
+                               continue;
+
+                       int fd = openat(dirfd(dir), de->d_name, O_RDONLY);
+                       if (fd < 0)
+                               continue;
+
+                       FILE *fp = fdopen(fd, "r");
+                       if (fp) {
+                               log_config_read_file_internal(config, fp);
+                               fclose(fp);
+                       }
+                       close(fd);
+               }
+               closedir(dir);
+       }
 }
 
 /**
@@ -113,37 +147,47 @@ int log_config_read(struct log_config* config)
  * @return 0 on success, -errno on failure
  * @see log_config_read
  */
-int log_config_read_file(struct log_config* config, const char* filename)
+int log_config_read_file(struct log_config *config, const char *filename)
 {
-       FILE * file;
-       char line[MAX_CONF_ENTRY_LEN];
-       char * tok;
+       assert(config);
+       assert(filename);
 
-       file = fopen(filename, "r");
-       if (!file)
+       FILE *fp = fopen(filename, "r");
+       if (!fp)
                return -errno;
 
-       while (fgets(line, MAX_CONF_ENTRY_LEN, file)) {
-               int len = strlen(line);
-               char key[MAX_CONF_KEY_LEN];
+       log_config_read_file_internal(config, fp);
+       fclose(fp);
 
-               if (len <= 1 || line[0] == '#')
-                       continue;
+       return 0;
+}
 
-               if (line[len - 1] == '\n')
-                       line[len - 1] = '\0';
+/**
+ * @brief Read the config
+ * @details Read the entire configuration.
+ * @param[in] config The config to fill
+ * @remarks The path defaults can be overridden with the DLOG_CONFIG_PATH environment variable.
+ *          Additionally, configuration snippets will be read from files ending with ".conf"
+ *          from DLOG_CONFIG_PATH.d directory
+ * @return 0 on success, -errno on failure
+ * @see log_config_free
+ * @see log_config_write
+ */
+int log_config_read(struct log_config *config)
+{
+       assert(config);
 
-               tok = strchr(line, '=');
-               if (!tok || (tok - line > MAX_CONF_KEY_LEN))
-                       continue;
-               ++tok;
+       config->begin = config->last = NULL;
 
-               snprintf(key, tok - line, "%s", line);
-               if (!log_config_get(config, key))
-                       log_config_push(config, key, tok);
-       }
+       char const *main_path = getenv("DLOG_CONFIG_PATH") ?: DEFAULT_CONFIG_PATH;
+       int r = log_config_read_file(config, main_path);
+       if (r < 0)
+               return r;
+
+       char dir_path[PATH_MAX];
+       snprintf(dir_path, sizeof dir_path, "%s.d", main_path);
+       log_config_read_dir(config, dir_path);
 
-       fclose(file);
        return 0;
 }
 
index b2d0b52..474e383 100644 (file)
@@ -30,5 +30,12 @@ int main()
        assert(strncmp(get, "bar", 4));
        assert(!strncmp(get, "quux", 5));
 
+       get = log_config_get(&config, "valid_extra_conf");
+       assert(get);
+       assert(!strncmp(get, "123", 4));
+
+       get = log_config_get(&config, "invalid_extra_conf");
+       assert(!get);
+
        return 0;
 }
index 9420591..f9b1b39 100644 (file)
@@ -1,4 +1,4 @@
 foo=bar
 
 #baz=quux
-
+backend=bla
diff --git a/src/tests/test.conf.d/test.conf b/src/tests/test.conf.d/test.conf
new file mode 100644 (file)
index 0000000..d59255f
--- /dev/null
@@ -0,0 +1,2 @@
+valid_extra_conf=123
+
diff --git a/src/tests/test.conf.d/test.invalid b/src/tests/test.conf.d/test.invalid
new file mode 100644 (file)
index 0000000..54a7cf2
--- /dev/null
@@ -0,0 +1,2 @@
+invalid_extra_conf=123
+