diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | CMakeLists.txt | 32 | ||||
-rw-r--r-- | debug.c | 45 | ||||
-rw-r--r-- | initd/early.c (renamed from early.c) | 19 | ||||
-rw-r--r-- | initd/init.c | 115 | ||||
-rw-r--r-- | initd/init.h | 23 | ||||
-rw-r--r-- | initd/mkdev.c (renamed from mkdev.c) | 6 | ||||
-rw-r--r-- | initd/preinit.c | 98 | ||||
-rw-r--r-- | inittab.c | 10 | ||||
-rw-r--r-- | libvalidate.h | 6 | ||||
-rw-r--r-- | log.c | 135 | ||||
-rw-r--r-- | log.h (renamed from syslog.h) | 41 | ||||
-rw-r--r-- | logread.c | 369 | ||||
-rw-r--r-- | measure.c | 99 | ||||
-rw-r--r-- | plug/coldplug.c (renamed from coldplug.c) | 9 | ||||
-rw-r--r-- | plug/hotplug.c (renamed from hotplug.c) | 36 | ||||
-rw-r--r-- | plug/hotplug.h (renamed from hotplug.h) | 1 | ||||
-rw-r--r-- | plug/udevtrigger.c (renamed from udevtrigger.c) | 0 | ||||
-rw-r--r-- | preinit.c | 68 | ||||
-rw-r--r-- | procd.c (renamed from main.c) | 31 | ||||
-rw-r--r-- | procd.h | 33 | ||||
-rw-r--r-- | rcS.c | 10 | ||||
-rw-r--r-- | service/instance.c (renamed from instance.c) | 25 | ||||
-rw-r--r-- | service/instance.h (renamed from instance.h) | 2 | ||||
-rw-r--r-- | service/service.c (renamed from service.c) | 45 | ||||
-rw-r--r-- | service/service.h (renamed from service.h) | 1 | ||||
-rw-r--r-- | service/trigger.c (renamed from trigger.c) | 6 | ||||
-rw-r--r-- | service/validate.c (renamed from service_validate.c) | 3 | ||||
-rw-r--r-- | signal.c | 13 | ||||
-rw-r--r-- | state.c | 15 | ||||
-rw-r--r-- | syslog.c | 320 | ||||
-rw-r--r-- | system.c | 6 | ||||
-rw-r--r-- | ubus.c | 97 | ||||
-rw-r--r-- | utils/askfirst.c (renamed from askfirst.c) | 0 | ||||
-rw-r--r-- | utils/md5.c (renamed from md5.c) | 0 | ||||
-rw-r--r-- | utils/md5.h (renamed from md5.h) | 0 | ||||
-rw-r--r-- | utils/utils.c (renamed from utils.c) | 0 | ||||
-rw-r--r-- | utils/utils.h (renamed from utils.h) | 0 | ||||
-rw-r--r-- | validate.c | 1002 | ||||
-rw-r--r-- | validate_data.c | 28 | ||||
-rw-r--r-- | watchdog.c | 10 |
41 files changed, 420 insertions, 2344 deletions
@@ -1,13 +1,10 @@ procd -validate_data -logread askfirst udevtrigger +init .* -*.so Makefile CMakeCache.txt CMakeFiles *.cmake install_manifest.txt - diff --git a/CMakeLists.txt b/CMakeLists.txt index a521ea7..d353801 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,9 @@ IF(APPLE) LINK_DIRECTORIES(/opt/local/lib) ENDIF() -SET(SOURCES main.c ubus.c service.c service_validate.c instance.c utils.c md5.c hotplug.c state.c mkdev.c early.c inittab.c preinit.c coldplug.c syslog.c log.c watchdog.c signal.c system.c debug.c rcS.c trigger.c measure.c) +SET(SOURCES procd.c signal.c watchdog.c state.c inittab.c rcS.c ubus.c system.c + service/service.c service/instance.c service/validate.c service/trigger.c + plug/coldplug.c plug/hotplug.c utils/utils.c utils/md5.c) find_library(json NAMES json-c json) SET(LIBS ubox ubus ${json} blobmsg_json json_script) @@ -19,42 +21,28 @@ IF(DEBUG) ADD_DEFINITIONS(-DDEBUG -g3) ENDIF() -ADD_LIBRARY(validate SHARED validate.c) - -INSTALL(TARGETS validate - LIBRARY DESTINATION lib -) ADD_EXECUTABLE(procd ${SOURCES}) - -TARGET_LINK_LIBRARIES(procd ${LIBS} validate) - +TARGET_LINK_LIBRARIES(procd ${LIBS}) INSTALL(TARGETS procd RUNTIME DESTINATION sbin ) -ADD_EXECUTABLE(askfirst askfirst.c) -INSTALL(TARGETS askfirst +ADD_EXECUTABLE(init initd/init.c initd/early.c initd/preinit.c initd/mkdev.c watchdog.c) +TARGET_LINK_LIBRARIES(init ${LIBS}) +INSTALL(TARGETS init RUNTIME DESTINATION sbin ) -ADD_EXECUTABLE(udevtrigger udevtrigger.c) +ADD_EXECUTABLE(udevtrigger plug/udevtrigger.c) INSTALL(TARGETS udevtrigger RUNTIME DESTINATION sbin ) -ADD_EXECUTABLE(logread logread.c) -TARGET_LINK_LIBRARIES(logread ${LIBS}) -INSTALL(TARGETS logread - RUNTIME DESTINATION sbin -) - -ADD_EXECUTABLE(validate_data validate_data.c) -TARGET_LINK_LIBRARIES(validate_data ${LIBS} validate) - -INSTALL(TARGETS validate_data +ADD_EXECUTABLE(askfirst utils/askfirst.c) +INSTALL(TARGETS askfirst RUNTIME DESTINATION sbin ) diff --git a/debug.c b/debug.c deleted file mode 100644 index fbf1e4f..0000000 --- a/debug.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 <regex.h> -#include <unistd.h> - -#include "procd.h" - -unsigned int debug = 0; - -void debug_init(void) -{ - char line[256]; - int r, fd = open("/proc/cmdline", O_RDONLY); - regex_t pat_cmdline; - regmatch_t matches[2]; - - if (fd < 0) - return; - - r = read(fd, line, sizeof(line) - 1); - line[r] = '\0'; - close(fd); - - regcomp(&pat_cmdline, "init_debug=([0-9]+)", REG_EXTENDED); - if (!regexec(&pat_cmdline, line, 2, matches, 0)) { - line[matches[1].rm_eo] = '\0'; - debug = atoi(&line[matches[1].rm_so]); - } - regfree(&pat_cmdline); -} @@ -19,10 +19,13 @@ #include <stdio.h> #include <fcntl.h> #include <unistd.h> +#include <stdlib.h> -#include "procd.h" +#include "../log.h" +#include "init.h" -static void early_mounts(void) +static void +early_mounts(void) { mount("proc", "/proc", "proc", MS_NOATIME, 0); mount("sysfs", "/sys", "sysfs", MS_NOATIME, 0); @@ -39,13 +42,15 @@ static void early_mounts(void) mount("devpts", "/dev/pts", "devpts", MS_NOATIME, "mode=600"); } -static void early_dev(void) +static void +early_dev(void) { mkdev("*", 0600); mknod("/dev/null", 0666, makedev(1, 3)); } -static void early_console(const char *dev) +static void +early_console(const char *dev) { struct stat s; int dd; @@ -69,12 +74,14 @@ static void early_console(const char *dev) close(dd); } -static void early_env(void) +static void +early_env(void) { setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin", 1); } -void procd_early(void) +void +early(void) { if (getpid() != 1) return; diff --git a/initd/init.c b/initd/init.c new file mode 100644 index 0000000..d458f29 --- /dev/null +++ b/initd/init.c @@ -0,0 +1,115 @@ +/* + * 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/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/reboot.h> + +#include <libubox/uloop.h> +#include <libubus.h> + +#include <stdlib.h> +#include <fcntl.h> +#include <getopt.h> +#include <libgen.h> +#include <regex.h> +#include <unistd.h> +#include <stdio.h> + +#include "init.h" +#include "../watchdog.h" + +unsigned int debug = 0; + +static void +signal_shutdown(int signal, siginfo_t *siginfo, void *data) +{ + fprintf(stderr, "reboot\n"); + fflush(stderr); + sync(); + sleep(2); + reboot(RB_AUTOBOOT); + while (1) + ; +} + +static struct sigaction sa_shutdown = { + .sa_sigaction = signal_shutdown, + .sa_flags = SA_SIGINFO +}; + +static void +cmdline(void) +{ + char line[256]; + int r, fd = open("/proc/cmdline", O_RDONLY); + regex_t pat_cmdline; + regmatch_t matches[2]; + + if (fd < 0) + return; + + r = read(fd, line, sizeof(line) - 1); + line[r] = '\0'; + close(fd); + + regcomp(&pat_cmdline, "init_debug=([0-9]+)", REG_EXTENDED); + if (!regexec(&pat_cmdline, line, 2, matches, 0)) { + line[matches[1].rm_eo] = '\0'; + debug = atoi(&line[matches[1].rm_so]); + } + regfree(&pat_cmdline); +} + +int +main(int argc, char **argv) +{ + pid_t pid; + + sigaction(SIGTERM, &sa_shutdown, NULL); + sigaction(SIGUSR1, &sa_shutdown, NULL); + sigaction(SIGUSR2, &sa_shutdown, NULL); + + early(); + cmdline(); + watchdog_init(1); + + pid = fork(); + if (!pid) { + char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL }; + + if (debug < 3) { + int fd = open("/dev/null", O_RDWR); + + if (fd > -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } + } + execvp(kmod[0], kmod); + ERROR("Failed to start kmodloader\n"); + exit(-1); + } + if (pid <= 0) + ERROR("Failed to start kmodloader instance\n"); + uloop_init(); + preinit(); + uloop_run(); + + return 0; +} diff --git a/initd/init.h b/initd/init.h new file mode 100644 index 0000000..1321cf8 --- /dev/null +++ b/initd/init.h @@ -0,0 +1,23 @@ +/* + * 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 _INIT_H__ +#define _INIT_H__ + +#include "../log.h" + +void preinit(void); +void early(void); +int mkdev(const char *progname, int progmode); + +#endif @@ -26,7 +26,9 @@ #include <limits.h> #include <fnmatch.h> -#include "procd.h" +#include "init.h" + +#include "../log.h" static char **patterns; static int n_patterns; @@ -50,7 +52,7 @@ static void make_dev(const char *path, bool block, int major, int minor) unsigned int oldumask = umask(0); unsigned int _mode = mode | (block ? S_IFBLK : S_IFCHR); - DEBUG(2, "Creating %s device %s(%d,%d)\n", + DEBUG(4, "Creating %s device %s(%d,%d)\n", block ? "block" : "character", path, major, minor); diff --git a/initd/preinit.c b/initd/preinit.c new file mode 100644 index 0000000..eeadbeb --- /dev/null +++ b/initd/preinit.c @@ -0,0 +1,98 @@ +/* + * 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/stat.h> +#include <sys/types.h> +#include <sys/mount.h> + +#include <libubox/uloop.h> +#include <libubox/utils.h> +#include <libubus.h> + +#include <stdio.h> + +#include <unistd.h> + +#include "init.h" +#include "../watchdog.h" + +static struct uloop_process preinit_proc; +static struct uloop_process plugd_proc; + +static void +spawn_procd(struct uloop_process *proc, int ret) +{ + char *wdt_fd = watchdog_fd(); + char *argv[] = { "/sbin/procd", NULL }; + struct stat s; + + if (plugd_proc.pid > 0) + kill(plugd_proc.pid, SIGKILL); + + if (!stat("/tmp/sysupgrade", &s)) + while (true) + sleep(1); + + unsetenv("INITRAMFS"); + unsetenv("PREINIT"); + DEBUG(2, "Exec to real procd now\n"); + if (wdt_fd) + setenv("WDTFD", wdt_fd, 1); + execvp(argv[0], argv); +} + +static void +plugd_proc_cb(struct uloop_process *proc, int ret) +{ + proc->pid = 0; +} + +void +preinit(void) +{ + char *init[] = { "/bin/sh", "/etc/preinit", NULL }; + char *plug[] = { "/sbin/procd", "-h", "/etc/hotplug-preinit.json", NULL }; + + LOG("- preinit -\n"); + + plugd_proc.cb = plugd_proc_cb; + plugd_proc.pid = fork(); + if (!plugd_proc.pid) { + execvp(plug[0], plug); + ERROR("Failed to start plugd\n"); + exit(-1); + } + if (plugd_proc.pid <= 0) { + ERROR("Failed to start new plugd instance\n"); + return; + } + uloop_process_add(&plugd_proc); + + setenv("PREINIT", "1", 1); + + preinit_proc.cb = spawn_procd; + preinit_proc.pid = fork(); + if (!preinit_proc.pid) { + execvp(init[0], init); + ERROR("Failed to start preinit\n"); + exit(-1); + } + if (preinit_proc.pid <= 0) { + ERROR("Failed to start new preinit instance\n"); + return; + } + uloop_process_add(&preinit_proc); + + DEBUG(4, "Launched preinit instance, pid=%d\n", (int) preinit_proc.pid); +} @@ -72,7 +72,7 @@ static void fork_worker(struct init_action *a) } if (a->proc.pid > 0) { - DEBUG(2, "Launched new %s action, pid=%d\n", + DEBUG(4, "Launched new %s action, pid=%d\n", a->handler->name, (int) a->proc.pid); uloop_process_add(&a->proc); @@ -83,7 +83,7 @@ static void child_exit(struct uloop_process *proc, int ret) { struct init_action *a = container_of(proc, struct init_action, proc); - DEBUG(2, "pid:%d\n", proc->pid); + DEBUG(4, "pid:%d\n", proc->pid); uloop_timeout_set(&a->tout, a->respawn); } @@ -116,7 +116,7 @@ static void askfirst(struct init_action *a) i = stat(a->id, &s); chdir("/"); if (i || (console && !strcmp(console, a->id))) { - DEBUG(2, "Skipping %s\n", a->id); + DEBUG(4, "Skipping %s\n", a->id); return; } @@ -156,7 +156,7 @@ static void askconsole(struct init_action *a) i = stat(tty, &s); chdir("/"); if (i) { - DEBUG(2, "skipping %s\n", tty); + DEBUG(4, "skipping %s\n", tty); goto err_out; } console = strdup(tty); @@ -265,7 +265,7 @@ void procd_inittab(void) if (regexec(&pat_inittab, line, 5, matches, 0)) continue; - DEBUG(2, "Parsing inittab - %s", line); + DEBUG(4, "Parsing inittab - %s", line); for (i = TAG_ID; i <= TAG_PROCESS; i++) { line[matches[i].rm_eo] = '\0'; diff --git a/libvalidate.h b/libvalidate.h deleted file mode 100644 index d3b8e05..0000000 --- a/libvalidate.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _VALIDATE_H__ -#define _VALIDATE_H__ - -bool dt_parse(const char *code, const char *value); - -#endif @@ -1,135 +0,0 @@ -/* - * 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 <linux/types.h> - -#include <libubox/uloop.h> -#include <libubox/blobmsg_json.h> - -#include "procd.h" -#include "syslog.h" - -static int notify; -struct ubus_context *_ctx; -static struct blob_buf b; - -static const struct blobmsg_policy read_policy = - { .name = "lines", .type = BLOBMSG_TYPE_INT32 }; - -static const struct blobmsg_policy write_policy = - { .name = "event", .type = BLOBMSG_TYPE_STRING }; - -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 blob_attr *tb; - struct log_head *l; - void *lines, *entry; - int count = 0; - - if (msg) { - blobmsg_parse(&read_policy, 1, &tb, blob_data(msg), blob_len(msg)); - if (tb) - count = blobmsg_get_u32(tb); - } - - blob_buf_init(&b, 0); - lines = blobmsg_open_array(&b, "lines"); - - l = log_list(count, NULL); - - while (l) { - entry = blobmsg_open_table(&b, NULL); - 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); - blobmsg_close_table(&b, entry); - l = log_list(count, l); - } - blobmsg_close_table(&b, lines); - ubus_send_reply(ctx, req, b.head); - - 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 void log_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) -{ - notify = obj->has_subscribers; -} - -static const struct ubus_method log_methods[] = { - { .name = "read", .handler = read_log, .policy = &read_policy, .n_policy = 1 }, - { .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), - .subscribe_cb = log_subscribe_cb, -}; - -void ubus_notify_log(struct log_head *l) -{ - int ret; - - if (!notify) - return; - - blob_buf_init(&b, 0); - 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)); - - ret = ubus_notify(_ctx, &log_object, l->data, b.head, -1); - if (ret) - ERROR("Failed to notify log: %s\n", ubus_strerror(ret)); -} - -void ubus_init_log(struct ubus_context *ctx) -{ - int ret; - - _ctx = ctx; - - ret = ubus_add_object(ctx, &log_object); - if (ret) - ERROR("Failed to add object: %s\n", ubus_strerror(ret)); -} @@ -12,32 +12,27 @@ * GNU General Public License for more details. */ -#ifndef __SYSLOG_H -#define __SYSLOG_H +#ifndef __LOG_H +#define __LOG_H -enum { - SOURCE_KLOG = 0, - SOURCE_SYSLOG = 1, - SOURCE_INTERNAL = 2, - SOURCE_ANY = 0xff, -}; +#include <syslog.h> -struct log_head { - unsigned int size; - unsigned int id; - int priority; - int source; - struct timespec ts; - char data[]; -}; +#define DEBUG(level, fmt, ...) do { \ + if (debug >= level) { \ + syslog(0, fmt, ## __VA_ARGS__); \ + fprintf(stderr, "procd: %s(%d): " fmt, __func__, __LINE__, ## __VA_ARGS__); \ + } } while (0) -void log_init(void); -void log_shutdown(void); +#define LOG(fmt, ...) do { \ + syslog(0, fmt, ## __VA_ARGS__); \ + fprintf(stderr, "procd: "fmt, ## __VA_ARGS__); \ + } while (0) -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 log_printf(char *fmt, ...); +#define ERROR(fmt, ...) do { \ + syslog(0, fmt, ## __VA_ARGS__); \ + fprintf(stderr, "procd: "fmt, ## __VA_ARGS__); \ + } while (0) + +extern unsigned int debug; #endif diff --git a/logread.c b/logread.c deleted file mode 100644 index e8749f8..0000000 --- a/logread.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * 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/blobmsg_json.h> -#include <libubox/usock.h> -#include <libubox/uloop.h> -#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 ubus_subscriber log_event; -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, log_udp; - -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_remove(struct ubus_context *ctx, struct ubus_subscriber *s, - uint32_t id) -{ - fprintf(stderr, "Object %08x went away\n", id); -} - -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 ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - 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; - - 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]) - 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); - } - } - - 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; - - *buf = '\0'; - if (hostname) - snprintf(buf, sizeof(buf), "%s ", hostname); - 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, method, 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:"), - method); - write(sender.fd, buf, strlen(buf)); - } - - free(str); - if (log_type == LOG_FILE) - fsync(sender.fd); - - return 0; -} - -static void follow_log(struct ubus_context *ctx, int id) -{ - FILE *fp; - int ret; - - signal(SIGPIPE, SIG_IGN); - - if (pid_file) { - fp = fopen(pid_file, "w+"); - if (fp) { - fprintf(fp, "%d", getpid()); - fclose(fp); - } - } - - uloop_init(); - ubus_add_uloop(ctx); - - log_event.remove_cb = log_handle_remove; - log_event.cb = log_notify; - ret = ubus_register_subscriber(ctx, &log_event); - if (ret) - fprintf(stderr, "Failed to add watch handler: %s\n", ubus_strerror(ret)); - - ret = ubus_subscribe(ctx, &log_event, id); - if (ret) - fprintf(stderr, "Failed to add watch handler: %s\n", ubus_strerror(ret)); - - 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; - } - - uloop_run(); - ubus_free(ctx); - uloop_done(); -} - -enum { - READ_LINE, - __READ_MAX -}; - - - -static const struct blobmsg_policy read_policy[] = { - [READ_LINE] = { .name = "lines", .type = BLOBMSG_TYPE_ARRAY }, -}; - -static void read_cb(struct ubus_request *req, int type, struct blob_attr *msg) -{ - struct blob_attr *cur; - struct blob_attr *_tb[__READ_MAX]; - time_t t; - int rem; - - if (!msg) - return; - - blobmsg_parse(read_policy, ARRAY_SIZE(read_policy), _tb, blob_data(msg), blob_len(msg)); - if (!_tb[READ_LINE]) - return; - blobmsg_for_each_attr(cur, _tb[READ_LINE], rem) { - struct blob_attr *tb[__LOG_MAX]; - uint32_t p; - char *c; - - if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) - continue; - - blobmsg_parse(log_policy, ARRAY_SIZE(log_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur)); - if (!tb[LOG_MSG] || !tb[LOG_ID] || !tb[LOG_PRIO] || !tb[LOG_SOURCE] || !tb[LOG_TIME]) - continue; - - t = blobmsg_get_u64(tb[LOG_TIME]); - p = blobmsg_get_u32(tb[LOG_PRIO]); - c = ctime(&t); - c[strlen(c) - 1] = '\0'; - - printf("%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:"), - blobmsg_get_string(tb[LOG_MSG])); - } -} - -static int usage(const char *prog) -{ - fprintf(stderr, "Usage: %s [options]\n" - "Options:\n" - " -s <path> Path to ubus socket\n" - " -l <count> Got only the last 'count' messages\n" - " -r <server> <port> Stream message to a server\n" - " -F <file> Log file\n" - " -S <bytes> Log size\n" - " -p <file> PID file\n" - " -h <hostname> Add hostname to the message\n" - " -P <prefix> Prefix custom text to streamed messages\n" - " -f Follow log messages\n" - " -u Use UDP as the protocol\n" - "\n", prog); - return 1; -} - -int main(int argc, char **argv) -{ - struct ubus_context *ctx; - uint32_t id; - const char *ubus_socket = NULL; - int ch, ret, subscribe = 0, lines = 0; - static struct blob_buf b; - - while ((ch = getopt(argc, argv, "ufcs:l:r:F:p:S:P:h:")) != -1) { - switch (ch) { - case 'u': - log_udp = 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': - subscribe = 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; - default: - return usage(*argv); - } - } - - ctx = ubus_connect(ubus_socket); - if (!ctx) { - fprintf(stderr, "Failed to connect to ubus\n"); - return -1; - } - - ret = ubus_lookup_id(ctx, "log", &id); - if (ret) - fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret)); - - if (!subscribe || lines) { - blob_buf_init(&b, 0); - if (lines) - blobmsg_add_u32(&b, "lines", lines); - ubus_invoke(ctx, id, "read", b.head, read_cb, 0, 3000); - } - - if (subscribe) - follow_log(ctx, id); - - return 0; -} diff --git a/measure.c b/measure.c deleted file mode 100644 index 9e21a66..0000000 --- a/measure.c +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (C) 2010 Steven Barth <steven@midlink.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 General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - */ - - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdint.h> -#include <ctype.h> -#include <fcntl.h> -#include <regex.h> -#include <stdio.h> -#include <string.h> -#include <glob.h> -#include <libgen.h> - -#include "procd.h" - -static regex_t pat_vmsize, pat_ppid, pat_state, pat_uid; - -static void __attribute__((constructor)) measure_init() { - regcomp(&pat_vmsize, "VmSize:[ \t]*([0-9]*) kB", REG_EXTENDED); - regcomp(&pat_uid, "Uid:[ \t]*([0-9]*).*", REG_EXTENDED); - regcomp(&pat_ppid, "PPid:[ \t]*([0-9]+)", REG_EXTENDED); - regcomp(&pat_state, "State:[ \t]*([A-Z])", REG_EXTENDED); -} - -static void __attribute__((destructor)) measure_fini() { - regfree(&pat_vmsize); - regfree(&pat_ppid); - regfree(&pat_uid); - regfree(&pat_state); -} - -int measure_process(pid_t pid, struct pid_info *pi) { - int fd; - char buffer[512] = ""; - ssize_t rxed; - regmatch_t matches[2]; - glob_t gl; - int i; - - memset(pi, 0, sizeof(*pi)); - - snprintf(buffer, sizeof(buffer), "/proc/%i/fd/*", (int)pid); - - if (glob(buffer, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) { - fprintf(stderr, "glob failed on %s\n", buffer); - return -1; - } - - for (i = 0; i < gl.gl_pathc; i++) - if (isdigit(basename(gl.gl_pathv[i])[0])) - pi->fdcount++; - globfree(&gl); - - snprintf(buffer, sizeof(buffer), "/proc/%i/status", (int)pid); - fd = open(buffer, O_RDONLY); - if (fd == -1) - return -1; - - rxed = read(fd, buffer, sizeof(buffer) - 1); - close(fd); - if (rxed == -1) - return -1; - - buffer[rxed] = 0; - - if (!regexec(&pat_state, buffer, 2, matches, 0)) - pi->stat = buffer[matches[1].rm_so]; - - if (!regexec(&pat_ppid, buffer, 2, matches, 0)) - pi->ppid = atoi(buffer + matches[1].rm_so); - - if (!regexec(&pat_uid, buffer, 2, matches, 0)) - pi->uid = atoi(buffer + matches[1].rm_so); - - if (!regexec(&pat_vmsize, buffer, 2, matches, 0)) - pi->vmsize = atoi(buffer + matches[1].rm_so) * 1024; - - return 0; -} diff --git a/coldplug.c b/plug/coldplug.c index 71b09f0..466b759 100644 --- a/coldplug.c +++ b/plug/coldplug.c @@ -18,21 +18,22 @@ #include <unistd.h> -#include "procd.h" +#include "../procd.h" + #include "hotplug.h" static struct uloop_process udevtrigger; static void coldplug_complete(struct uloop_timeout *t) { - DEBUG(2, "Coldplug complete\n"); + DEBUG(4, "Coldplug complete\n"); hotplug_last_event(NULL); procd_state_next(); } static void udevtrigger_complete(struct uloop_process *proc, int ret) { - DEBUG(2, "Finished udevtrigger\n"); + DEBUG(4, "Finished udevtrigger\n"); hotplug_last_event(coldplug_complete); } @@ -61,5 +62,5 @@ void procd_coldplug(void) uloop_process_add(&udevtrigger); - DEBUG(2, "Launched coldplug instance, pid=%d\n", (int) udevtrigger.pid); + DEBUG(4, "Launched coldplug instance, pid=%d\n", (int) udevtrigger.pid); } diff --git a/hotplug.c b/plug/hotplug.c index 422e849..ca1e823 100644 --- a/hotplug.c +++ b/plug/hotplug.c @@ -28,7 +28,8 @@ #include <stdlib.h> #include <libgen.h> -#include "procd.h" +#include "../procd.h" + #include "hotplug.h" #define HOTPLUG_WAIT 500 @@ -137,7 +138,7 @@ static void handle_exec(struct blob_attr *msg, struct blob_attr *data) break; } - if (debug < 2) { + if (debug < 3) { fd = open("/dev/null", O_RDWR); if (fd > -1) { dup2(fd, STDIN_FILENO); @@ -165,7 +166,7 @@ static void handle_firmware(struct blob_attr *msg, struct blob_attr *data) char *path, loadpath[256], syspath[256]; int fw, load, sys, len; - DEBUG(1, "Firmware request for %s/%s\n", dir, file); + DEBUG(2, "Firmware request for %s/%s\n", dir, file); if (!file || !dir || !dev) { ERROR("Request for unknown firmware %s/%s\n", dir, file); @@ -230,7 +231,7 @@ static void handle_firmware(struct blob_attr *msg, struct blob_attr *data) write(load, "0", 1); close(load); - DEBUG(1, "Done loading %s\n", path); + DEBUG(2, "Done loading %s\n", path); exit(-1); } @@ -283,12 +284,12 @@ static void queue_next(void) uloop_process_add(&queue_proc); - DEBUG(2, "Launched hotplug exec instance, pid=%d\n", (int) queue_proc.pid); + DEBUG(4, "Launched hotplug exec instance, pid=%d\n", (int) queue_proc.pid); } static void queue_proc_cb(struct uloop_process *c, int ret) { - DEBUG(2, "Finished hotplug exec instance, pid=%d\n", (int) c->pid); + DEBUG(4, "Finished hotplug exec instance, pid=%d\n", (int) c->pid); queue_next(); } @@ -356,16 +357,16 @@ static void rule_handle_command(struct json_script_ctx *ctx, const char *name, struct blob_attr *cur; int rem, i; - if (debug > 1) { - DEBUG(2, "Command: %s", name); + if (debug > 3) { + DEBUG(4, "Command: %s", name); blobmsg_for_each_attr(cur, data, rem) - DEBUG(2, " %s", (char *) blobmsg_data(cur)); - DEBUG(2, "\n"); + DEBUG(4, " %s", (char *) blobmsg_data(cur)); + DEBUG(4, "\n"); - DEBUG(2, "Message:"); + DEBUG(4, "Message:"); blobmsg_for_each_attr(cur, vars, rem) - DEBUG(2, " %s=%s", blobmsg_name(cur), (char *) blobmsg_data(cur)); - DEBUG(2, "\n"); + DEBUG(4, " %s=%s", blobmsg_name(cur), (char *) blobmsg_data(cur)); + DEBUG(4, "\n"); } for (i = 0; i < ARRAY_SIZE(handlers); i++) @@ -461,6 +462,15 @@ void hotplug(char *rules) uloop_fd_add(&hotplug_fd, ULOOP_READ); } +int hotplug_run(char *rules) +{ + uloop_init(); + hotplug(rules); + uloop_run(); + + return 0; +} + void hotplug_shutdown(void) { uloop_fd_delete(&hotplug_fd); diff --git a/hotplug.h b/plug/hotplug.h index e33afcb..2a44442 100644 --- a/hotplug.h +++ b/plug/hotplug.h @@ -18,6 +18,7 @@ #include <libubox/uloop.h> void hotplug(char *rules); +int hotplug_run(char *rules); void hotplug_shutdown(void); void hotplug_last_event(uloop_timeout_handler handler); diff --git a/udevtrigger.c b/plug/udevtrigger.c index 5013189..5013189 100644 --- a/udevtrigger.c +++ b/plug/udevtrigger.c diff --git a/preinit.c b/preinit.c deleted file mode 100644 index c015ebd..0000000 --- a/preinit.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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/stat.h> -#include <sys/types.h> -#include <sys/mount.h> - -#include <unistd.h> -#include <unistd.h> - -#include "procd.h" -#include "hotplug.h" -#include "watchdog.h" - -static struct uloop_process preinit; - -static void spawn_procd(struct uloop_process *proc, int ret) -{ - char *wdt_fd = watchdog_fd(); - char *argv[] = { "/sbin/procd", NULL }; - struct stat s; - - if (!stat("/tmp/sysupgrade", &s)) - while (true) - sleep(1); - - unsetenv("INITRAMFS"); - unsetenv("PREINIT"); - DEBUG(1, "Exec to real procd now\n"); - if (wdt_fd) - setenv("WDTFD", wdt_fd, 1); - execvp(argv[0], argv); -} - -void procd_preinit(void) -{ - char *argv[] = { "/bin/sh", "/etc/preinit", NULL }; - - LOG("- preinit -\n"); - - setenv("PREINIT", "1", 1); - preinit.cb = spawn_procd; - preinit.pid = fork(); - if (!preinit.pid) { - execvp(argv[0], argv); - ERROR("Failed to start preinit\n"); - exit(-1); - } - - if (preinit.pid <= 0) { - ERROR("Failed to start new preinit instance\n"); - return; - } - - uloop_process_add(&preinit); - DEBUG(2, "Launched preinit instance, pid=%d\n", (int) preinit.pid); -} @@ -21,43 +21,30 @@ #include <libgen.h> #include "procd.h" -#include "hotplug.h" #include "watchdog.h" +#include "plug/hotplug.h" + +unsigned int debug; static int usage(const char *prog) { ERROR("Usage: %s [options]\n" "Options:\n" - " -s <path>: Path to ubus socket\n" - " -d: Enable debug messages\n" + "\t-s <path>\tPath to ubus socket\n" + "\t-h <path>\trun as hotplug daemon\n" + "\td\t\tEnable debug messages\n" "\n", prog); return 1; } - -static int main_procd_init(int argc, char **argv) -{ - procd_signal_preinit(); - procd_early(); - debug_init(); - watchdog_init(1); - system("/sbin/kmodloader /etc/modules-boot.d/"); - uloop_init(); - hotplug("/etc/hotplug-preinit.json"); - procd_preinit(); - uloop_run(); - return 0; -} - int main(int argc, char **argv) { int ch; - if (!strcmp(basename(*argv), "init")) - return main_procd_init(argc, argv); - - while ((ch = getopt(argc, argv, "ds:")) != -1) { + while ((ch = getopt(argc, argv, "ds:h:")) != -1) { switch (ch) { + case 'h': + return hotplug_run(optarg); case 's': ubus_socket = optarg; break; @@ -22,37 +22,17 @@ #include <stdio.h> #include <syslog.h> -#include "syslog.h" +#include "log.h" #define __init __attribute__((constructor)) -#define DEBUG(level, fmt, ...) do { \ - if (debug >= level) \ - fprintf(stderr, "procd: %s(%d): " fmt, __func__, __LINE__, ## __VA_ARGS__); \ - } while (0) - -#define LOG(fmt, ...) do { \ - log_printf(fmt, ## __VA_ARGS__); \ - fprintf(stderr, "procd: "fmt, ## __VA_ARGS__); \ - } while (0) - -#define ERROR(fmt, ...) do { \ - log_printf(fmt, ## __VA_ARGS__); \ - fprintf(stderr, "procd: "fmt, ## __VA_ARGS__); \ - } while (0) - extern char *ubus_socket; extern int upgrade_running; -extern unsigned int debug; -void debug_init(void); - void procd_connect_ubus(void); void procd_reconnect_ubus(int reconnect); void ubus_init_service(struct ubus_context *ctx); -void ubus_init_log(struct ubus_context *ctx); void ubus_init_system(struct ubus_context *ctx); -void ubus_notify_log(struct log_head *l); void procd_state_next(void); void procd_shutdown(int event); @@ -64,21 +44,10 @@ void procd_signal_preinit(void); void procd_inittab(void); void procd_inittab_run(const char *action); -int mkdev(const char *progname, int progmode); - struct trigger; void trigger_init(void); void trigger_event(char *type, struct blob_attr *data); void trigger_add(struct blob_attr *rule, void *id); void trigger_del(void *id); -struct pid_info { - char stat; - uint32_t ppid; - uint32_t fdcount; - uint32_t vmsize; - uint16_t uid; -}; -int measure_process(pid_t pid, struct pid_info *pi); - #endif @@ -55,7 +55,7 @@ static void pipe_cb(struct ustream *s, int bytes) break; *newline = 0; len = newline + 1 - str; - log_printf(buf->data); + syslog(0, buf->data); ustream_consume(s, len); } while (1); } @@ -66,7 +66,7 @@ static void q_initd_run(struct runqueue *q, struct runqueue_task *t) int pipefd[2]; pid_t pid; - DEBUG(1, "start %s %s \n", s->file, s->param); + DEBUG(2, "start %s %s \n", s->file, s->param); if (pipe(pipefd) == -1) { ERROR("Failed to create pipe\n"); return; @@ -96,7 +96,7 @@ static void q_initd_complete(struct runqueue *q, struct runqueue_task *p) { struct initd *s = container_of(p, struct initd, proc.task); - DEBUG(1, "stop %s %s \n", s->file, s->param); + DEBUG(2, "stop %s %s \n", s->file, s->param); ustream_free(&s->fd.stream); close(s->fd.fd.fd); free(s); @@ -126,10 +126,10 @@ static int _rc(struct runqueue *q, char *path, const char *file, char *pattern, int j; - DEBUG(1, "running %s/%s%s %s\n", path, file, pattern, param); + DEBUG(2, "running %s/%s%s %s\n", path, file, pattern, param); snprintf(dir, sizeof(dir), "%s/%s%s", path, file, pattern); if (glob(dir, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) { - printf("glob failed on %s\n", dir); + DEBUG(2, "glob failed on %s\n", dir); return -1; } diff --git a/instance.c b/service/instance.c index 05b0f99..5ac7d57 100644 --- a/instance.c +++ b/service/instance.c @@ -20,10 +20,12 @@ #include <stdint.h> #include <fcntl.h> -#include "procd.h" +#include "../procd.h" + #include "service.h" #include "instance.h" -#include "md5.h" + +#include "../utils/md5.h" enum { INSTANCE_ATTR_COMMAND, @@ -119,7 +121,7 @@ instance_start(struct service_instance *in) return; } - DEBUG(1, "Started instance %s::%s\n", in->srv->name, in->name); + DEBUG(2, "Started instance %s::%s\n", in->srv->name, in->name); in->proc.pid = pid; clock_gettime(CLOCK_MONOTONIC, &in->start); uloop_process_add(&in->proc); @@ -148,7 +150,7 @@ instance_exit(struct uloop_process *p, int ret) clock_gettime(CLOCK_MONOTONIC, &tp); runtime = tp.tv_sec - in->start.tv_sec; - DEBUG(1, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime); + DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime); if (upgrade_running) return; @@ -448,7 +450,6 @@ instance_init(struct service_instance *in, struct service *s, struct blob_attr * void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) { void *i; - struct pid_info pi; i = blobmsg_open_table(b, in->name); blobmsg_add_u8(b, "running", in->proc.pending); @@ -474,18 +475,6 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) if (verbose && in->trigger) blobmsg_add_blob(b, in->trigger); - if (!measure_process(in->proc.pid, &pi)) { - struct timespec tp; - long uptime; - - clock_gettime(CLOCK_MONOTONIC, &tp); - uptime = tp.tv_sec - in->start.tv_sec; - - blobmsg_add_u8(b, "ppid", pi.ppid); - blobmsg_add_u16(b, "uid", pi.uid); - blobmsg_add_u32(b, "fdcount", pi.fdcount); - blobmsg_add_u32(b, "vmsize", pi.vmsize); - blobmsg_add_u32(b, "uptime", uptime); - } + blobmsg_close_table(b, i); } diff --git a/instance.h b/service/instance.h index 6e69086..65b670e 100644 --- a/instance.h +++ b/service/instance.h @@ -17,7 +17,7 @@ #include <libubox/vlist.h> #include <libubox/uloop.h> -#include "utils.h" +#include "../utils/utils.h" #define RESPAWN_ERROR (5 * 60) diff --git a/service.c b/service/service.c index c5f5bf3..aa393b9 100644 --- a/service.c +++ b/service/service.c @@ -14,10 +14,13 @@ #include <libubox/blobmsg_json.h> #include <libubox/avl-cmp.h> -#include "procd.h" + +#include "../procd.h" + #include "service.h" #include "instance.h" -#include "rcS.h" + +#include "../rcS.h" struct avl_tree services; static struct blob_buf b; @@ -51,15 +54,15 @@ service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new, in_n = container_of(node_new, struct service_instance, node); if (in_o && in_n) { - DEBUG(1, "Update instance %s::%s\n", in_o->srv->name, in_o->name); + DEBUG(2, "Update instance %s::%s\n", in_o->srv->name, in_o->name); instance_update(in_o, in_n); instance_free(in_n); } else if (in_o) { - DEBUG(1, "Free instance %s::%s\n", in_o->srv->name, in_o->name); + DEBUG(2, "Free instance %s::%s\n", in_o->srv->name, in_o->name); instance_stop(in_o); instance_free(in_o); } else if (in_n) { - DEBUG(1, "Create instance %s::%s\n", in_n->srv->name, in_n->name); + DEBUG(2, "Create instance %s::%s\n", in_n->srv->name, in_n->name); instance_start(in_n); } } @@ -226,11 +229,11 @@ service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, s = avl_find_element(&services, name, s, avl); if (s) { - DEBUG(1, "Update service %s\n", name); + DEBUG(2, "Update service %s\n", name); return service_update(s, msg, tb, add); } - DEBUG(1, "Create service %s\n", name); + DEBUG(2, "Create service %s\n", name); s = service_alloc(name); if (!s) return UBUS_STATUS_UNKNOWN_ERROR; @@ -425,6 +428,34 @@ static struct ubus_object main_object = { .n_methods = ARRAY_SIZE(main_object_methods), }; +int +service_start_early(char *name, char *cmdline) +{ + void *instances, *instance, *command, *respawn; + char *t; + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "name", name); + instances = blobmsg_open_table(&b, "instances"); + instance = blobmsg_open_table(&b, "instance1"); + command = blobmsg_open_array(&b, "command"); + t = strtok(cmdline, " "); + while (t) { + blobmsg_add_string(&b, NULL, t); + t = strtok(NULL, " "); + } + blobmsg_close_array(&b, command); + respawn = blobmsg_open_array(&b, "respawn"); + blobmsg_add_string(&b, NULL, "1"); + blobmsg_add_string(&b, NULL, "3600"); + blobmsg_add_string(&b, NULL, "10"); + blobmsg_close_array(&b, respawn); + blobmsg_close_table(&b, instance); + blobmsg_close_table(&b, instances); + + return service_handle_set(NULL, NULL, NULL, "add", b.head); +} + void ubus_init_service(struct ubus_context *ctx) { ubus_add_object(ctx, &main_object); diff --git a/service.h b/service/service.h index 6448e5e..46ba746 100644 --- a/service.h +++ b/service/service.h @@ -49,6 +49,7 @@ struct service { void service_validate_add(struct service *s, struct blob_attr *attr); void service_validate_dump(struct blob_buf *b, struct service *s); void service_validate_dump_all(struct blob_buf *b, char *p, char *s); +int service_start_early(char *name, char *cmdline); void service_validate_del(struct service *s); void service_validate_init(void); void service_init(void); diff --git a/trigger.c b/service/trigger.c index d14101e..41fb55d 100644 --- a/trigger.c +++ b/service/trigger.c @@ -30,7 +30,7 @@ #include <stdlib.h> #include <libgen.h> -#include "procd.h" +#include "../procd.h" struct trigger { struct list_head list; @@ -84,7 +84,7 @@ static void q_job_run(struct runqueue *q, struct runqueue_task *t) { struct job *j = container_of(t, struct job, proc.task); - DEBUG(2, "handle event %s\n", j->cmd->name); + DEBUG(4, "handle event %s\n", j->cmd->name); j->cmd->handler(j, j->exec, j->env); } @@ -150,7 +150,7 @@ static void handle_run_script(struct job *j, struct blob_attr *exec, struct blob return; } - if (debug < 2) { + if (debug < 3) { close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); diff --git a/service_validate.c b/service/validate.c index 3522cde..ca9bb39 100644 --- a/service_validate.c +++ b/service/validate.c @@ -14,7 +14,8 @@ #include <libubox/blobmsg_json.h> #include <libubox/avl-cmp.h> -#include "procd.h" +#include "../procd.h" + #include "service.h" enum { @@ -19,8 +19,6 @@ #include "procd.h" -static int preinit; - static void do_reboot(void) { LOG("reboot\n"); @@ -37,9 +35,6 @@ static void signal_shutdown(int signal, siginfo_t *siginfo, void *data) int event = 0; char *msg = NULL; - if (preinit) - do_reboot(); - switch(signal) { case SIGTERM: event = RB_AUTOBOOT; @@ -97,11 +92,3 @@ void procd_signal(void) sigaction(SIGKILL, &sa_dummy, NULL); sigaction(SIGSTOP, &sa_dummy, NULL); } - -void procd_signal_preinit(void) -{ - preinit = 1; - sigaction(SIGTERM, &sa_shutdown, NULL); - sigaction(SIGUSR1, &sa_shutdown, NULL); - sigaction(SIGUSR2, &sa_shutdown, NULL); -} @@ -18,9 +18,9 @@ #include "procd.h" #include "syslog.h" -#include "hotplug.h" +#include "plug/hotplug.h" #include "watchdog.h" -#include "service.h" +#include "service/service.h" enum { STATE_NONE = 0, @@ -49,10 +49,13 @@ static void state_enter(void) case STATE_INIT: // try to reopen incase the wdt was not available before coldplug watchdog_init(0); - LOG("- init -\n"); - log_init(); + LOG("- ubus -\n"); procd_connect_ubus(); + + LOG("- init -\n"); service_init(); + service_start_early("ubus", "/sbin/ubusd"); + procd_inittab(); procd_inittab_run("respawn"); procd_inittab_run("askconsole"); @@ -83,14 +86,14 @@ static void state_enter(void) void procd_state_next(void) { - DEBUG(2, "Change state %d -> %d\n", state, state + 1); + DEBUG(4, "Change state %d -> %d\n", state, state + 1); state++; state_enter(); } void procd_shutdown(int event) { - DEBUG(1, "Shutting down system with event %x\n", event); + DEBUG(2, "Shutting down system with event %x\n", event); reboot_event = event; state = STATE_SHUTDOWN; state_enter(); diff --git a/syslog.c b/syslog.c deleted file mode 100644 index 7a2839e..0000000 --- a/syslog.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * 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 <linux/un.h> - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> - -#include <fcntl.h> -#include <regex.h> -#include <time.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -#include <libubox/uloop.h> -#include <libubox/usock.h> -#include <libubox/ustream.h> - -#include "procd.h" -#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, 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; - } - - DEBUG(2, "-> %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 { - DEBUG(2, "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; -} - -void log_printf(char *fmt, ...) -{ - static int buffer_len = 128; - static char *buffer; - va_list ap; - int n = 0; - - do { - if (n) - buffer_len = n + 1; - if (!buffer) - buffer = malloc(buffer_len); - if (!buffer) - return; - va_start(ap, fmt); - n = vsnprintf(buffer, buffer_len, fmt, ap); - va_end(ap); - if (n < 1) - return; - if (n >= buffer_len) { - free(buffer); - buffer = NULL; - } - } while (n >= buffer_len); - - log_add(buffer, n, SOURCE_INTERNAL); -} - -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; - - DEBUG(1, "Opening %s\n", KLOG_DEFAULT_PROC); - fd = open(KLOG_DEFAULT_PROC, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - ERROR("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; - - DEBUG(1, "Opening %s\n", log_dev); - unlink(log_dev); - fd = usock(USOCK_UNIX | USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK, log_dev, NULL); - if (fd < 0) { - ERROR("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) { - ERROR("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(void) -{ - regcomp(&pat_prio, "^<([0-9]*)>(.*)", REG_EXTENDED); - regcomp(&pat_tstamp, "^\[[ 0]*([0-9]*).([0-9]*)] (.*)", REG_EXTENDED); - - if (log_buffer_init(log_size)) { - ERROR("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); -} @@ -25,7 +25,6 @@ #include "procd.h" #include "watchdog.h" -#include "hotplug.h" static struct blob_buf b; @@ -189,12 +188,7 @@ static int system_upgrade(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { - procd_reconnect_ubus(0); - log_shutdown(); - hotplug_shutdown(); - upgrade_running = 1; - return 0; } @@ -21,97 +21,46 @@ char *ubus_socket = NULL; static struct ubus_context *ctx; -static struct uloop_process ubus_proc; -static bool ubus_connected = false; -static struct uloop_timeout retry; -static int reconnect = 1; +static struct uloop_timeout ubus_timer; -static void procd_ubus_connection_lost(struct ubus_context *old_ctx); - -static void ubus_proc_cb(struct uloop_process *proc, int ret) +static void +ubus_reconnect_cb(struct uloop_timeout *timeout) { - /* nothing to do here */ + if (!ubus_reconnect(ctx, ubus_socket)) + ubus_add_uloop(ctx); + else + uloop_timeout_set(timeout, 2000); } -static void procd_restart_ubus(void) +static void +ubus_disconnect_cb(struct ubus_context *ctx) { - char *argv[] = { "ubusd", NULL, ubus_socket, NULL }; - - if (ubus_proc.pending) { - ERROR("Killing existing ubus instance, pid=%d\n", (int) ubus_proc.pid); - kill(ubus_proc.pid, SIGKILL); - uloop_process_delete(&ubus_proc); - } - - if (ubus_socket) - argv[1] = "-s"; - - ubus_proc.pid = fork(); - if (!ubus_proc.pid) { - setpriority(PRIO_PROCESS, 0, -20); - execvp(argv[0], argv); - exit(-1); - } - - if (ubus_proc.pid <= 0) { - ERROR("Failed to start new ubus instance\n"); - return; - } - - DEBUG(1, "Launched new ubus instance, pid=%d\n", (int) ubus_proc.pid); - uloop_process_add(&ubus_proc); + ubus_timer.cb = ubus_reconnect_cb; + uloop_timeout_set(&ubus_timer, 2000); } -static void procd_ubus_try_connect(void) +static void +ubus_connect_cb(struct uloop_timeout *timeout) { - if (ctx) { - ubus_connected = !ubus_reconnect(ctx, ubus_socket); - return; - } ctx = ubus_connect(ubus_socket); + if (!ctx) { - ubus_connected = false; - DEBUG(2, "Connection to ubus failed\n"); + DEBUG(4, "Connection to ubus failed\n"); + uloop_timeout_set(&ubus_timer, 1000); return; } - ctx->connection_lost = procd_ubus_connection_lost; - ubus_connected = true; + ctx->connection_lost = ubus_disconnect_cb; ubus_init_service(ctx); ubus_init_system(ctx); - if (getpid() == 1) - ubus_init_log(ctx); -} - -static void -procd_ubus_reconnect_timer(struct uloop_timeout *timeout) -{ - procd_ubus_try_connect(); - if (ubus_connected) { - DEBUG(1, "Connected to ubus, id=%08x\n", ctx->local_id); - ubus_add_uloop(ctx); - return; - } - uloop_timeout_set(&retry, 1000); - procd_restart_ubus(); + DEBUG(2, "Connected to ubus, id=%08x\n", ctx->local_id); + ubus_add_uloop(ctx); } -static void procd_ubus_connection_lost(struct ubus_context *old_ctx) +void +procd_connect_ubus(void) { - retry.cb = procd_ubus_reconnect_timer; - procd_restart_ubus(); - uloop_timeout_set(&retry, 1000); + ubus_timer.cb = ubus_connect_cb; + uloop_timeout_set(&ubus_timer, 1000); } - -void procd_connect_ubus(void) -{ - ubus_proc.cb = ubus_proc_cb; - procd_ubus_connection_lost(NULL); -} - -void procd_reconnect_ubus(int _reconnect) -{ - reconnect = _reconnect; -} - diff --git a/askfirst.c b/utils/askfirst.c index 6ad77aa..6ad77aa 100644 --- a/askfirst.c +++ b/utils/askfirst.c diff --git a/validate.c b/validate.c deleted file mode 100644 index f94a071..0000000 --- a/validate.c +++ /dev/null @@ -1,1002 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include <ctype.h> - -#include <arpa/inet.h> -#include <netinet/ether.h> -#include <sys/stat.h> - -#include "libvalidate.h" - -enum dt_optype { - OP_UNKNOWN, - OP_BOOL, - OP_NUMBER, - OP_STRING, - OP_FUNCTION -}; - -struct dt_fun; - -struct dt_op { - enum dt_optype type; - const char *next; - int length; - int nextop; - union { - bool boolean; - double number; - const char *string; - struct dt_fun *function; - } value; -}; - -struct dt_state { - int pos; - int depth; - const char *value; - struct dt_op stack[32]; -}; - -struct dt_fun { - const char *name; - bool (*call)(struct dt_state *s, int nargs); -}; - -static bool -dt_test_number(double number, const char *value) -{ - char *e; - double n; - - n = strtod(value, &e); - - return (e > value && *e == 0 && n == number); -} - -static bool -dt_test_string(const char *s, const char *end, const char *value) -{ - bool esc = false; - - while (*value) - { - if (s > end) - return false; - - if (!esc && *s == '\\') - { - s++; - - if (s >= end) - break; - - esc = true; - continue; - } - - if (*s != *value) - return false; - - esc = false; - value++; - s++; - } - - return (*s == *value || (s > end && *value == 0)); -} - -static bool -dt_step(struct dt_state *s); - -static bool -dt_call(struct dt_state *s); - -static bool -dt_type_or(struct dt_state *s, int nargs) -{ - while (nargs--) - if (dt_step(s)) - return true; - - return false; -} - -static bool -dt_type_and(struct dt_state *s, int nargs) -{ - while (nargs--) - if (!dt_step(s)) - return false; - - return true; -} - -static bool -dt_type_not(struct dt_state *s, int nargs) -{ - if (!nargs) - return false; - - return !dt_step(s); -} - -static bool -dt_type_neg(struct dt_state *s, int nargs) -{ - bool rv; - const char *value = s->value; - - if (!nargs) - return false; - - if (*s->value == '!') - while (isspace(*++s->value)); - - rv = dt_step(s); - s->value = value; - - return rv; -} - -static bool -dt_type_list(struct dt_state *s, int nargs) -{ - bool rv = true; - int pos = s->pos; - char *p, *str = strdup(s->value); - const char *value = s->value; - - if (!str || !nargs) - return false; - - for (p = strtok(str, " \t"); p; p = strtok(NULL, " \t")) - { - s->value = p; - - if (!dt_step(s)) - { - rv = false; - break; - } - - s->pos = pos; - } - - s->value = value; - free(str); - - return rv; -} - -static bool -dt_type_min(struct dt_state *s, int nargs) -{ - int n; - char *e; - - if (nargs >= 1 && s->stack[s->pos].type == OP_NUMBER) - { - n = strtol(s->value, &e, 0); - - return (e > s->value && *e == 0 && - n >= s->stack[s->pos].value.number); - } - - return false; -} - -static bool -dt_type_max(struct dt_state *s, int nargs) -{ - int n; - char *e; - - if (nargs >= 1 && s->stack[s->pos].type == OP_NUMBER) - { - n = strtol(s->value, &e, 0); - - return (e > s->value && *e == 0 && - n <= s->stack[s->pos].value.number); - } - - return false; -} - -static bool -dt_type_range(struct dt_state *s, int nargs) -{ - int n; - char *e; - - if (nargs >= 2 && - s->stack[s->pos].type == OP_NUMBER && - s->stack[s->pos + 1].type == OP_NUMBER) - { - n = strtol(s->value, &e, 0); - - return (e > s->value && *e == 0 && - n >= s->stack[s->pos].value.number && - n <= s->stack[s->pos + 1].value.number); - } - - return false; -} - -static bool -dt_type_minlen(struct dt_state *s, int nargs) -{ - if (nargs >= 1 && s->stack[s->pos].type == OP_NUMBER) - return (strlen(s->value) >= s->stack[s->pos].value.number); - - return false; -} - -static bool -dt_type_maxlen(struct dt_state *s, int nargs) -{ - if (nargs >= 1 && s->stack[s->pos].type == OP_NUMBER) - return (strlen(s->value) <= s->stack[s->pos].value.number); - - return false; -} - -static bool -dt_type_rangelen(struct dt_state *s, int nargs) -{ - if (nargs >= 2 && - s->stack[s->pos].type == OP_NUMBER && - s->stack[s->pos + 1].type == OP_NUMBER) - return (strlen(s->value) >= s->stack[s->pos].value.number && - strlen(s->value) <= s->stack[s->pos + 1].value.number); - - return false; -} - -static bool -dt_type_int(struct dt_state *s, int nargs) -{ - char *e; - - strtol(s->value, &e, 0); - - return (e > s->value && *e == 0); -} - -static bool -dt_type_uint(struct dt_state *s, int nargs) -{ - int n; - char *e; - - n = strtol(s->value, &e, 0); - - return (e > s->value && *e == 0 && n >= 0); -} - -static bool -dt_type_float(struct dt_state *s, int nargs) -{ - char *e; - - strtod(s->value, &e); - - return (e > s->value && *e == 0); -} - -static bool -dt_type_ufloat(struct dt_state *s, int nargs) -{ - int n; - char *e; - - n = strtod(s->value, &e); - - return (e > s->value && *e == 0 && n >= 0.0); -} - -static bool -dt_type_bool(struct dt_state *s, int nargs) -{ - int i; - const char *values[] = { - "0", "off", "false", "no", - "1", "on", "true", "yes" - }; - - for (i = 0; i < sizeof(values) / sizeof(values[0]); i++) - if (!strcasecmp(values[i], s->value)) - return true; - - return false; -} - -static bool -dt_type_string(struct dt_state *s, int nargs) -{ - return true; -} - -static bool -dt_type_ip4addr(struct dt_state *s, int nargs) -{ - struct in6_addr a; - return inet_pton(AF_INET, s->value, &a); -} - -static bool -dt_type_ip6addr(struct dt_state *s, int nargs) -{ - struct in6_addr a; - return inet_pton(AF_INET6, s->value, &a); -} - -static bool -dt_type_ipaddr(struct dt_state *s, int nargs) -{ - return (dt_type_ip4addr(s, 0) || dt_type_ip6addr(s, 0)); -} - -static bool -dt_type_netmask4(struct dt_state *s, int nargs) -{ - int i; - struct in_addr a; - - if (!inet_pton(AF_INET, s->value, &a)) - return false; - - if (a.s_addr == 0) - return true; - - a.s_addr = ntohl(a.s_addr); - - for (i = 0; (i < 32) && !(a.s_addr & (1 << i)); i++); - - return ((uint32_t)(~((1 << i) - 1)) == a.s_addr); -} - -static bool -dt_type_netmask6(struct dt_state *s, int nargs) -{ - int i; - struct in6_addr a; - - if (!inet_pton(AF_INET6, s->value, &a)) - return false; - - for (i = 0; (i < 16) && (a.s6_addr[i] == 0xFF); i++); - - if (i == 16) - return true; - - if ((a.s6_addr[i] != 255) && (a.s6_addr[i] != 254) && - (a.s6_addr[i] != 252) && (a.s6_addr[i] != 248) && - (a.s6_addr[i] != 240) && (a.s6_addr[i] != 224) && - (a.s6_addr[i] != 192) && (a.s6_addr[i] != 128) && - (a.s6_addr[i] != 0)) - return false; - - for (; (i < 16) && (a.s6_addr[i] == 0); i++); - - return (i == 16); -} - -static bool -dt_type_cidr4(struct dt_state *s, int nargs) -{ - int n; - struct in_addr a; - char *p, buf[sizeof("255.255.255.255/32\0")]; - - if (strlen(s->value) >= sizeof(buf)) - return false; - - strcpy(buf, s->value); - p = strchr(buf, '/'); - - if (p) - { - *p++ = 0; - - n = strtoul(p, &p, 10); - - if ((*p != 0) || (n > 32)) - return false; - } - - return inet_pton(AF_INET, buf, &a); -} - -static bool -dt_type_cidr6(struct dt_state *s, int nargs) -{ - int n; - struct in6_addr a; - char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128\0")]; - - if (strlen(s->value) >= sizeof(buf)) - return false; - - strcpy(buf, s->value); - p = strchr(buf, '/'); - - if (p) - { - *p++ = 0; - - n = strtoul(p, &p, 10); - - if ((*p != 0) || (n > 128)) - return false; - } - - return inet_pton(AF_INET6, buf, &a); -} - -static bool -dt_type_cidr(struct dt_state *s, int nargs) -{ - return (dt_type_cidr4(s, 0) || dt_type_cidr6(s, 0)); -} - -static bool -dt_type_ipmask4(struct dt_state *s, int nargs) -{ - bool rv; - struct in_addr a; - const char *value; - char *p, buf[sizeof("255.255.255.255/255.255.255.255\0")]; - - if (strlen(s->value) >= sizeof(buf)) - return false; - - strcpy(buf, s->value); - p = strchr(buf, '/'); - - if (p) - { - *p++ = 0; - - value = s->value; - s->value = p; - rv = dt_type_netmask4(s, 0); - s->value = value; - - if (!rv) - return false; - } - - return inet_pton(AF_INET, buf, &a); -} - -static bool -dt_type_ipmask6(struct dt_state *s, int nargs) -{ - bool rv; - struct in6_addr a; - const char *value; - char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/" - "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255\0")]; - - if (strlen(s->value) >= sizeof(buf)) - return false; - - strcpy(buf, s->value); - p = strchr(buf, '/'); - - if (p) - { - *p++ = 0; - - value = s->value; - s->value = p; - rv = dt_type_netmask6(s, 0); - s->value = value; - - if (!rv) - return false; - } - - return inet_pton(AF_INET6, buf, &a); -} - -static bool -dt_type_ipmask(struct dt_state *s, int nargs) -{ - return (dt_type_ipmask4(s, 0) || dt_type_ipmask6(s, 0)); -} - -static bool -dt_type_port(struct dt_state *s, int nargs) -{ - int n; - char *e; - - n = strtoul(s->value, &e, 10); - - return (e > s->value && *e == 0 && n <= 65535); -} - -static bool -dt_type_portrange(struct dt_state *s, int nargs) -{ - int n, m; - char *e; - - n = strtoul(s->value, &e, 10); - - if (e == s->value || *e != '-') - return false; - - m = strtoul(e + 1, &e, 10); - - return (*e == 0 && n <= 65535 && m <= 65535 && n <= m); -} - -static bool -dt_type_macaddr(struct dt_state *s, int nargs) -{ - return !!ether_aton(s->value); -} - -static bool -dt_type_uciname(struct dt_state *s, int nargs) -{ - const char *p; - - for (p = s->value; - *p && ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || - (*p >= '0' && *p <= '9') || (*p == '_')); - p++); - - return (*p == 0); -} - -static bool -dt_type_wpakey(struct dt_state *s, int nargs) -{ - int len = strlen(s->value); - const char *p = s->value; - - if (len == 64) - { - while (isxdigit(*p)) - p++; - - return (*p == 0); - } - - return (len >= 8 && len <= 63); -} - -static bool -dt_type_wepkey(struct dt_state *s, int nargs) -{ - int len = strlen(s->value); - const char *p = s->value; - - if (!strncmp(p, "s:", 2)) - { - len -= 2; - p += 2; - } - - if (len == 10 || len == 26) - { - while (isxdigit(*p)) - p++; - - return (*p == 0); - } - - return (len == 5 || len == 13); -} - -static bool -dt_type_hostname(struct dt_state *s, int nargs) -{ - const char *p, *last; - - for (p = last = s->value; *p; p++) - { - if (*p == '.') - { - if ((p - last) == 0 || (p - last) > 63) - return false; - - last = p + 1; - continue; - } - else if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || - (*p >= '0' && *p <= '9') || (*p == '_') || (*p == '-')) - { - continue; - } - - return false; - } - - return ((p - last) > 0 && (p - last) <= 255); -} - -static bool -dt_type_host(struct dt_state *s, int nargs) -{ - return (dt_type_hostname(s, 0) || dt_type_ipaddr(s, 0)); -} - -static bool -dt_type_network(struct dt_state *s, int nargs) -{ - return (dt_type_uciname(s, 0) || dt_type_host(s, 0)); -} - -static bool -dt_type_phonedigit(struct dt_state *s, int nargs) -{ - const char *p; - - for (p = s->value; - *p && ((*p >= '0' && *p <= '9') || (*p == '*') || (*p == '#') || - (*p == '!') || (*p == '.')); - p++); - - return (*p == 0); -} - -static bool -dt_type_directory(struct dt_state *s, int nargs) -{ - struct stat st; - return (!stat(s->value, &st) && S_ISDIR(st.st_mode)); -} - - -static bool -dt_type_device(struct dt_state *s, int nargs) -{ - struct stat st; - return (!stat(s->value, &st) && - (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))); -} - -static bool -dt_type_file(struct dt_state *s, int nargs) -{ - struct stat st; - return (!stat(s->value, &st) && S_ISREG(st.st_mode)); -} - - -static struct dt_fun dt_types[] = { - { "or", dt_type_or }, - { "and", dt_type_and }, - { "not", dt_type_not }, - { "neg", dt_type_neg }, - { "list", dt_type_list }, - { "min", dt_type_min }, - { "max", dt_type_max }, - { "range", dt_type_range }, - { "minlength", dt_type_minlen }, - { "maxlength", dt_type_maxlen }, - { "rangelength", dt_type_rangelen }, - { "integer", dt_type_int }, - { "uinteger", dt_type_uint }, - { "float", dt_type_float }, - { "ufloat", dt_type_ufloat }, - { "bool", dt_type_bool }, - { "string", dt_type_string }, - { "ip4addr", dt_type_ip4addr }, - { "ip6addr", dt_type_ip6addr }, - { "ipaddr", dt_type_ipaddr }, - { "cidr4", dt_type_cidr4 }, - { "cidr6", dt_type_cidr6 }, - { "cidr", dt_type_cidr }, - { "netmask4", dt_type_netmask4 }, - { "netmask6", dt_type_netmask6 }, - { "ipmask4", dt_type_ipmask4 }, - { "ipmask6", dt_type_ipmask6 }, - { "ipmask", dt_type_ipmask }, - { "port", dt_type_port }, - { "portrange", dt_type_portrange }, - { "macaddr", dt_type_macaddr }, - { "uciname", dt_type_uciname }, - { "wpakey", dt_type_wpakey }, - { "wepkey", dt_type_wepkey }, - { "hostname", dt_type_hostname }, - { "host", dt_type_host }, - { "network", dt_type_network }, - { "phonedigit", dt_type_phonedigit }, - { "directory", dt_type_directory }, - { "device", dt_type_device }, - { "file", dt_type_file }, - - { } -}; - -static struct dt_fun * -dt_lookup_function(const char *s, const char *e) -{ - struct dt_fun *fun = dt_types; - - while (fun->name) - { - if (!strncmp(fun->name, s, e - s) && *(fun->name + (e - s)) == '\0') - return fun; - - fun++; - } - - return NULL; -} - -static bool -dt_parse_atom(struct dt_state *s, const char *label, const char *end) -{ - char q, *e; - const char *p; - bool esc; - double dval; - struct dt_fun *func; - struct dt_op *op = &s->stack[s->depth]; - - if ((s->depth + 1) >= (sizeof(s->stack) / sizeof(s->stack[0]))) - { - printf("Syntax error, expression too long\n"); - return false; - } - - while (isspace(*label)) - label++; - - /* test whether label is a float */ - dval = strtod(label, &e); - - if (e > label) - { - op->next = e; - op->type = OP_NUMBER; - op->value.number = dval; - op->nextop = ++s->depth; - - return true; - } - else if ((*label == '"') || (*label == '\'')) - { - for (p = label + 1, q = *label, esc = false; p <= end; p++) - { - if (esc) - { - esc = false; - continue; - } - else if (*p == '\\') - { - esc = true; - continue; - } - else if (*p == q) - { - op->next = p + 1; - op->type = OP_STRING; - op->length = (p - label) - 2; - op->value.string = label + 1; - op->nextop = ++s->depth; - - return true; - } - } - - printf("Syntax error, unterminated string\n"); - return false; - } - else if (*label) - { - for (p = label; - p <= end && ((*p >= 'A' && *p <= 'Z') || - (*p >= 'a' && *p <= 'z') || - (*p >= '0' && *p <= '9') || - (*p == '_')); - p++); - - func = dt_lookup_function(label, p); - - if (!func) - { - printf("Syntax error, unrecognized function\n"); - return false; - } - - op->next = p; - op->type = OP_FUNCTION; - op->value.function = func; - op->nextop = ++s->depth; - - return true; - } - - printf("Syntax error, unexpected EOF\n"); - return false; -} - -static bool -dt_parse_list(struct dt_state *s, const char *code, const char *end); - -static bool -dt_parse_expr(const char *code, const char *end, struct dt_state *s) -{ - struct dt_op *tok; - - if (!dt_parse_atom(s, code, end)) - return false; - - tok = &s->stack[s->depth - 1]; - - while (isspace(*tok->next)) - tok->next++; - - if (tok->type == OP_FUNCTION) - { - if (*tok->next == '(') - { - end--; - - while (isspace(*end) && end > tok->next + 1) - end--; - - return dt_parse_list(s, tok->next + 1, end); - } - else if (tok->next == end) - { - return dt_parse_list(s, tok->next, tok->next); - } - - printf("Syntax error, expected '(' or EOF after function label\n"); - return false; - } - else if (tok->next == end) - { - return true; - } - - printf("Syntax error, expected ',' after literal\n"); - return false; -} - -static bool -dt_parse_list(struct dt_state *s, const char *code, const char *end) -{ - char c; - bool esc; - int nest; - const char *p, *last; - struct dt_op *fptr; - - if (!code) - return false; - - fptr = &s->stack[s->depth - 1]; - - for (nest = 0, p = last = code, esc = false, c = *p; - p <= end; - p++, c = (p < end) ? *p : '\0') - { - if (esc) - { - esc = false; - continue; - } - - switch (c) - { - case '\\': - esc = true; - break; - - case '(': - nest++; - break; - - case ')': - nest--; - break; - - case ',': - case '\0': - if (nest <= 0) - { - if (p > last) - { - if (!dt_parse_expr(last, p, s)) - return false; - - fptr->length++; - } - - last = p + 1; - } - - break; - } - } - - fptr->nextop = s->depth; - return true; -} - -static bool -dt_step(struct dt_state *s) -{ - bool rv; - struct dt_op *op = &s->stack[s->pos]; - - switch (op->type) - { - case OP_BOOL: - rv = op->value.boolean; - break; - - case OP_NUMBER: - rv = dt_test_number(op->value.number, s->value); - break; - - case OP_STRING: - rv = dt_test_string(op->value.string, op->value.string + op->length, s->value); - break; - - case OP_FUNCTION: - rv = dt_call(s); - break; - - default: - rv = false; - break; - } - - s->pos = op->nextop; - return rv; -} - -static bool -dt_call(struct dt_state *s) -{ - bool rv; - struct dt_op *fptr = &s->stack[s->pos]; - struct dt_fun *func = fptr->value.function; - - s->pos++; - - rv = func->call(s, fptr->length); - - s->pos = fptr->nextop; - - return rv; -} - -bool -dt_parse(const char *code, const char *value) -{ - struct dt_state s = { - .depth = 1, - .stack = { - { - .type = OP_FUNCTION, - .value.function = &dt_types[0], - .next = code - } - } - }; - - if (!value || !*value) - return false; - - if (!dt_parse_list(&s, code, code + strlen(code))) - return false; - - s.value = value; - - return dt_call(&s); -} diff --git a/validate_data.c b/validate_data.c deleted file mode 100644 index dc5e96b..0000000 --- a/validate_data.c +++ /dev/null @@ -1,28 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include <ctype.h> - -#include <arpa/inet.h> -#include <netinet/ether.h> -#include <sys/stat.h> - -#include "libvalidate.h" - -int main(int argc, char **argv) -{ - bool rv; - - if (argc == 3) { - rv = dt_parse(argv[1], argv[2]); - - printf("%s - %s = %s\n", argv[1], argv[2], rv ? "true" : "false"); - - return rv ? 0 : 1; - } else if (argc > 3) { - - } - - return 0; -} @@ -34,7 +34,7 @@ static int wdt_frequency = 5; static void watchdog_timeout_cb(struct uloop_timeout *t) { - DEBUG(2, "Ping\n"); + DEBUG(4, "Ping\n"); if (write(wdt_fd, "X", 1) < 0) ERROR("WDT failed to write: %s\n", strerror(errno)); uloop_timeout_set(t, wdt_frequency * 1000); @@ -59,7 +59,7 @@ int watchdog_timeout(int timeout) return 0; if (timeout) { - DEBUG(2, "Set watchdog timeout: %ds\n", timeout); + DEBUG(4, "Set watchdog timeout: %ds\n", timeout); ioctl(wdt_fd, WDIOC_SETTIMEOUT, &timeout); } ioctl(wdt_fd, WDIOC_GETTIMEOUT, &timeout); @@ -73,7 +73,7 @@ int watchdog_frequency(int frequency) return 0; if (frequency) { - DEBUG(2, "Set watchdog frequency: %ds\n", frequency); + DEBUG(4, "Set watchdog frequency: %ds\n", frequency); wdt_frequency = frequency; } @@ -100,7 +100,7 @@ void watchdog_init(int preinit) wdt_timeout.cb = watchdog_timeout_cb; if (env) { - DEBUG(1, "Watchdog handover: fd=%s\n", env); + DEBUG(2, "Watchdog handover: fd=%s\n", env); wdt_fd = atoi(env); unsetenv("WDTFD"); } else { @@ -117,5 +117,5 @@ void watchdog_init(int preinit) watchdog_timeout(30); watchdog_timeout_cb(&wdt_timeout); - DEBUG(2, "Opened watchdog with timeout %ds\n", watchdog_timeout(0)); + DEBUG(4, "Opened watchdog with timeout %ds\n", watchdog_timeout(0)); } |