Add toolchain and mbtk source

Change-Id: Ie12546301367ea59240bf23d5e184ad7e36e40b3
diff --git a/mbtk/mbtk_logd/Makefile b/mbtk/mbtk_logd/Makefile
new file mode 100755
index 0000000..562a644
--- /dev/null
+++ b/mbtk/mbtk_logd/Makefile
@@ -0,0 +1,40 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_logd
+
+INC_DIR += -I$(BUILD_ROOT)
+	
+LIB_DIR +=
+
+LIBS += -lubus -lubox -ljson-c -lblobmsg_json
+
+CFLAGS +=
+
+DEFINE +=
+
+MY_FILES_PATH:=$(LOCAL_PATH)
+#ifeq ($(CONFIG_MBTK_QL_SUPPORT),y)
+#MY_FILES_PATH += $(LOCAL_PATH)/ql
+#endif
+
+#ifeq ($(CONFIG_MBTK_PLATFORM),linux)
+#MY_FILES_PATH += $(LOCAL_PATH)/platform/linux
+#endif
+
+MY_FILES_SUFFIX:=%.c %.cpp
+My_All_Files := $(foreach src_path,$(MY_FILES_PATH), $(shell find "$(src_path)" -type f))
+MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(My_All_Files))
+MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)
+LOCAL_SRC_FILES += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/bin/mbtk_logd
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
diff --git a/mbtk/mbtk_logd/alog_read.c b/mbtk/mbtk_logd/alog_read.c
new file mode 100755
index 0000000..33f227f
--- /dev/null
+++ b/mbtk/mbtk_logd/alog_read.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define  ALOG_DEV "/dev/log_radio"
+
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+typedef struct AndroidLogEntry_t {
+    time_t tv_sec;
+    long tv_nsec;
+    android_LogPriority priority;
+    int32_t pid;
+    int32_t tid;
+    const char * tag;
+    size_t messageLen;
+    const char * message;
+} AndroidLogEntry;
+
+static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry *config = NULL;
+static char tmp_log[48] = {0};
+
+void hex_print(char* buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        printf("%x ", buf[i]);
+    }
+}
+
+static char filterPriToChar(android_LogPriority pri)
+{
+    switch (pri) {
+        case ANDROID_LOG_VERBOSE:
+            return 'V';
+        case ANDROID_LOG_DEBUG:
+            return 'D';
+        case ANDROID_LOG_INFO:
+            return 'I';
+        case ANDROID_LOG_WARN:
+            return 'W';
+        case ANDROID_LOG_ERROR:
+            return 'E';
+        case ANDROID_LOG_FATAL:
+            return 'F';
+        case ANDROID_LOG_SILENT:
+            return 'S';
+
+        case ANDROID_LOG_DEFAULT:
+        case ANDROID_LOG_UNKNOWN:
+        default:
+            return '?';
+    }
+}
+
+static android_LogPriority filterCharToPri(char c)
+{
+    switch (c) {
+        case 'v':
+            return ANDROID_LOG_VERBOSE;
+        case 'd':
+            return ANDROID_LOG_DEBUG;
+        case 'i':
+            return ANDROID_LOG_INFO;
+        case 'w':
+            return ANDROID_LOG_WARN;
+        case 'e':
+            return ANDROID_LOG_ERROR;
+        case 'f':
+            return ANDROID_LOG_FATAL;
+        case 's':
+            return ANDROID_LOG_SILENT;
+        case '*':
+        default:
+            return ANDROID_LOG_VERBOSE;
+    }
+}
+
+int fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        int p = filterCharToPri(_filter->priority);
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri < p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int alog_process(char* data, int len, AndroidLogEntry *entry)
+{
+    int i, n = 0;
+    int tmp_len;
+
+    for (i = 0; i < len;) {
+        if (data[i] == '\0') {
+            i += 1;
+        } else {
+            switch (n) {
+                case 0: {
+                    // printf("%d - %d: %x\n", i, tmp_len, data[i]);
+                    i++;
+                    break;
+                }
+                case 1: {
+                    int* pid = (int*)&data[i];
+                    entry->pid = *pid;
+                    // printf("%d pid: %d\n", i, entry->pid);
+                    i += 4;
+                    break;
+                }
+                case 2: {
+                    int* tid = (int*)&data[i];
+                    entry->tid = *tid;
+                    // printf("%d tid: %d\n", i, entry->tid);
+                    i += 4;
+                    break;
+                }
+                case 3: {
+                    // printf("%d - %d: %x %x %x %x\n", i, tmp_len, data[i], data[i + 1], data[i + 2], data[i + 3]);
+                    time_t* _t = (time_t*)&data[i];
+                    entry->tv_sec = *_t;
+                    i += 8;
+                    break;
+                }
+                case 4: {
+                    entry->priority = data[i];
+                    entry->tag = &data[i + 1];
+                    i += strlen(&data[i]);
+                    break;
+                }
+                //* format: <priority:1><tag:N>\0<message:N>\0
+                case 5: {
+                    entry->message = &data[i];
+                    entry->messageLen = strlen(&data[i]);
+                    i += entry->messageLen;
+                    break;
+                }
+                default:
+                    printf("process error \n");
+                    break;
+            }
+            n++;
+        }
+    }
+    return 0;
+}
+
+int android_log_printLogLine(
+    int fd,
+    struct file_list_t *_file_list,
+    const AndroidLogEntry *entry)
+{
+    char priChar;
+    char timeBuf[32];
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+	struct stat s;
+    char * ret = NULL;
+
+	if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+		if (fd_new < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+			exit(-1);
+        }
+	}
+
+    if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+        return -1;
+    }
+
+    priChar = filterPriToChar(entry->priority);
+    struct tm* ptm = localtime(&entry->tv_sec);
+    strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer),
+    "%s %c/%s (%d): %s\n", timeBuf, priChar, entry->tag, entry->pid, entry->message);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+void* alog_thread(void* argv)
+{
+    int dev_fd, ret;
+    int log_fd;
+    AndroidLogEntry entry;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv)
+        return NULL;
+
+    dev_fd = open(ALOG_DEV, O_RDONLY, 0600);
+    if (dev_fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", ALOG_DEV, strerror(errno));
+        exit(-1);
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+
+    printf("android log start...\n");
+    while (1) {
+        ret = read(dev_fd, buf, sizeof(buf));
+        if (ret < 0) {
+            printf("read error\n");
+            break;
+        }
+        alog_process(buf, ret, &entry);
+        android_log_printLogLine(log_fd, &file_list, &entry);
+        memset(buf, 0, sizeof(buf));
+    }
+    close(dev_fd);
+    close(log_fd);
+
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+	return NULL;
+}
diff --git a/mbtk/mbtk_logd/common.c b/mbtk/mbtk_logd/common.c
new file mode 100755
index 0000000..1e293b6
--- /dev/null
+++ b/mbtk/mbtk_logd/common.c
@@ -0,0 +1,282 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include "log_config.h"
+
+/* 文件大小和修改时间 */
+static int get_file_size_time(const char *filename)
+{
+	struct stat statbuf;
+	/* 判断未打开文件 */
+	if(stat(filename,&statbuf)==-1)
+	{
+		printf("Get stat on %s Error: %s\n", filename, strerror(errno));
+		return(-1);
+	}
+	if(S_ISDIR(statbuf.st_mode)) // 目录
+		return(1);
+	if(S_ISREG(statbuf.st_mode)) // 文件
+		printf("%s size: %ld bytes\tmodified at %s", filename, statbuf.st_size, ctime(&statbuf.st_mtime));
+	return(0);
+}
+
+int __main(int argc,char **argv)
+{
+	DIR *dirp;
+	struct dirent *direntp;
+	int stats;
+
+	if(argc!=2)
+	{
+		printf("Usage: %s filename\n\a", argv[0]);
+		exit(1);
+	}
+
+	if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1)) // 文件或出现错误
+		exit(1);
+
+	/* 打开目录 */
+	if((dirp=opendir(argv[1]))==NULL)
+	{
+		printf("Open Directory %s Error: %s\n", argv[1], strerror(errno));
+		exit(1);
+	}
+
+	/* 返回目录中文件大小和修改时间 */
+	while((direntp=readdir(dirp))!=NULL)
+	{
+		/* 给文件或目录名添加路径:argv[1]+"/"+direntp->d_name */
+		char dirbuf[512];
+		memset(dirbuf,0,sizeof(dirbuf));
+		strcpy(dirbuf,argv[1]);
+		strcat(dirbuf,"/");
+		strcat(dirbuf,direntp->d_name);
+		if(get_file_size_time(dirbuf)==-1) break;
+	}
+
+	closedir(dirp);
+	exit(1);
+}
+// 从后往前找
+char *strstr_tail(const char *dst, const char *src)
+{
+    if(NULL == dst || NULL == src)
+        return NULL;
+    const char *pdst = dst;
+    const char *psrc = src;
+    char *tmp = NULL ;
+    while (*pdst)                          //因为要从后向前找,则首先让pdst指向'\0'
+    {
+       pdst++;
+    }
+
+    while (pdst >= dst )                     //当pdst大于dst则表明dst这个字符串还没有找完
+    {
+        if (tmp=(char *)strstr(pdst, psrc = src))  //使用strstr帮助寻找,找到保存到tmp
+        return tmp;
+
+        pdst--;
+     }
+
+     return NULL ;
+}
+
+char* strcpy_malloc(char* src)
+{
+    if (NULL == src || 0 == strlen(src)) {
+        return NULL;
+    }
+    int len = strlen(src);
+    char* temp = malloc(len + 1);
+    if (NULL == temp) {
+        return NULL;
+    }
+    memset(temp, 0, len + 1);
+    strcpy(temp, src);
+
+    return temp;
+}
+
+int get_time (char *out_time)
+{
+    time_t rawtime;
+    struct tm *info;
+    char buffer[16] = {0};
+
+    time( &rawtime );
+    info = localtime(&rawtime);
+    strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S \n", info);
+    if(out_time)
+        memcpy(out_time, &buffer[2], 12);
+
+    return(0);
+}
+
+int tcp_connect(char* ip, int port)
+{
+    int sockfd;
+    struct hostent* he;
+    struct sockaddr_in server;
+
+    he = gethostbyname(ip);
+
+    if (he == NULL) {
+        printf("gethostbyname error\n");
+        exit(1);
+    }
+
+    sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+    if (sockfd == -1) {
+        printf("socket error\n");
+        exit(1);
+    }
+
+    bzero(&server, sizeof(server));
+    server.sin_family = AF_INET;
+    server.sin_port = htons(port);
+    server.sin_addr = *((struct in_addr*)he->h_addr);
+
+    if (connect(sockfd, (struct sockaddr*)&server, sizeof(server)) == -1) {
+        printf("connect error\n");
+        exit(1);
+    }
+
+    return sockfd;
+}
+int movefile(char *src, char *dst)
+{
+    if (strcmp(src, dst) == 0)
+    {
+        printf("Destination file name and source file name can't be the same!");
+        return -1;
+    }
+    FILE *fsrc = fopen(src, "rb"); //一定要“rb”否则复制的文件有时会不能使用
+    FILE *fdst = fopen(dst, "wb"); //一定要“wb”否则复制的文件有时会不能使用
+    int buflen = 1024;
+    char buf[1024];
+    int nread = 0;
+    while ((nread = fread(buf, 1, buflen, fsrc)) > 0) //最好把读文件的代码放这里
+    {
+        fwrite(buf, 1, nread, fdst);
+    }
+
+    fclose(fsrc);
+    fsrc = NULL;
+    fclose(fdst);
+    fdst = NULL;
+    remove(src);//删除源文件
+
+    return 0;
+}
+/**
+ * @brief      get_rotate_file
+ *
+ * @details    转移log文件
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int get_rotate_file(int fd, char *base_file, struct file_list_t *_file_list)
+{
+    char _time[16] = {0};
+    int num = 0;
+    char tmp_buf[48] = {0};
+    char *current_file = _file_list->file[_file_list->current];
+    int len = strlen(base_file);
+    char *old = malloc(len + 20);
+    int rotate_file_count_max;
+
+    if(_file_list->total == -1 || _file_list->total == 0 || _file_list->total > ROTATE_FILE_COUNT_MAX)
+        rotate_file_count_max = ROTATE_FILE_COUNT_MAX;
+    else
+        rotate_file_count_max = _file_list->total;
+
+
+    if(0 == _file_list->current && NULL == current_file)
+        _file_list->current = rotate_file_count_max - 1;
+    if(NULL == old)
+    {
+        fprintf(stderr, "failed to malloc %s\n", strerror(errno));
+        exit(-1);
+    }
+    close(fd);
+    sprintf(tmp_buf, "/tmp/log%s", strstr_tail(base_file, "/"));
+    get_time(_time);
+    sprintf(old, "%s.%s", base_file, _time);
+    if (current_file && strstr(current_file, old)) {
+        int tmp_len = strlen(current_file);
+        //  以时间命名的文件是否已经存在
+        if(current_file[tmp_len - 3] == '.'){
+            num = atoi(&current_file[tmp_len - 2]);
+            num++;
+            sprintf(old, "%s.%02d", old, num);
+        }else{
+            sprintf(old, "%s.%02d", old, num);
+        }
+    }
+    if (movefile(tmp_buf, old) != 0){
+        printf("%s %d: Renamed error ,%s to %s.\n", __FUNCTION__, __LINE__, tmp_buf, old);
+    }
+    _file_list->current++;
+    // ringbuf
+    if(_file_list->current > (rotate_file_count_max - 1))
+    {
+        _file_list->current = 0;
+    }
+    // 如果之前已经存在,先释放之前存放的资源
+    if(_file_list->file[_file_list->current])
+    {
+        // printf("%s %d: remove %s\n", __FUNCTION__, __LINE__, _file_list->file[_file_list->current]);
+        // 如果 不限制文件数目,则不删除文件
+        if(_file_list->total != -1)
+            unlink(_file_list->file[_file_list->current]);
+        free(_file_list->file[_file_list->current]);
+    }
+    // 将文件名保存下来
+    _file_list->file[_file_list->current] = strdup(old);
+    free(old);
+    int fd_new = open(tmp_buf, O_CREAT | O_WRONLY | O_APPEND, 0600);
+    if (fd_new < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", tmp_buf, strerror(errno));
+        exit(-1);
+    }
+
+    return fd_new;
+}
+
+#if 0
+void get_rotate_file_test()
+{
+    struct file_list_t file_list;
+    int i;
+    char *test_path = "/tmp/log/m_log.txt";
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = 3;
+
+    int fd = open(test_path, O_CREAT | O_WRONLY | O_APPEND, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", test_path, strerror(errno));
+        exit(-1);
+    }
+    write(fd, "test1111", 8);
+    for (i = 0; i < 6; ++i) {
+        // sleep(1);
+        fd = get_rotate_file(fd, test_path, &file_list);
+        write(fd, "test2222", 8);
+    }
+    close(fd);
+}
+#endif
diff --git a/mbtk/mbtk_logd/common_read.c b/mbtk/mbtk_logd/common_read.c
new file mode 100755
index 0000000..90f2f7f
--- /dev/null
+++ b/mbtk/mbtk_logd/common_read.c
@@ -0,0 +1,146 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define  ALOG_DEV "/dev/log_radio"
+
+static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry *config = NULL;
+static char tmp_log[48] = {0};
+
+
+static int fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        // _filter->priority
+        // 获取 筛选的等级 p
+        int p = 0;
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri < p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int common_log_print(
+    int fd,
+    struct file_list_t *_file_list,
+    char *entry)
+{
+    char priChar;
+    char timeBuf[32];
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+	struct stat s;
+	time_t timetemp; // 定义一个时间结构体变量
+    char * ret = NULL;
+
+	if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+		if (fd_new < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+			exit(-1);
+        }
+	}
+
+    // if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    // {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+    //     return -1;
+    // }
+	time(&timetemp); // 获得时间参数
+    struct tm* ptm = localtime(&timetemp);
+    strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer),
+    "%s : %s\n", timeBuf, entry);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+void* common_log_thread(void* argv)
+{
+    int dev_fd, ret;
+    int log_fd;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv || NULL == config->name)
+        return NULL;
+
+    dev_fd = open(config->name, O_RDONLY, 0600);
+    if (dev_fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", config->name, strerror(errno));
+        exit(-1);
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+
+    printf("uart log start...\n");
+    while (1) {
+        ret = read(dev_fd, buf, sizeof(buf));
+        if (ret < 0) {
+            printf("read error\n");
+            break;
+        }
+        // common_log_process(buf, ret, &entry);
+        common_log_print(log_fd, &file_list, buf);
+        memset(buf, 0, sizeof(buf));
+    }
+    close(dev_fd);
+    close(log_fd);
+
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+	return NULL;
+}
diff --git a/mbtk/mbtk_logd/log_config.h b/mbtk/mbtk_logd/log_config.h
new file mode 100755
index 0000000..c37ce24
--- /dev/null
+++ b/mbtk/mbtk_logd/log_config.h
@@ -0,0 +1,41 @@
+#ifndef _LOG_CONFIG_H
+#define _LOG_CONFIG_H
+
+
+#define LOG_CONFIG_PATH     "/etc/mbtk/mbtk_log.json"
+
+#define ROTATE_FILE_COUNT_MAX    10
+
+struct filter_list_t {
+    char priority;
+    char *tag;
+    struct filter_list_t *next;
+};
+
+struct file_list_t {
+    int total;
+    int current;
+    char *base_file;
+    char *file[ROTATE_FILE_COUNT_MAX];
+};
+
+typedef struct log_config_entry_t {
+    int enable;
+    char *name;
+    int send_fd;
+    char *out_path;
+    char *ip;
+    char *port;
+    int rotate_file_size;
+    int rotate_file_count;
+    int32_t log_format;
+    struct filter_list_t *filter_list;
+} log_config_entry;
+
+int get_rotate_file(int fd, char *base_file, struct file_list_t *_file_list);
+extern void* alog_thread(void* argv);
+extern void* syslog_main(void* argv);
+extern void* socket_log_thread(void* argv);
+extern void* common_log_thread(void* argv);
+
+#endif // _LOG_CONFIG_H
diff --git a/mbtk/mbtk_logd/main.c b/mbtk/mbtk_logd/main.c
new file mode 100755
index 0000000..25dbdb1
--- /dev/null
+++ b/mbtk/mbtk_logd/main.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "json/json.h"
+#include "json/printbuf.h"
+#include "log_config.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+#define mbtk_log(...)                    printf(__VA_ARGS__)
+#else
+#define mbtk_log(...)
+#endif
+
+static void handler_free(log_config_entry* listdata)
+{
+    int i, n;
+    struct filter_list_t* _filter_list = NULL;
+    log_config_entry* entry;
+
+    for (i = 0; i < 5; i++) {
+        entry = listdata + i;
+        if (entry->name) {
+            free(entry->name);
+            if (entry->out_path) {
+                free(entry->out_path);
+            }
+            if (entry->ip) {
+                free(entry->ip);
+            }
+            _filter_list = entry->filter_list;
+            for (n = 0; n < 10; n++) {
+                printf("%s %d: malloc %x!\n", __FUNCTION__, __LINE__, _filter_list);
+                if (_filter_list) {
+                    printf("%s %d: malloc %x!\n", __FUNCTION__, __LINE__, _filter_list->next);
+                    if (_filter_list->tag) {
+                        free(_filter_list->tag);
+                    }
+                    free(_filter_list);
+                    _filter_list = _filter_list->next;
+                } else {
+                    break;
+                }
+            }
+        } else {
+            break;
+        }
+    }
+}
+
+int parse_config(log_config_entry* listdata)
+{
+    json_object* jsonobj = NULL;
+    json_object* tmpjson = NULL;
+    json_object* datajson = NULL;
+    json_object* listjson = NULL;
+    json_object* fileterjson = NULL;
+    json_object* fileter_listjson = NULL;
+    log_config_entry* entry;
+    int i, n, ret;
+    char* cmdval = NULL;
+
+    jsonobj = json_object_from_file(LOG_CONFIG_PATH);
+    if (NULL == jsonobj) {
+        printf("Can't open config file: %s\n", LOG_CONFIG_PATH);
+        return -1;
+    }
+    ret = json_object_object_get_ex(jsonobj, "logd", &tmpjson);
+    if (!ret) {
+        printf("get jsondata error ...\n");
+    }
+
+    if (NULL == tmpjson) {
+        printf("the tmpjson : [%s]\n", json_object_to_json_string(tmpjson));
+    }
+    /**获取total***/
+    cmdval = json_object_get_string(tmpjson);
+    printf("logd enable : %s\n", cmdval);
+    json_object_put(tmpjson);
+    /***获取data***/
+    json_object_object_get_ex(jsonobj, "buffer_list", &tmpjson);
+    for (i = 0 ; i < 5; i++) {
+        struct filter_list_t* _filter_list = NULL;
+        struct filter_list_t* tmp_filter_list = NULL;
+        datajson = json_object_array_get_idx(tmpjson, i);
+        if (NULL == datajson) {
+            mbtk_log("the datajson exit\n");
+            break;
+        }
+        entry = listdata + i;
+        json_object_object_get_ex(datajson, "enable", &listjson);
+        entry->enable = json_object_get_int(listjson);
+        mbtk_log("enable: %d\n", entry->enable);
+
+        json_object_object_get_ex(datajson, "name", &listjson);
+        entry->name = strdup(json_object_get_string(listjson));
+        mbtk_log("cmdval: %x, %s\n", entry->name, entry->name);
+
+        json_object_object_get_ex(datajson, "log_file", &listjson);
+        entry->out_path = strdup(json_object_get_string(listjson));
+        mbtk_log("cmdval: %s\n", entry->out_path);
+
+        json_object_object_get_ex(datajson, "log_stream", &listjson);
+        if (listjson) {
+            entry->ip = strdup(json_object_get_string(listjson));
+            cmdval = strstr(entry->ip, ":");
+            if (cmdval) {
+                entry->port = &cmdval[1];
+                cmdval[0] = 0;
+                mbtk_log("cmdval: %s [%s]\n", entry->ip, entry->port);
+            } else {
+                printf("Can't find port!!\n");
+                free(entry->ip);
+                entry->ip = NULL;
+            }
+        }
+        json_object_object_get_ex(datajson, "rotate_file_size", &listjson);
+        entry->rotate_file_size = json_object_get_int(listjson) * 1024;
+        mbtk_log("rotate_file_size: %d\n", entry->rotate_file_size);
+
+        json_object_object_get_ex(datajson, "rotate_file_count", &listjson);
+        entry->rotate_file_count = json_object_get_int(listjson);
+        mbtk_log("rotate_file_count: %d\n", entry->rotate_file_count);
+
+        json_object_object_get_ex(datajson, "filter_list", &listjson);
+        if (NULL == listjson) {
+            printf("%s %d: object failure!\n", __FUNCTION__, __LINE__);
+            json_object_put(listjson);
+            continue;
+        }
+        entry->filter_list = (struct filter_list_t*)malloc(sizeof(struct filter_list_t));
+        _filter_list = entry->filter_list;
+
+        for (n = 0 ; n < 5; n++) {
+            fileterjson = json_object_array_get_idx(listjson, n);
+            if (NULL == fileterjson) {
+                mbtk_log("the fileterjson exit\n");
+                free(tmp_filter_list->next);
+                tmp_filter_list->next = NULL;
+                break;
+            }
+            memset(_filter_list, 0, sizeof(struct filter_list_t));
+            json_object_object_get_ex(fileterjson, "priority", &fileter_listjson);
+            char* str = json_object_get_string(fileter_listjson);
+            if (str) {
+                _filter_list->priority = str[0];
+                mbtk_log("fileter_listjson: %c\n", _filter_list->priority);
+            }
+            json_object_object_get_ex(fileterjson, "tag", &fileter_listjson);
+            // if (NULL == fileter_listjson) {
+            //     printf("%s %d: object failure!\n", __FUNCTION__, __LINE__);
+            // }
+            str = json_object_get_string(fileter_listjson);
+            if (str) {
+                _filter_list->tag = strdup(str);
+                mbtk_log("fileter_listjson: %s\n", _filter_list->tag);
+            }
+            json_object_put(fileter_listjson);
+            _filter_list->next = (struct filter_list_t*)malloc(sizeof(struct filter_list_t));
+            if (NULL == _filter_list->next) {
+                printf("%s %d: malloc failure!\n", __FUNCTION__, __LINE__);
+                break;
+            }
+            tmp_filter_list = _filter_list;
+            _filter_list = _filter_list->next;
+        }
+        json_object_put(listjson);
+    }
+    json_object_put(tmpjson);
+
+    /***释放json对象***/
+    json_object_put(jsonobj);
+
+    return 0;
+}
+
+#define  LOGD_PID  "/var/run/mbtk_logd.pid"
+
+static int save_pid(void)
+{
+    pid_t process_id;
+    int fd, ret;
+    char buf[12] = {0};
+
+    process_id  = getpid();
+    if(access(LOGD_PID, F_OK) == 0)
+    {
+        printf("mbtk_logd 进程已经存在\n");
+        return -1;
+    }
+    fd = open(LOGD_PID, O_CREAT | O_WRONLY, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", LOGD_PID, strerror(errno));
+        return -2;
+    }
+    snprintf(buf, sizeof(buf), "%d\n", process_id);
+    ret = write(fd, buf, strlen(buf));
+    close(fd);
+
+    if(ret > 0)
+        return 0;
+    else
+        return -2;
+}
+
+int main(int argc, char* argv[])
+{
+    log_config_entry listdata[5];
+    pthread_t pid[5] = {0};
+    int i, ret;
+    void* tret;
+
+    memset(listdata, 0, sizeof(log_config_entry) * 5);
+
+    ret = parse_config(listdata);
+    if (ret) {
+        return -1;
+    }
+    if(0 != save_pid())
+    {
+        printf("%s %d: logd exit!\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    printf("logd %s start !\n", __FUNCTION__);
+
+    for (i = 0; i < 5; ++i) {
+        if (NULL == listdata[i].name) {
+            break;
+        }
+
+        if (0 == listdata[i].enable) {
+            printf("%s log disabled !\n", listdata[i].name);
+            continue;
+        }
+
+        if (0 == memcmp(listdata[i].name, "radio", 5)) {
+            ret = pthread_create(&pid[i], NULL, alog_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s: Failed to create pthread\n", __FUNCTION__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "syslog", 6)) {
+            ret = pthread_create(&pid[i], NULL, syslog_main, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "local_socket", 12)) {
+            ret = pthread_create(&pid[i], NULL, socket_log_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "/dev/tty", 8)) {
+            ret = pthread_create(&pid[i], NULL, common_log_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        }
+    }
+
+    for (i = 0; i < 5; ++i) {
+        if (NULL == listdata[i].name) {
+            break;
+        }
+        if (pid[i]) {
+            if (pthread_join(pid[i], &tret) != 0) {
+                printf("Join thread %d : %d error!\n", i, pid[i]);
+                exit(1);
+            }
+        }
+    }
+    handler_free(listdata);
+
+    return 0;
+}
diff --git a/mbtk/mbtk_logd/socket_read.c b/mbtk/mbtk_logd/socket_read.c
new file mode 100755
index 0000000..df8fe27
--- /dev/null
+++ b/mbtk/mbtk_logd/socket_read.c
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define _MOPEN_RILD_CONNET_NUM  5
+#define _MOPEN_RILD_SOCKET "/tmp/logd_socket"
+
+static int client_sockfd[_MOPEN_RILD_CONNET_NUM];
+
+static const char* log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry* config = NULL;
+static char tmp_log[48] = {0};
+
+static int fileter_log(int pri, char* tag, struct filter_list_t* filter)
+{
+    struct filter_list_t* _filter = filter;
+
+    while (_filter) {
+        // _filter->priority
+        // 获取 筛选的等级 p
+        int p = 0;
+        if (_filter->tag) {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if (0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p))) {
+                return 0;
+            }
+        } else { // have no tag
+            if (pri < p) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int socket_log_print(
+    int fd,
+    struct file_list_t* _file_list,
+    char* entry)
+{
+    char priChar;
+    // char timeBuf[32];
+    // time_t timetemp; // 定义一个时间结构体变量
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+    struct stat s;
+    char* ret = NULL;
+
+    if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+        if (fd_new < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+            exit(-1);
+        }
+    }
+
+    // if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    // {
+    // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+    //     return -1;
+    // }
+    // time(&timetemp); // 获得时间参数
+    // struct tm* ptm = localtime(&timetemp);
+    // strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer), "%s", entry);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+static int open_local_socket(char *path)
+{
+    int listen_fd;
+    int ret;
+    struct sockaddr_un srv_addr;
+
+    listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (listen_fd < 0) {
+        printf("connect creat communication socket");
+        return -1;
+    }
+
+    unlink(path);
+    srv_addr.sun_family = AF_UNIX;
+    strcpy(srv_addr.sun_path, path);
+
+    ret = bind(listen_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
+    if (ret < 0) {
+        printf("cannot bind server socket");
+        close(listen_fd);
+        unlink(path);
+        return -1;
+    }
+
+    return listen_fd;
+}
+
+void* socket_log_thread(void* argv)
+{
+    int listen_fd;
+    int com_fd, fd_max, fd_num;
+    int ret, log_fd;
+    int i, n, str_len;
+    fd_set reads, cpy_reads;
+    struct timeval timeout;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry*)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv || NULL == config->name) {
+        return NULL;
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY | O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if (config->rotate_file_size) {
+        log_size = config->rotate_file_size;
+    }
+
+    listen_fd = open_local_socket(_MOPEN_RILD_SOCKET);
+    if (listen_fd < 0 || listen_fd == 0) {
+        return NULL;
+    }
+    ret = listen(listen_fd, 1);
+    if (ret < 0) {
+        printf("cannot listen sockfd");
+        close(listen_fd);
+        unlink(_MOPEN_RILD_SOCKET);
+        return NULL;
+    }
+    FD_ZERO(&reads);
+    FD_SET(listen_fd, &reads);
+    fd_max = listen_fd;
+    printf("socket log start...\n");
+    memset(client_sockfd, 0, sizeof(client_sockfd));
+    for (;;) {
+        cpy_reads = reads;
+        timeout.tv_sec = 5;
+        timeout.tv_usec = 5000;
+
+        if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1) {
+            perror("select error");
+            break;
+        }
+        if (fd_num == 0) {
+            continue;
+        }
+
+        for (n = 0; n < fd_max + 1; n++) {
+            if (FD_ISSET(n, &cpy_reads)) {
+                if (n == listen_fd) {
+                    com_fd = accept(listen_fd, NULL, NULL);
+                    FD_SET(com_fd, &reads);
+                    if (fd_max < com_fd) {
+                        fd_max = com_fd;
+                    }
+                    printf("accept accept fd [%d]", com_fd);
+                    for (i = 0; i < _MOPEN_RILD_CONNET_NUM; i++) {
+                        if (client_sockfd[i] <= 0) {
+                            client_sockfd[i] = com_fd;
+                            break;
+                        }
+                    }
+                } else {
+                    str_len = read(n, buf, sizeof(buf));
+                    if (str_len == 0) {
+                        for (i = 0; i < _MOPEN_RILD_CONNET_NUM; i++) {
+                            if (client_sockfd[i] == n) {
+                                client_sockfd[i] = 0;
+                                break;
+                            }
+                        }
+                        FD_CLR(n, &reads);
+                        close(n);
+                        printf("closed client: %d \n", n);
+                    } else {
+                        socket_log_print(log_fd, &file_list, buf);
+                        memset(buf, 0, sizeof(buf));
+                    }
+                }
+            }
+        }
+    }
+    close(listen_fd);
+    close(log_fd);
+    unlink(_MOPEN_RILD_SOCKET);
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+
+    return NULL;
+}
diff --git a/mbtk/mbtk_logd/syslog.h b/mbtk/mbtk_logd/syslog.h
new file mode 100755
index 0000000..b682ced
--- /dev/null
+++ b/mbtk/mbtk_logd/syslog.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * 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/mbtk/mbtk_logd/syslog_read.c b/mbtk/mbtk_logd/syslog_read.c
new file mode 100755
index 0000000..3cae9e9
--- /dev/null
+++ b/mbtk/mbtk_logd/syslog_read.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define SYSLOG_NAMES
+#include <syslog.h>
+
+#include <libubox/ustream.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/usock.h>
+#include <libubox/uloop.h>
+#include "libubus.h"
+#include "syslog.h"
+#include "log_config.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 const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_type = LOG_STDOUT;
+static int log_size = 1 * 1024 * 1024, log_udp, log_follow = 0;
+static struct file_list_t file_list;
+static struct filter_list_t *filter_log = NULL;
+static char tmp_log[48] = {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 "<unknown>";
+};
+
+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(0, "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 filter_char_to_pri(char c)
+{
+    switch (c) {
+        case 'v':
+            return 8;
+        case 'd':
+            return LOG_DEBUG;
+        case 'i':
+            return LOG_INFO;
+        case 'w':
+            return LOG_WARNING;
+        case 'e':
+            return LOG_ERR;
+        case 'f':
+            return LOG_ALERT;
+        case '*':
+        default:
+            return 8;
+    }
+}
+
+static int syslog_fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        int p = filter_char_to_pri(_filter->priority);
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri < p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri > p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+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;
+
+	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(tmp_log, &s)) && (s.st_size > log_size)) {
+        sender.fd = get_rotate_file(sender.fd, log_file, &file_list);
+		if (sender.fd < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+			exit(-1);
+        }
+	}
+
+	m = blobmsg_get_string(tb[LOG_MSG]);
+	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(filter_log && syslog_fileter_log(LOG_PRI(p), m, filter_log))
+    {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, p, m);
+        exit(-1);
+    }
+	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));
+			strncat(buf, " ", sizeof(buf));
+		}
+		if (log_prefix) {
+			strncat(buf, log_prefix, sizeof(buf));
+			strncat(buf, ": ", sizeof(buf));
+		}
+		if (blobmsg_get_u32(tb[LOG_SOURCE]) == SOURCE_KLOG)
+			strncat(buf, "kernel: ", sizeof(buf));
+		strncat(buf, m, sizeof(buf));
+		if (log_udp)
+			err = write(sender.fd, buf, strlen(buf));
+		else
+			err = send(sender.fd, buf, strlen(buf), 0);
+
+		if (err < 0) {
+			syslog(0, "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);
+		write(sender.fd, buf, strlen(buf));
+	}
+
+	free(str);
+	if (log_type == LOG_FILE)
+		fsync(sender.fd);
+
+	return 0;
+}
+
+static void logread_fd_data_cb(struct ustream *s, int bytes)
+{
+	while (true) {
+		int len;
+		struct blob_attr *a;
+
+		a = (void*) ustream_get_read_buf(s, &len);
+		if (len < sizeof(*a) || len < blob_len(a) + sizeof(*a))
+			break;
+		log_notify(a);
+		ustream_consume(s, blob_len(a) + sizeof(*a));
+	}
+	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);
+}
+
+static void logread_complete_cb(struct ubus_request *req, int ret)
+{
+}
+
+void* syslog_main(void* 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;
+    log_config_entry *config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+
+    if (NULL == argv)
+        return NULL;
+
+	signal(SIGPIPE, SIG_IGN);
+	uloop_init();
+
+    log_file = config->out_path;
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+    if(config->ip)
+    {
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_ip = config->ip;
+        log_port = config->port;
+    }
+    filter_log = config->filter_list;
+    // Follow log messages
+    log_follow = 1;
+	ctx = ubus_connect(ubus_socket);
+	if (!ctx) {
+		fprintf(stderr, "Failed to connect to ubus\n");
+		return -1;
+	}
+	ubus_add_uloop(ctx);
+
+    printf("syslog log start...\n");
+	/* 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);
+		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;
+            // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+            sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+			sender.fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+			if (sender.fd < 0) {
+				fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+				exit(-1);
+			}
+		} else {
+			sender.fd = STDOUT_FILENO;
+		}
+
+		ubus_invoke_async(ctx, id, "read", b.head, &req);
+		req.fd_cb = logread_fd_cb;
+		req.complete_cb = logread_complete_cb;
+		ubus_complete_request_async(ctx, &req);
+
+		uloop_run();
+		ubus_free(ctx);
+		uloop_done();
+
+	} while (ret && tries--);
+
+    pthread_exit(NULL);
+	return NULL;
+}