diff --git a/bsp/buildroot_external/package/libubox/Config.in b/bsp/buildroot_external/package/libubox/Config.in index 3e2e8bd9..349ddd3a 100644 --- a/bsp/buildroot_external/package/libubox/Config.in +++ b/bsp/buildroot_external/package/libubox/Config.in @@ -1,6 +1,14 @@ config BR2_PACKAGE_LIBUBOX bool "libubox" - default n + depends on !BR2_STATIC_LIBS select BR2_PACKAGE_JSON_C help - New Version of the ubox library. + This library originates from the OpenWrt project to + handle the configuration file infrastructure, but can + also be used for the same purposes in projects other + than OpenWrt. + + http://nbd.name/gitweb.cgi?p=luci2/libubox.git;a=summary + +comment "libubox needs a toolchain w/ dynamic library" + depends on BR2_STATIC_LIBS diff --git a/bsp/buildroot_external/package/libubox/libubox.mk b/bsp/buildroot_external/package/libubox/libubox.mk index b0a849cc..0e8985c8 100644 --- a/bsp/buildroot_external/package/libubox/libubox.mk +++ b/bsp/buildroot_external/package/libubox/libubox.mk @@ -6,14 +6,17 @@ LIBUBOX_VERSION:= 2016-11-29 -LIBUBOX_SITE = $(TOPDIR)/../../src/3P/libubox/builders/cmake +LIBUBOX_SITE = $(TOPDIR)/../../src/3P/libubox LIBUBOX_SITE_METHOD = local +LIBUBOX_LICENSE = LGPLv2.1, GPLv2, BSD-3c, MIT LIBUBOX_INSTALL_STAGING = YES LIBUBOX_DEPENDENCIES = json-c LIBUBOX_CONF = SRC_DIR=$(TOPDIR)/../.. +LIBUBOX_CONF_OPTS +=-DBUILD_LUA=OFF + LIBUBOX_CONF_ENV = $(LIBUBOX_CONF) LIBUBOX_MAKE_ENV = $(LIBUBOX_CONF) LIBUBOX_CONF_OPTS += -DMODULE_PATH=$(TOPDIR)/../../bsp/cmake-modules -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) diff --git a/bsp/buildroot_external/package/ubox/ubox.mk b/bsp/buildroot_external/package/ubox/ubox.mk index df92ef13..7fac4258 100644 --- a/bsp/buildroot_external/package/ubox/ubox.mk +++ b/bsp/buildroot_external/package/ubox/ubox.mk @@ -6,7 +6,7 @@ UBOX_VERSION:= 2017.01.15 -UBOX_SITE = $(TOPDIR)/../../src/3P/ubox/builders/cmake +UBOX_SITE = $(TOPDIR)/../../src/3P/ubox UBOX_SITE_METHOD = local UBOX_INSTALL_STAGING = YES diff --git a/bsp/buildroot_external/package/ubus/Config.in b/bsp/buildroot_external/package/ubus/Config.in index 41250dd4..2e5a3ba2 100644 --- a/bsp/buildroot_external/package/ubus/Config.in +++ b/bsp/buildroot_external/package/ubus/Config.in @@ -2,5 +2,15 @@ config BR2_PACKAGE_UBUS bool "ubus" default n select BR2_PACKAGE_LIBUBOX + select BR2_PACKAGE_JSON_C help - Next Version of the ubus daemon programs. + IPC/RPC bus that allows communication between processes. + + It consists of few parts including a daemon (ubusd), a library + (libubus) and a command line interface (ubus). Although created + for the OpenWRT project, it can be used as a general IPC/RPC + mechanism in other projects. + + * Select BR2_PACKAGE_LUA_5_1 if you want to have Lua support. + + https://wiki.openwrt.org/doc/techref/ubus diff --git a/bsp/buildroot_external/package/ubus/ubus.mk b/bsp/buildroot_external/package/ubus/ubus.mk index a1518860..99eae702 100644 --- a/bsp/buildroot_external/package/ubus/ubus.mk +++ b/bsp/buildroot_external/package/ubus/ubus.mk @@ -6,7 +6,7 @@ UBUS_VERSION:= 2017.01.22 -UBUS_SITE = $(TOPDIR)/../../src/3P/ubus/builders/cmake +UBUS_SITE = $(TOPDIR)/../../src/3P/ubus UBUS_SITE_METHOD = local UBUS_INSTALL_STAGING = YES diff --git a/bsp/buildroot_external/package/uci/uci.mk b/bsp/buildroot_external/package/uci/uci.mk index 020630d4..841b1fdd 100644 --- a/bsp/buildroot_external/package/uci/uci.mk +++ b/bsp/buildroot_external/package/uci/uci.mk @@ -6,7 +6,7 @@ UCI_VERSION:= 2016.07.04 -UCI_SITE = $(TOPDIR)/../../src/3P/uci/builders/cmake +UCI_SITE = $(TOPDIR)/../../src/3P/uci UCI_SITE_METHOD = local UCI_INSTALL_STAGING = YES @@ -14,6 +14,8 @@ UCI_DEPENDENCIES = libubox ubus UCI_CONF = SRC_DIR=$(TOPDIR)/../.. +UCI_CONF_OPTS +=-DBUILD_LUA=OFF + UCI_CONF_ENV = $(UCI_CONF) UCI_MAKE_ENV = $(UCI_CONF) UCI_CONF_OPTS += -DMODULE_PATH=$(TOPDIR)/../../bsp/cmake-modules -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) diff --git a/projects/x86_64_domo/configs/buildroot.config b/projects/x86_64_domo/configs/buildroot.config index 7889955a..bf7e424b 100644 --- a/projects/x86_64_domo/configs/buildroot.config +++ b/projects/x86_64_domo/configs/buildroot.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Buildroot 2016.08.1-g2fc32dd-dirty Configuration +# Buildroot 2016.08.1-gb9e31fc-dirty Configuration # BR2_HAVE_DOT_CONFIG=y BR2_HOST_GCC_AT_LEAST_4_6=y @@ -811,6 +811,12 @@ BR2_PACKAGE_GAUCHE_ARCH_SUPPORTS=y # BR2_PACKAGE_JAMVM is not set # BR2_PACKAGE_JIMTCL is not set # BR2_PACKAGE_LUA is not set +# BR2_PACKAGE_LUA_5_1 is not set +# BR2_PACKAGE_LUA_5_2 is not set +# BR2_PACKAGE_LUA_5_3 is not set +# BR2_PACKAGE_LUA_EDITING_NONE is not set +# BR2_PACKAGE_LUA_READLINE is not set +# BR2_PACKAGE_LUA_LINENOISE is not set BR2_PACKAGE_LUAJIT_ARCH_SUPPORTS=y # BR2_PACKAGE_LUAJIT is not set # BR2_PACKAGE_MICROPYTHON is not set diff --git a/src/3P/libubox/builders/cmake/CMakeLists.txt b/src/3P/libubox/builders/cmake/CMakeLists.txt deleted file mode 100644 index 3e8e80dd..00000000 --- a/src/3P/libubox/builders/cmake/CMakeLists.txt +++ /dev/null @@ -1,67 +0,0 @@ -cmake_minimum_required (VERSION 3.0) - -project (libubox) - -set (CMAKE_MODULE_PATH "${MODULE_PATH}") - -set(DISABLE_TARGET_OPTIMIZATION ON) - -include (br) - -ADD_DEFINITIONS(-DJSONC) - -include_directories ($ENV{SRC_DIR}/src/3P/libubox/) - -file ( - GLOB_RECURSE - source_files - - $ENV{SRC_DIR}/src/3P/libubox/avl.c - $ENV{SRC_DIR}/src/3P/libubox/avl-cmp.c - $ENV{SRC_DIR}/src/3P/libubox/blob.c - $ENV{SRC_DIR}/src/3P/libubox/blobmsg.c - $ENV{SRC_DIR}/src/3P/libubox/uloop.c - $ENV{SRC_DIR}/src/3P/libubox/usock.c - $ENV{SRC_DIR}/src/3P/libubox/ustream.c - $ENV{SRC_DIR}/src/3P/libubox/ustream-fd.c - $ENV{SRC_DIR}/src/3P/libubox/vlist.c - $ENV{SRC_DIR}/src/3P/libubox/utils.c - $ENV{SRC_DIR}/src/3P/libubox/safe_list.c - $ENV{SRC_DIR}/src/3P/libubox/runqueue.c - $ENV{SRC_DIR}/src/3P/libubox/md5.c - $ENV{SRC_DIR}/src/3P/libubox/kvlist.c - $ENV{SRC_DIR}/src/3P/libubox/ulog.c - $ENV{SRC_DIR}/src/3Plibubox/base64.c - ) - -add_library (ubox SHARED ${source_files}) -target_link_libraries (ubox - LINK_PUBLIC - json-c - rt - pthread - ) - -target_include_directories (ubox PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) - - -file (GLOB ubox_headers $ENV{SRC_DIR}/src/3P/libubox/*.h) -install (FILES ${ubox_headers} DESTINATION include/libubox) - -add_library (json_script SHARED $ENV{SRC_DIR}/src/3P/libubox/json_script.c) -target_link_libraries (json_script ubox) - -add_library (blobmsg_json SHARED $ENV{SRC_DIR}/src/3P/libubox/blobmsg_json.c) -target_link_libraries (blobmsg_json json-c) - -add_executable (jshn $ENV{SRC_DIR}/src/3P/libubox/jshn.c) -target_link_libraries (jshn ubox blobmsg_json json-c) - -install (TARGETS ubox json_script blobmsg_json - LIBRARY DESTINATION ../lib -) - -install (TARGETS jshn RUNTIME DESTINATION bin) - -install (FILES $ENV{SRC_DIR}/src/3P/libubox/sh/jshn.sh - DESTINATION share/libubox) diff --git a/src/3P/ubox/builders/cmake/CMakeLists.txt b/src/3P/ubox/builders/cmake/CMakeLists.txt deleted file mode 100644 index 837663dc..00000000 --- a/src/3P/ubox/builders/cmake/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required (VERSION 3.0) - -project (ubox) - -ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations) - -set (CMAKE_MODULE_PATH "${MODULE_PATH}") - -set(DISABLE_TARGET_OPTIMIZATION ON) - -include (br) - -# Logd -add_executable (logd - $ENV{SRC_DIR}/src/3P/ubox/log/logd.c - $ENV{SRC_DIR}/src/3P/ubox/log/syslog.c) -target_link_libraries (logd ubox ubus) -install (TARGETS logd RUNTIME DESTINATION sbin) - -# Logread -add_executable (logread - $ENV{SRC_DIR}/src/3P/ubox/log/logread.c) -target_link_libraries (logread ubox ubus json-c blobmsg_json) -install (TARGETS logread RUNTIME DESTINATION sbin) - -# kmodloader -add_executable (kmodloader - $ENV{SRC_DIR}/src/3P/ubox/kmodloader.c) -target_link_libraries (kmodloader ubox) -install (TARGETS kmodloader RUNTIME DESTINATION ../sbin) diff --git a/src/3P/ubox/log/logd.c b/src/3P/ubox/log/logd.c new file mode 100644 index 00000000..d778909e --- /dev/null +++ b/src/3P/ubox/log/logd.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * 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. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "syslog.h" + +int debug = 0; +static struct blob_buf b; +static struct ubus_auto_conn conn; +static LIST_HEAD(clients); + +enum { + READ_LINES, + READ_STREAM, + __READ_MAX +}; + +static const struct blobmsg_policy read_policy[__READ_MAX] = { + [READ_LINES] = { .name = "lines", .type = BLOBMSG_TYPE_INT32 }, + [READ_STREAM] = { .name = "stream", .type = BLOBMSG_TYPE_BOOL }, +}; + +static const struct blobmsg_policy write_policy = + { .name = "event", .type = BLOBMSG_TYPE_STRING }; + +struct client { + struct list_head list; + + struct ustream_fd s; + int fd; +}; + +static void +client_close(struct ustream *s) +{ + struct client *cl = container_of(s, struct client, s.stream); + + list_del(&cl->list); + ustream_free(s); + close(cl->fd); + free(cl); +} + +static void client_notify_state(struct ustream *s) +{ + client_close(s); +} + +static void +log_fill_msg(struct blob_buf *b, struct log_head *l) +{ + blobmsg_add_string(b, "msg", l->data); + blobmsg_add_u32(b, "id", l->id); + blobmsg_add_u32(b, "priority", l->priority); + blobmsg_add_u32(b, "source", l->source); + blobmsg_add_u64(b, "time", l->ts.tv_sec * 1000LL); +} + +static int +read_log(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct client *cl; + struct blob_attr *tb[__READ_MAX]; + struct log_head *l; + int count = 0; + int fds[2]; + int ret; + bool stream = true; + void *c, *e; + + if (!stream) + count = 100; + + if (msg) { + blobmsg_parse(read_policy, __READ_MAX, tb, blob_data(msg), blob_len(msg)); + if (tb[READ_LINES]) + count = blobmsg_get_u32(tb[READ_LINES]); + if (tb[READ_STREAM]) + stream = blobmsg_get_bool(tb[READ_STREAM]); + } + + if (pipe(fds) == -1) { + fprintf(stderr, "logd: failed to create pipe: %s\n", strerror(errno)); + return -1; + } + + l = log_list(count, NULL); + if (stream) { + ubus_request_set_fd(ctx, req, fds[0]); + cl = calloc(1, sizeof(*cl)); + cl->s.stream.notify_state = client_notify_state; + cl->fd = fds[1]; + ustream_fd_init(&cl->s, cl->fd); + list_add(&cl->list, &clients); + while ((!tb[READ_LINES] || count) && l) { + blob_buf_init(&b, 0); + log_fill_msg(&b, l); + l = log_list(count, l); + ret = ustream_write(&cl->s.stream, (void *) b.head, blob_len(b.head) + sizeof(struct blob_attr), false); + if (ret < 0) + break; + } + } else { + blob_buf_init(&b, 0); + c = blobmsg_open_array(&b, "log"); + while ((!tb[READ_LINES] || count) && l) { + e = blobmsg_open_table(&b, NULL); + log_fill_msg(&b, l); + blobmsg_close_table(&b, e); + l = log_list(count, l); + } + blobmsg_close_array(&b, c); + ubus_send_reply(ctx, req, b.head); + } + blob_buf_free(&b); + return 0; +} + +static int +write_log(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb; + char *event; + + if (msg) { + blobmsg_parse(&write_policy, 1, &tb, blob_data(msg), blob_len(msg)); + if (tb) { + event = blobmsg_get_string(tb); + log_add(event, strlen(event) + 1, SOURCE_SYSLOG); + } + } + + return 0; +} + +static const struct ubus_method log_methods[] = { + UBUS_METHOD("read", read_log, read_policy), + { .name = "write", .handler = write_log, .policy = &write_policy, .n_policy = 1 }, +}; + +static struct ubus_object_type log_object_type = + UBUS_OBJECT_TYPE("log", log_methods); + +static struct ubus_object log_object = { + .name = "log", + .type = &log_object_type, + .methods = log_methods, + .n_methods = ARRAY_SIZE(log_methods), +}; + +void +ubus_notify_log(struct log_head *l) +{ + struct client *c; + + if (list_empty(&clients)) + return; + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "msg", l->data); + blobmsg_add_u32(&b, "id", l->id); + blobmsg_add_u32(&b, "priority", l->priority); + blobmsg_add_u32(&b, "source", l->source); + blobmsg_add_u64(&b, "time", (((__u64) l->ts.tv_sec) * 1000) + (l->ts.tv_nsec / 1000000)); + + list_for_each_entry(c, &clients, list) + ustream_write(&c->s.stream, (void *) b.head, blob_len(b.head) + sizeof(struct blob_attr), false); + + blob_buf_free(&b); +} + +static void +ubus_connect_handler(struct ubus_context *ctx) +{ + int ret; + + ret = ubus_add_object(ctx, &log_object); + if (ret) { + fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret)); + exit(1); + } + fprintf(stderr, "log: connected to ubus\n"); +} + +int +main(int argc, char **argv) +{ + int ch, log_size = 16; + + signal(SIGPIPE, SIG_IGN); + while ((ch = getopt(argc, argv, "S:")) != -1) { + switch (ch) { + case 'S': + log_size = atoi(optarg); + if (log_size < 1) + log_size = 16; + break; + } + } + log_size *= 1024; + + uloop_init(); + log_init(log_size); + conn.cb = ubus_connect_handler; + ubus_auto_connect(&conn); + uloop_run(); + log_shutdown(); + uloop_done(); + ubus_auto_shutdown(&conn); + + return 0; +} diff --git a/src/3P/ubox/log/logread.c b/src/3P/ubox/log/logread.c new file mode 100644 index 00000000..676bb82b --- /dev/null +++ b/src/3P/ubox/log/logread.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * 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. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SYSLOG_NAMES +#include + +#include +#include +#include +#include +#include "libubus.h" +#include "syslog.h" + +enum { + LOG_STDOUT, + LOG_FILE, + LOG_NET, +}; + +enum { + LOG_MSG, + LOG_ID, + LOG_PRIO, + LOG_SOURCE, + LOG_TIME, + __LOG_MAX +}; + +static const struct blobmsg_policy log_policy[] = { + [LOG_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_STRING }, + [LOG_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, + [LOG_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 }, + [LOG_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_INT32 }, + [LOG_TIME] = { .name = "time", .type = BLOBMSG_TYPE_INT64 }, +}; + +static struct uloop_timeout retry; +static struct uloop_fd sender; +static regex_t regexp_preg; +static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname, *regexp_pattern; +static int log_type = LOG_STDOUT; +static int log_size, log_udp, log_follow, log_trailer_null = 0; + +static const char* getcodetext(int value, CODE *codetable) { + CODE *i; + + if (value >= 0) + for (i = codetable; i->c_val != -1; i++) + if (i->c_val == value) + return (i->c_name); + return ""; +}; + +static void log_handle_reconnect(struct uloop_timeout *timeout) +{ + sender.fd = usock((log_udp) ? (USOCK_UDP) : (USOCK_TCP), log_ip, log_port); + if (sender.fd < 0) { + fprintf(stderr, "failed to connect: %s\n", strerror(errno)); + uloop_timeout_set(&retry, 1000); + } else { + uloop_fd_add(&sender, ULOOP_READ); + syslog(LOG_INFO, "Logread connected to %s:%s\n", log_ip, log_port); + } +} + +static void log_handle_fd(struct uloop_fd *u, unsigned int events) +{ + if (u->eof) { + uloop_fd_delete(u); + close(sender.fd); + sender.fd = -1; + uloop_timeout_set(&retry, 1000); + } +} + +static int log_notify(struct blob_attr *msg) +{ + struct blob_attr *tb[__LOG_MAX]; + struct stat s; + char buf[512]; + uint32_t p; + char *str; + time_t t; + char *c, *m; + int ret = 0; + + if (sender.fd < 0) + return 0; + + blobmsg_parse(log_policy, ARRAY_SIZE(log_policy), tb, blob_data(msg), blob_len(msg)); + if (!tb[LOG_ID] || !tb[LOG_PRIO] || !tb[LOG_SOURCE] || !tb[LOG_TIME] || !tb[LOG_MSG]) + return 1; + + if ((log_type == LOG_FILE) && log_size && (!stat(log_file, &s)) && (s.st_size > log_size)) { + char *old = malloc(strlen(log_file) + 5); + + close(sender.fd); + if (old) { + sprintf(old, "%s.old", log_file); + rename(log_file, old); + free(old); + } + sender.fd = open(log_file, O_CREAT | O_WRONLY | O_APPEND, 0600); + if (sender.fd < 0) { + fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); + exit(-1); + } + } + + m = blobmsg_get_string(tb[LOG_MSG]); + if (regexp_pattern && + regexec(®exp_preg, m, 0, NULL, 0) == REG_NOMATCH) + return 0; + t = blobmsg_get_u64(tb[LOG_TIME]) / 1000; + c = ctime(&t); + p = blobmsg_get_u32(tb[LOG_PRIO]); + c[strlen(c) - 1] = '\0'; + str = blobmsg_format_json(msg, true); + if (log_type == LOG_NET) { + int err; + + snprintf(buf, sizeof(buf), "<%u>", p); + strncat(buf, c + 4, 16); + if (hostname) { + strncat(buf, hostname, sizeof(buf) - strlen(buf) - 1); + strncat(buf, " ", sizeof(buf) - strlen(buf) - 1); + } + if (log_prefix) { + strncat(buf, log_prefix, sizeof(buf) - strlen(buf) - 1); + strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1); + } + if (blobmsg_get_u32(tb[LOG_SOURCE]) == SOURCE_KLOG) + strncat(buf, "kernel: ", sizeof(buf) - strlen(buf) - 1); + strncat(buf, m, sizeof(buf) - strlen(buf) - 1); + if (log_udp) + err = write(sender.fd, buf, strlen(buf)); + else { + size_t buflen = strlen(buf); + if (!log_trailer_null) + buf[buflen] = '\n'; + err = send(sender.fd, buf, buflen + 1, 0); + } + + if (err < 0) { + syslog(LOG_INFO, "failed to send log data to %s:%s via %s\n", + log_ip, log_port, (log_udp) ? ("udp") : ("tcp")); + uloop_fd_delete(&sender); + close(sender.fd); + sender.fd = -1; + uloop_timeout_set(&retry, 1000); + } + } else { + snprintf(buf, sizeof(buf), "%s %s.%s%s %s\n", + c, getcodetext(LOG_FAC(p) << 3, facilitynames), getcodetext(LOG_PRI(p), prioritynames), + (blobmsg_get_u32(tb[LOG_SOURCE])) ? ("") : (" kernel:"), m); + ret = write(sender.fd, buf, strlen(buf)); + } + + free(str); + if (log_type == LOG_FILE) + fsync(sender.fd); + + return ret; +} + +static int usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [options]\n" + "Options:\n" + " -s Path to ubus socket\n" + " -l Got only the last 'count' messages\n" + " -e Filter messages with a regexp\n" + " -r Stream message to a server\n" + " -F Log file\n" + " -S Log size\n" + " -p PID file\n" + " -h Add hostname to the message\n" + " -P Prefix custom text to streamed messages\n" + " -f Follow log messages\n" + " -u Use UDP as the protocol\n" + " -0 Use \\0 instead of \\n as trailer when using TCP\n" + "\n", prog); + return 1; +} + +static void logread_fd_data_cb(struct ustream *s, int bytes) +{ + while (true) { + struct blob_attr *a; + int len, cur_len; + + a = (void*) ustream_get_read_buf(s, &len); + if (len < sizeof(*a)) + break; + + cur_len = blob_len(a) + sizeof(*a); + if (len < cur_len) + break; + + log_notify(a); + ustream_consume(s, cur_len); + } + if (!log_follow) + uloop_end(); +} + +static void logread_fd_cb(struct ubus_request *req, int fd) +{ + static struct ustream_fd test_fd; + + test_fd.stream.notify_read = logread_fd_data_cb; + ustream_fd_init(&test_fd, fd); +} + +int main(int argc, char **argv) +{ + static struct ubus_request req; + struct ubus_context *ctx; + uint32_t id; + const char *ubus_socket = NULL; + int ch, ret, lines = 0; + static struct blob_buf b; + int tries = 5; + + signal(SIGPIPE, SIG_IGN); + + while ((ch = getopt(argc, argv, "u0fcs:l:r:F:p:S:P:h:e:")) != -1) { + switch (ch) { + case 'u': + log_udp = 1; + break; + case '0': + log_trailer_null = 1; + break; + case 's': + ubus_socket = optarg; + break; + case 'r': + log_ip = optarg++; + log_port = argv[optind++]; + break; + case 'F': + log_file = optarg; + break; + case 'p': + pid_file = optarg; + break; + case 'P': + log_prefix = optarg; + break; + case 'f': + log_follow = 1; + break; + case 'l': + lines = atoi(optarg); + break; + case 'S': + log_size = atoi(optarg); + if (log_size < 1) + log_size = 1; + log_size *= 1024; + break; + case 'h': + hostname = optarg; + break; + case 'e': + if (!regcomp(®exp_preg, optarg, REG_NOSUB)) { + regexp_pattern = optarg; + } + break; + default: + return usage(*argv); + } + } + uloop_init(); + + ctx = ubus_connect(ubus_socket); + if (!ctx) { + fprintf(stderr, "Failed to connect to ubus\n"); + return -1; + } + ubus_add_uloop(ctx); + + /* ugly ugly ugly ... we need a real reconnect logic */ + do { + ret = ubus_lookup_id(ctx, "log", &id); + if (ret) { + fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret)); + sleep(1); + continue; + } + + blob_buf_init(&b, 0); + blobmsg_add_u8(&b, "stream", 1); + if (lines) + blobmsg_add_u32(&b, "lines", lines); + else if (log_follow) + blobmsg_add_u32(&b, "lines", 0); + if (log_follow) { + if (pid_file) { + FILE *fp = fopen(pid_file, "w+"); + if (fp) { + fprintf(fp, "%d", getpid()); + fclose(fp); + } + } + } + + if (log_ip && log_port) { + openlog("logread", LOG_PID, LOG_DAEMON); + log_type = LOG_NET; + sender.cb = log_handle_fd; + retry.cb = log_handle_reconnect; + uloop_timeout_set(&retry, 1000); + } else if (log_file) { + log_type = LOG_FILE; + sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600); + if (sender.fd < 0) { + fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); + exit(-1); + } + } else { + sender.fd = STDOUT_FILENO; + } + + ubus_invoke_async(ctx, id, "read", b.head, &req); + req.fd_cb = logread_fd_cb; + ubus_complete_request_async(ctx, &req); + + uloop_run(); + ubus_free(ctx); + uloop_done(); + + } while (ret && tries--); + + return ret; +} diff --git a/src/3P/ubox/log/syslog.c b/src/3P/ubox/log/syslog.c new file mode 100644 index 00000000..ac4f1ae9 --- /dev/null +++ b/src/3P/ubox/log/syslog.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * 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. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "syslog.h" + +#define LOG_DEFAULT_SIZE (16 * 1024) +#define LOG_DEFAULT_SOCKET "/dev/log" +#define LOG_LINE_LEN 256 +#define SYSLOG_PADDING 16 + +#define KLOG_DEFAULT_PROC "/proc/kmsg" + +#define PAD(x) (x % 4) ? (((x) - (x % 4)) + 4) : (x) + +static char *log_dev = LOG_DEFAULT_SOCKET; +static int log_size = LOG_DEFAULT_SIZE; +static struct log_head *log, *log_end, *oldest, *newest; +static int current_id = 0; +static regex_t pat_prio; +static regex_t pat_tstamp; + +static struct log_head* +log_next(struct log_head *h, int size) +{ + struct log_head *n = (struct log_head *) &h->data[PAD(sizeof(struct log_head) + size)]; + + return (n >= log_end) ? (log) : (n); +} + +void +log_add(char *buf, int size, int source) +{ + regmatch_t matches[4]; + struct log_head *next; + int priority = 0; + int ret; + + /* bounce out if we don't have init'ed yet (regmatch etc will blow) */ + if (!log) { + fprintf(stderr, "%s", buf); + return; + } + + /* strip trailing newline */ + if (buf[size - 2] == '\n') { + buf[size - 2] = '\0'; + size -= 1; + } + + /* strip the priority */ + ret = regexec(&pat_prio, buf, 3, matches, 0); + if (!ret) { + priority = atoi(&buf[matches[1].rm_so]); + size -= matches[2].rm_so; + buf += matches[2].rm_so; + } + +#if 0 + /* strip kernel timestamp */ + ret = regexec(&pat_tstamp,buf, 4, matches, 0); + if ((source == SOURCE_KLOG) && !ret) { + size -= matches[3].rm_so; + buf += matches[3].rm_so; + } +#endif + + /* strip syslog timestamp */ + if ((source == SOURCE_SYSLOG) && (size > SYSLOG_PADDING) && (buf[SYSLOG_PADDING - 1] == ' ')) { + size -= SYSLOG_PADDING; + buf += SYSLOG_PADDING; + } + + //fprintf(stderr, "-> %d - %s\n", priority, buf); + + /* find new oldest entry */ + next = log_next(newest, size); + if (next > newest) { + while ((oldest > newest) && (oldest <= next) && (oldest != log)) + oldest = log_next(oldest, oldest->size); + } else { + //fprintf(stderr, "Log wrap\n"); + newest->size = 0; + next = log_next(log, size); + for (oldest = log; oldest <= next; oldest = log_next(oldest, oldest->size)) + ; + newest = log; + } + + /* add the log message */ + newest->size = size; + newest->id = current_id++; + newest->priority = priority; + newest->source = source; + clock_gettime(CLOCK_REALTIME, &newest->ts); + strcpy(newest->data, buf); + + ubus_notify_log(newest); + + newest = next; +} + +static void +slog_cb(struct ustream *s, int bytes) +{ + struct ustream_buf *buf = s->r.head; + char *str; + int len; + + do { + str = ustream_get_read_buf(s, NULL); + if (!str) + break; + len = strlen(buf->data); + if (!len) { + bytes -= 1; + ustream_consume(s, 1); + continue; + } + log_add(buf->data, len + 1, SOURCE_SYSLOG); + ustream_consume(s, len); + bytes -= len; + } while (bytes > 0); +} + +static void +klog_cb(struct ustream *s, int bytes) +{ + struct ustream_buf *buf = s->r.head; + char *newline, *str; + int len; + + do { + str = ustream_get_read_buf(s, NULL); + if (!str) + break; + newline = strchr(buf->data, '\n'); + if (!newline) + break; + *newline = 0; + len = newline + 1 - str; + log_add(buf->data, len, SOURCE_KLOG); + ustream_consume(s, len); + } while (1); +} + +struct ustream_fd slog = { + .stream.string_data = true, + .stream.notify_read = slog_cb, +}; + +struct ustream_fd klog = { + .stream.string_data = true, + .stream.notify_read = klog_cb, +}; + +static int +klog_open(void) +{ + int fd; + + fd = open(KLOG_DEFAULT_PROC, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + fprintf(stderr, "Failed to open %s\n", KLOG_DEFAULT_PROC); + return -1; + } + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + ustream_fd_init(&klog, fd); + return 0; +} + +static int +syslog_open(void) +{ + int fd; + + unlink(log_dev); + fd = usock(USOCK_UNIX | USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK, log_dev, NULL); + if (fd < 0) { + fprintf(stderr,"Failed to open %s\n", log_dev); + return -1; + } + chmod(log_dev, 0666); + ustream_fd_init(&slog, fd); + return 0; +} + +struct log_head* +log_list(int count, struct log_head *h) +{ + unsigned int min = count; + + if (count) + min = (count < current_id) ? (current_id - count) : (0); + if (!h && oldest->id >= min) + return oldest; + if (!h) + h = oldest; + + while (h != newest) { + h = log_next(h, h->size); + if (!h->size && (h > newest)) + h = log; + if (h->id >= min && (h != newest)) + return h; + } + + return NULL; +} + +int +log_buffer_init(int size) +{ + struct log_head *_log = malloc(size); + + if (!_log) { + fprintf(stderr, "Failed to initialize log buffer with size %d\n", log_size); + return -1; + } + + memset(_log, 0, size); + + if (log && ((log_size + sizeof(struct log_head)) < size)) { + struct log_head *start = _log; + struct log_head *end = ((void*) _log) + size; + struct log_head *l; + + l = log_list(0, NULL); + while ((start < end) && l && l->size) { + memcpy(start, l, PAD(sizeof(struct log_head) + l->size)); + start = (struct log_head *) &l->data[PAD(l->size)]; + l = log_list(0, l); + } + free(log); + newest = start; + newest->size = 0; + oldest = log = _log; + log_end = ((void*) log) + size; + } else { + oldest = newest = log = _log; + log_end = ((void*) log) + size; + } + log_size = size; + + return 0; +} + +void +log_init(int _log_size) +{ + if (_log_size > 0) + log_size = _log_size; + + regcomp(&pat_prio, "^<([0-9]*)>(.*)", REG_EXTENDED); + regcomp(&pat_tstamp, "^\[[ 0]*([0-9]*).([0-9]*)] (.*)", REG_EXTENDED); + + if (log_buffer_init(log_size)) { + fprintf(stderr, "Failed to allocate log memory\n"); + exit(-1); + } + + syslog_open(); + klog_open(); + openlog("sysinit", LOG_CONS, LOG_DAEMON); +} + +void +log_shutdown(void) +{ + ustream_free(&slog.stream); + ustream_free(&klog.stream); + close(slog.fd.fd); + close(klog.fd.fd); + free(log); + regfree(&pat_prio); + regfree(&pat_tstamp); +} diff --git a/src/3P/ubox/log/syslog.h b/src/3P/ubox/log/syslog.h new file mode 100644 index 00000000..81a039f3 --- /dev/null +++ b/src/3P/ubox/log/syslog.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * 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. + */ + +#ifndef __SYSLOG_H +#define __SYSLOG_H + +enum { + SOURCE_KLOG = 0, + SOURCE_SYSLOG = 1, + SOURCE_INTERNAL = 2, + SOURCE_ANY = 0xff, +}; + +struct log_head { + unsigned int size; + unsigned int id; + int priority; + int source; + struct timespec ts; + char data[]; +}; + +void log_init(int log_size); +void log_shutdown(void); + +typedef void (*log_list_cb)(struct log_head *h); +struct log_head* log_list(int count, struct log_head *h); +int log_buffer_init(int size); +void log_add(char *buf, int size, int source); +void ubus_notify_log(struct log_head *l); + +#endif diff --git a/src/3P/ubus/builders/cmake/CMakeLists.txt b/src/3P/ubus/builders/cmake/CMakeLists.txt deleted file mode 100644 index 5ca59a6c..00000000 --- a/src/3P/ubus/builders/cmake/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -cmake_minimum_required(VERSION 3.0) - -project (ubus) - -set (CMAKE_MODULE_PATH "${MODULE_PATH}") - -set(DISABLE_TARGET_OPTIMIZATION ON) - -include (br) - -include_directories ($ENV{SRC_DIR}/src/3P/ubus) - -ADD_DEFINITIONS (-Werror --std=gnu99 -Wmissing-declarations -D_GNU_SOURCE) - -ADD_DEFINITIONS (-DUBUS_MAX_MSGLEN=1048576) -ADD_DEFINITIONS (-DUBUS_UNIX_SOCKET="/tmp/ubus.sock") - -# ubus library -file ( - GLOB_RECURSE - source_files - - $ENV{SRC_DIR}/src/3P/ubus/libubus.c - $ENV{SRC_DIR}/src/3P/ubus/libubus-io.c - $ENV{SRC_DIR}/src/3P/ubus/libubus-obj.c - $ENV{SRC_DIR}/src/3P/ubus/libubus-sub.c - $ENV{SRC_DIR}/src/3P/ubus/libubus-req.c - $ENV{SRC_DIR}/src/3P/ubus/libubus-acl.c - ) - -# Library -add_library (ubus SHARED ${source_files}) -target_link_libraries (ubus LINK_PUBLIC ubox) - -target_include_directories (ubus PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) - -install (TARGETS ubus LIBRARY DESTINATION local/lib) - -file (GLOB ubus_headers $ENV{SRC_DIR}/src/3P/ubus/*.h) -install (FILES ${ubus_headers} DESTINATION include/ubus) - - -# Daemon ubusd -file ( - GLOB_RECURSE - ubusd_source_files - - $ENV{SRC_DIR}/src/3P/ubus/ubusd.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_id.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_obj.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_proto.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_event.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_acl.c - $ENV{SRC_DIR}/src/3P/ubus/ubusd_monitor.c - ) - -# Daemon ubusd -add_executable (ubusd ${ubusd_source_files}) -target_link_libraries (ubusd ubox blobmsg_json) - -install (TARGETS ubusd RUNTIME DESTINATION ../sbin) - -# cmd line tool. -add_executable (ucli $ENV{SRC_DIR}/src/3P/ubus/cli.c) -set_target_properties (ucli PROPERTIES OUTPUT_NAME ubus) -target_link_libraries (ucli LINK_PUBLIC ubox ubus blobmsg_json) - -install (TARGETS ucli RUNTIME DESTINATION bin) \ No newline at end of file diff --git a/src/3P/uci/builders/cmake/CMakeLists.txt b/src/3P/uci/builders/cmake/CMakeLists.txt deleted file mode 100644 index 8eb0b0df..00000000 --- a/src/3P/uci/builders/cmake/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -cmake_minimum_required(VERSION 3.0) - -project (uci) - -set (CMAKE_MODULE_PATH "${MODULE_PATH}") - -set(DISABLE_TARGET_OPTIMIZATION ON) - -include (br) - -include_directories ($ENV{SRC_DIR}/src/3P/uci) - -ADD_DEFINITIONS (-Werror --std=gnu99 -Wmissing-declarations) - -CONFIGURE_FILE ($ENV{SRC_DIR}/src/3P/uci/uci_config.h.in $ENV{SRC_DIR}/src/3P/uci/uci_config.h ) - -# uci library -file ( - GLOB_RECURSE - lib_source_files - - $ENV{SRC_DIR}/src/3P/uci/libuci.c - $ENV{SRC_DIR}/src/3P/uci/file.c - $ENV{SRC_DIR}/src/3P/uci/util.c - $ENV{SRC_DIR}/src/3P/uci/delta.c - $ENV{SRC_DIR}/src/3P/uci/parse.c - $ENV{SRC_DIR}/src/3P/uci/blob.c -) - -# Library -add_library (uci SHARED ${lib_source_files}) -target_link_libraries (uci LINK_PUBLIC ubox) - -target_include_directories (uci PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) - -install (TARGETS uci LIBRARY DESTINATION local/lib) - -file (GLOB uci_headers $ENV{SRC_DIR}/src/3P/uci/*.h) -install (FILES ${uci_headers} DESTINATION include/uci) - - -# cmd line tool. -add_executable (uci_cli $ENV{SRC_DIR}/src/3P/uci/cli.c) -set_target_properties (uci_cli PROPERTIES OUTPUT_NAME uci) -target_link_libraries (uci_cli LINK_PUBLIC uci ubox blobmsg_json) - -install (TARGETS uci_cli RUNTIME DESTINATION ../sbin) \ No newline at end of file