Revert "Remove unnecessary shared log codes" 93/150993/2
authorŁukasz Stelmach <l.stelmach@samsung.com>
Fri, 15 Sep 2017 13:06:45 +0000 (15:06 +0200)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 21 Sep 2017 08:08:55 +0000 (10:08 +0200)
This reverts commit be1e9a33516c14ccc5815c7e9584b00bbf785a52.

Change-Id: I20c04d58dc0833e72d8ce2a5e0dcfedd0fa669a6

Makefile.am
src/shared/log.c [new file with mode: 0644]
src/shared/log.h [new file with mode: 0644]

index 8bd11a3..9df4e35 100644 (file)
@@ -15,7 +15,8 @@ DEFAULT_LDFLAGS = \
        $(OUR_LDFLAGS)
 
 DEFAULT_LIBS = \
-       $(LIBSYSTEM_LIBS)
+       $(LIBSYSTEM_LIBS) \
+       libinitrd-recovery-shared.la
 
 AM_CPPFLAGS = \
        -include $(top_builddir)/config.h \
@@ -41,6 +42,20 @@ initrd_recovery_libexec_SCRIPTS =
 initrd_recovery_install_dropin_DATA =
 
 # ------------------------------------------------------------------------------
+noinst_LTLIBRARIES += \
+       libinitrd-recovery-shared.la
+
+libinitrd_recovery_shared_la_SOURCES = \
+       src/shared/log.c \
+       src/shared/log.h
+
+libinitrd_recovery_shared_la_CFLAGS = \
+       $(AM_CFLAGS)
+
+libinitrd_recovery_shared_la_LIBADD = \
+       $(LIBSYSTEM_LIBS)
+
+# ------------------------------------------------------------------------------
 initrd_recovery_libexec_SCRIPTS += \
        src/initrd-recovery/init \
        src/initrd-recovery/mkinitrd-recovery.sh
diff --git a/src/shared/log.c b/src/shared/log.c
new file mode 100644 (file)
index 0000000..53c73f4
--- /dev/null
@@ -0,0 +1,414 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+
+#define FILEBUF 1024
+
+static inline void __cleanup_free_func(void *p)
+{
+       free(*(void**) p);
+}
+
+static inline bool isempty(const char *p)
+{
+       return !p || !p[0];
+}
+
+#define _cleanup_(x) __attribute__((cleanup(x)))
+
+#define _cleanup_free_ _cleanup_(__cleanup_free_func)
+
+#define new(t, n) ((t*) malloc(sizeof(t) * (n)))
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
+       for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state)))
+
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+
+static FILE *log_f[LOG_TYPE_MAX];
+static int stdout_bak = -1;
+static int stderr_bak = -1;
+
+static int log_level = LOG_DEBUG;
+
+static const char const *log_priority_name[] = {
+       [LOG_ALERT]   = "alert",
+       [LOG_CRIT]    = "crit",
+       [LOG_DEBUG]   = "debug",
+       [LOG_EMERG]   = "emerg",
+       [LOG_ERR]     = "err",
+       [LOG_INFO]    = "info",
+       [LOG_NOTICE]  = "notice",
+       [LOG_WARNING] = "warning"
+};
+
+void set_log_level(int level)
+{
+       log_level = level;
+}
+
+int get_log_level(void)
+{
+       return log_level;
+}
+
+static bool __quote_complete(char *str, size_t l, char q)
+{
+       char *s, *s2;
+
+       assert(str);
+
+       if (!l)
+               return true;
+
+       s = strchr(str, q);
+       if (!s || (s - str) > l)
+               return true;
+
+       s = strchr(s + 1, q);
+       if (!s || (s - str) > l)
+               return false;
+
+       s2 = strchr(s + 1, q);
+       if (!s2 || (s2 - str) > l)
+               return true;
+
+       return __quote_complete(s + 1, l - (s + 1 - str), q);
+}
+
+#define QUOTES "\"\'"
+static bool quote_complete(char *str, size_t l)
+{
+       char quotes[] = QUOTES;
+       int i;
+
+       assert(str);
+
+       if (!l)
+               return true;
+
+       for (i = 0; quotes[i]; i++) {
+               if (!__quote_complete(str, l, quotes[i]))
+                       return false;
+       }
+
+       return true;
+}
+
+static char *split(const char *c, size_t *l, const char *separator, char **state)
+{
+       bool separator_include_quotes;
+       char *current;
+       size_t s;
+
+       assert(c);
+       assert(l);
+       assert(separator);
+       assert(state);
+
+       current = *state ? *state : (char *) c;
+       if (!*current || *c == 0)
+               return NULL;
+
+       *l = 0;
+       separator_include_quotes = !!strspn(separator, QUOTES);
+       current += strspn(current, separator);
+
+       while ((s = strcspn(current + *l, separator))) {
+               *l += s;
+               if (separator_include_quotes ||
+                               quote_complete(current, *l))
+                       break;
+               (*l)++;
+       }
+
+       *state = current + *l;
+
+       return (char *) current;
+}
+
+static int stdpath_dup_and_backup(FILE *f)
+{
+       int r, fd;
+
+       stdout_bak = dup(STDOUT_FILENO);
+       stderr_bak = dup(STDERR_FILENO);
+
+       fd = fileno(f);
+       r = dup2(fd, STDOUT_FILENO);
+       if (r < 0)
+               return -errno;
+
+       r = dup2(fd, STDERR_FILENO);
+       if (r < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int stdpath_restore(void)
+{
+       int r;
+
+       if (stdout_bak >= 0) {
+               r = dup2(stdout_bak, STDOUT_FILENO);
+               if (r < 0)
+                       return -errno;
+
+               close(stdout_bak);
+               stdout_bak = -1;
+       }
+
+       if (stderr_bak >= 0) {
+               r = dup2(stderr_bak, STDERR_FILENO);
+               if (r < 0)
+                       return -errno;
+
+               close(stderr_bak);
+               stderr_bak = -1;
+       }
+
+       return 0;
+}
+
+int log_open(enum log_mask log_set, const char *path)
+{
+       int r;
+
+       if (log_set & LOG_MASK_FILE) {
+               assert(path);
+
+               log_f[LOG_TYPE_FILE] = fopen(path, "w+");
+               if (!log_f[LOG_TYPE_FILE])
+                       return -errno;
+
+               /* If standard output/error were not set, redirect
+                * standard output/error to log file */
+               if (!(log_set & LOG_MASK_STANDARD)) {
+                       r = stdpath_dup_and_backup(log_f[LOG_TYPE_FILE]);
+                       if (r < 0)
+                               return r;
+               }
+       }
+
+       if (log_set & LOG_MASK_KMSG) {
+               log_f[LOG_TYPE_KMSG] = fopen("/dev/kmsg", "we");
+               if (!log_f[LOG_TYPE_KMSG])
+                       return -errno;
+
+               /* If standard output/error or log file were not set,
+                * redirect standard output/error to kmsg */
+               if (!(log_set & LOG_MASK_STANDARD) &&
+                               !(log_set & LOG_MASK_FILE)) {
+                       r = stdpath_dup_and_backup(log_f[LOG_TYPE_KMSG]);
+                       if (r < 0)
+                               return r;
+               }
+       }
+
+       return 0;
+}
+
+int log_close(void)
+{
+       enum log_type type;
+
+       for (type = 0; type < LOG_TYPE_MAX; type++) {
+               if (type == LOG_TYPE_STANDARD || !log_f[type])
+                       continue;
+
+               fclose(log_f[type]);
+               log_f[type] = NULL;
+       }
+
+       return stdpath_restore();
+}
+
+static int _log_write(
+               int level,
+               const char *file,
+               int line,
+               const char *func,
+               const char *format,
+               va_list ap)
+{
+       char buff[LINE_MAX];
+       enum log_type type;
+
+       vsnprintf(buff, LINE_MAX, format, ap);
+
+       for (type = 0; type < LOG_TYPE_MAX; type++) {
+               if (type != LOG_TYPE_STANDARD && !log_f[type])
+                       continue;
+
+               switch (type) {
+               case LOG_TYPE_STANDARD:
+                       fprintf(level <= LOG_ERR ? stderr : stdout,
+                                       "%s\n", buff);
+                       break;
+               case LOG_TYPE_FILE:
+                       fprintf(log_f[LOG_TYPE_FILE],
+                                       "%-8s: %s\n", log_priority_name[level], buff);
+                       fflush(log_f[LOG_TYPE_FILE]);
+                       break;
+               case LOG_TYPE_KMSG:
+                       fprintf(log_f[LOG_TYPE_KMSG],
+                                       "initrd: %s\n", buff);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+int log_write(
+               int level,
+               const char*file,
+               int line,
+               const char *func,
+               const char *format, ...)
+{
+       va_list ap;
+       int r;
+
+       va_start(ap, format);
+       r = _log_write(level, file, line, func, format, ap);
+       va_end(ap);
+
+       return r;
+}
+
+int log_move(const char *to)
+{
+       _cleanup_free_ char *buf = NULL;
+       FILE *w = NULL;
+       size_t len;
+       int r;
+
+       assert(to);
+
+       if (!log_f[LOG_TYPE_FILE])
+               return 0;
+
+       buf = new(char, FILEBUF);
+       if (!buf) {
+               r = -ENOMEM;
+               goto error;
+       }
+
+       w = fopen(to, "a+");
+       if (!w) {
+               r = -errno;
+               goto error;
+       }
+
+       r = fseek(log_f[LOG_TYPE_FILE], 0, SEEK_SET);
+       if (r < 0) {
+               r = -errno;
+               goto error;
+       }
+
+       r = fflush(log_f[LOG_TYPE_FILE]);
+       if (r < 0) {
+               r = -errno;
+               goto error;
+       }
+
+       while ((len = fread(buf, sizeof(char), FILEBUF, log_f[LOG_TYPE_FILE])) > 0) {
+               if (fwrite(buf, sizeof(char), len, w) != len) {
+                       r = -errno;
+                       goto error;
+               }
+       }
+
+       fclose(log_f[LOG_TYPE_FILE]);
+       log_f[LOG_TYPE_FILE] = w;
+
+       r = stdpath_dup_and_backup(log_f[LOG_TYPE_FILE]);
+       if (r < 0)
+               goto error;
+
+       return 0;
+
+error:
+       if (w)
+               fclose(w);
+
+       log_dbg("Failed to move log: %s\n", strerror(-r));
+
+       return r;
+}
+
+enum log_mask parse_log_type(const char *type)
+{
+       char *word, *state;
+       enum log_mask mask = 0;
+       size_t l;
+
+       if (!type)
+               return LOG_MASK_INVALID;
+
+       FOREACH_WORD_SEPARATOR(word, l, type, "+", state) {
+
+               if (strncaseeq(word, "standard", l))
+                       mask |= LOG_MASK_STANDARD;
+               else if (strncaseeq(word, "file", l))
+                       mask |= LOG_MASK_FILE;
+               else if (strncaseeq(word, "kmsg", l))
+                       mask |= LOG_MASK_KMSG;
+               else
+                       return LOG_MASK_INVALID;
+       }
+
+       return mask;
+}
+
+int config_parse_log_type(
+               const char *filename,
+               unsigned line,
+               const char *section,
+               const char *lvalue,
+               int ltype,
+               const char *rvalue,
+               void *data)
+{
+
+       enum log_mask *mask = data;
+
+       if (isempty(rvalue))
+               return 0;
+
+       *mask = parse_log_type(rvalue);
+
+       return *mask == LOG_MASK_INVALID ? -EINVAL : 0;
+}
diff --git a/src/shared/log.h b/src/shared/log.h
new file mode 100644 (file)
index 0000000..ce26b1e
--- /dev/null
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/syslog.h>
+#include <stdbool.h>
+
+enum log_type {
+       LOG_TYPE_INVALID = -1,
+       LOG_TYPE_STANDARD = 0,
+       LOG_TYPE_FILE,
+       LOG_TYPE_KMSG,
+       LOG_TYPE_MAX
+};
+
+enum log_mask {
+       LOG_MASK_INVALID = -1,
+       LOG_MASK_STANDARD = 1 << LOG_TYPE_STANDARD,
+       LOG_MASK_FILE     = 1 << LOG_TYPE_FILE,
+       LOG_MASK_KMSG     = 1 << LOG_TYPE_KMSG,
+};
+
+#define log_full(level, ...)                                            \
+       do {                                                            \
+               log_write((level), __FILE__, __LINE__, __func__, __VA_ARGS__); \
+       } while (0)
+
+void set_log_level(int level);
+int get_log_level(void);
+int log_open(enum log_mask log_set, const char *path);
+int log_close(void);
+int log_write(int level, const char*file, int line, const char *func, const char *format, ...);
+int log_move(const char *to);
+enum log_mask parse_log_type(const char *type);
+int config_parse_log_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+#define log_dbg(format, ...)                                            \
+       do {                                                            \
+               if (get_log_level() >= LOG_DEBUG)                       \
+               log_full(LOG_DEBUG, format, ##__VA_ARGS__);     \
+       } while (0)
+
+#define log_err(format, ...)                                            \
+       do {                                                            \
+               if (get_log_level() >= LOG_ERR)                         \
+               log_full(LOG_ERR, format, ##__VA_ARGS__);       \
+       } while (0)
+
+#define log_info(format, ...)                                           \
+       do {                                                            \
+               if (get_log_level() >= LOG_INFO)                        \
+               log_full(LOG_INFO, format, ##__VA_ARGS__);      \
+       } while (0)