diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | askconsole.c | 64 | ||||
-rw-r--r-- | inittab.c | 336 | ||||
-rw-r--r-- | procd.h | 3 | ||||
-rw-r--r-- | rcS.c | 183 | ||||
-rw-r--r-- | rcS.h | 24 | ||||
-rw-r--r-- | service/service.c | 4 | ||||
-rw-r--r-- | state.c | 16 |
8 files changed, 68 insertions, 564 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 30b1410..7419ca5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -SET(SOURCES procd.c signal.c watchdog.c state.c inittab.c rcS.c ubus.c system.c early.c +SET(SOURCES procd.c signal.c watchdog.c state.c askconsole.c ubus.c system.c early.c service/service.c service/instance.c service/trigger.c service/watch.c utils/utils.c) diff --git a/askconsole.c b/askconsole.c new file mode 100644 index 0000000..703024e --- /dev/null +++ b/askconsole.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Matthias Schiffer <mschiffer@universe-factory.net> + * + * 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 "procd.h" + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <fcntl.h> +#include <unistd.h> + + +static void askconsole(struct uloop_process *proc) { + char *const ask[] = { + "/sbin/askfirst", + "/bin/ash", + "--login", + NULL, + }; + + pid_t p; + + proc->pid = fork(); + if (!proc->pid) { + p = setsid(); + + fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) & ~O_NONBLOCK); + + ioctl(STDIN_FILENO, TIOCSCTTY, 1); + tcsetpgrp(STDIN_FILENO, p); + + execvp(ask[0], ask); + ERROR("Failed to execute %s\n", ask[0]); + exit(-1); + } + + if (proc->pid > 0) { + DEBUG(4, "Launched askconsole, pid=%d\n", + (int) proc->pid); + uloop_process_add(proc); + } +} + +static void child_exit(struct uloop_process *proc, int ret) +{ + DEBUG(4, "pid:%d\n", proc->pid); + askconsole(proc); +} + +void procd_askconsole(void) { + struct uloop_process *proc = malloc(sizeof(*proc)); + proc->cb = child_exit; + askconsole(proc); +} diff --git a/inittab.c b/inittab.c deleted file mode 100644 index 4675aca..0000000 --- a/inittab.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> - * Copyright (C) 2015 Matthias Schiffer <mschiffer@universe-factory.net> - * - * 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 <sys/ioctl.h> - -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <regex.h> -#include <ctype.h> - -#include <libubox/utils.h> -#include <libubox/list.h> - -#include "utils/utils.h" -#include "procd.h" -#include "rcS.h" - -#define TAG_ID 0 -#define TAG_RUNLVL 1 -#define TAG_ACTION 2 -#define TAG_PROCESS 3 - -#define MAX_ARGS 8 - -struct init_action; -char *console = NULL; - -struct init_handler { - const char *name; - void (*cb) (struct init_action *a); - int multi; -}; - -struct init_action { - struct list_head list; - - char *id; - char *argv[MAX_ARGS]; - char *line; - - struct init_handler *handler; - struct uloop_process proc; - - int respawn; - struct uloop_timeout tout; -}; - -static const char *tab = "/etc/inittab"; -static char *ask = "/sbin/askfirst"; - -static LIST_HEAD(actions); - -static int dev_open(const char *dev) -{ - int fd = -1; - - if (dev) { - if (chdir("/dev")) - ERROR("failed to change dir to /dev\n"); - fd = open(dev, O_RDWR); - if (chdir("/")) - ERROR("failed to change dir to /\n"); - } - - return fd; -} - -static int dev_exist(const char *dev) -{ - int res; - - res = dev_open(dev); - if (res != -1) - close(res); - - return (res != -1); -} - -static void fork_worker(struct init_action *a) -{ - int fd; - pid_t p; - - a->proc.pid = fork(); - if (!a->proc.pid) { - p = setsid(); - - fd = dev_open(a->id); - if (fd != -1) - { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - close(fd); - } - - ioctl(STDIN_FILENO, TIOCSCTTY, 1); - tcsetpgrp(STDIN_FILENO, p); - - execvp(a->argv[0], a->argv); - ERROR("Failed to execute %s\n", a->argv[0]); - exit(-1); - } - - if (a->proc.pid > 0) { - DEBUG(4, "Launched new %s action, pid=%d\n", - a->handler->name, - (int) a->proc.pid); - uloop_process_add(&a->proc); - } -} - -static void child_exit(struct uloop_process *proc, int ret) -{ - struct init_action *a = container_of(proc, struct init_action, proc); - - DEBUG(4, "pid:%d\n", proc->pid); - uloop_timeout_set(&a->tout, a->respawn); -} - -static void respawn(struct uloop_timeout *tout) -{ - struct init_action *a = container_of(tout, struct init_action, tout); - fork_worker(a); -} - -static void rcdone(struct runqueue *q) -{ - procd_state_next(); -} - -static void runrc(struct init_action *a) -{ - if (!a->argv[1] || !a->argv[2]) { - ERROR("valid format is rcS <S|K> <param>\n"); - return; - } - - /* proceed even if no init or shutdown scripts run */ - if (rcS(a->argv[1], a->argv[2], rcdone)) - rcdone(NULL); -} - -static void askfirst(struct init_action *a) -{ - int i; - - if (!dev_exist(a->id) || (console && !strcmp(console, a->id))) { - DEBUG(4, "Skipping %s\n", a->id); - return; - } - - a->tout.cb = respawn; - for (i = MAX_ARGS - 1; i >= 1; i--) - a->argv[i] = a->argv[i - 1]; - a->argv[0] = ask; - a->respawn = 500; - - a->proc.cb = child_exit; - fork_worker(a); -} - -static void askconsole(struct init_action *a) -{ - char line[256], *tty, *split; - int i; - - tty = get_cmdline_val("console", line, sizeof(line)); - if (tty != NULL) { - split = strchr(tty, ','); - if (split != NULL) - *split = '\0'; - - if (!dev_exist(tty)) { - DEBUG(4, "skipping %s\n", tty); - return; - } - - console = strdup(tty); - a->id = strdup(tty); - } - else { - console = NULL; - a->id = NULL; - } - - a->tout.cb = respawn; - for (i = MAX_ARGS - 1; i >= 1; i--) - a->argv[i] = a->argv[i - 1]; - a->argv[0] = ask; - a->respawn = 500; - - a->proc.cb = child_exit; - fork_worker(a); -} - -static void rcrespawn(struct init_action *a) -{ - a->tout.cb = respawn; - a->respawn = 500; - - a->proc.cb = child_exit; - fork_worker(a); -} - -static struct init_handler handlers[] = { - { - .name = "sysinit", - .cb = runrc, - }, { - .name = "shutdown", - .cb = runrc, - }, { - .name = "askfirst", - .cb = askfirst, - .multi = 1, - }, { - .name = "askconsole", - .cb = askconsole, - .multi = 1, - }, { - .name = "respawn", - .cb = rcrespawn, - .multi = 1, - } -}; - -static int add_action(struct init_action *a, const char *name) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(handlers); i++) - if (!strcmp(handlers[i].name, name)) { - a->handler = &handlers[i]; - list_add_tail(&a->list, &actions); - return 0; - } - ERROR("Unknown init handler %s\n", name); - return -1; -} - -void procd_inittab_run(const char *handler) -{ - struct init_action *a; - - list_for_each_entry(a, &actions, list) - if (!strcmp(a->handler->name, handler)) { - if (a->handler->multi) { - a->handler->cb(a); - continue; - } - a->handler->cb(a); - break; - } -} - -void procd_inittab(void) -{ -#define LINE_LEN 128 - FILE *fp = fopen(tab, "r"); - struct init_action *a; - regex_t pat_inittab; - regmatch_t matches[5]; - char *line; - - if (!fp) { - ERROR("Failed to open %s\n", tab); - return; - } - - regcomp(&pat_inittab, "([a-zA-Z0-9]*):([a-zA-Z0-9]*):([a-zA-Z0-9]*):(.*)", REG_EXTENDED); - line = malloc(LINE_LEN); - a = malloc(sizeof(struct init_action)); - memset(a, 0, sizeof(struct init_action)); - - while (fgets(line, LINE_LEN, fp)) { - char *tags[TAG_PROCESS + 1]; - char *tok; - int i; - int len = strlen(line); - - while (isspace(line[len - 1])) - len--; - line[len] = 0; - - if (*line == '#') - continue; - - if (regexec(&pat_inittab, line, 5, matches, 0)) - continue; - - DEBUG(4, "Parsing inittab - %s", line); - - for (i = TAG_ID; i <= TAG_PROCESS; i++) { - line[matches[i].rm_eo] = '\0'; - tags[i] = &line[matches[i + 1].rm_so]; - }; - - tok = strtok(tags[TAG_PROCESS], " "); - for (i = 0; i < (MAX_ARGS - 1) && tok; i++) { - a->argv[i] = tok; - tok = strtok(NULL, " "); - } - a->argv[i] = NULL; - a->id = tags[TAG_ID]; - a->line = line; - - if (add_action(a, tags[TAG_ACTION])) - continue; - line = malloc(LINE_LEN); - a = malloc(sizeof(struct init_action)); - memset(a, 0, sizeof(struct init_action)); - } - - fclose(fp); - free(line); - free(a); - regfree(&pat_inittab); -} @@ -45,8 +45,7 @@ void procd_preinit(void); void procd_coldplug(void); void procd_signal(void); void procd_signal_preinit(void); -void procd_inittab(void); -void procd_inittab_run(const char *action); +void procd_askconsole(void); void procd_bcast_event(char *event, struct blob_attr *msg); struct trigger; @@ -1,183 +0,0 @@ -/* - * runqueue-example.c - * - * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> - * Copyright (C) 2015 Matthias Schiffer <mschiffer@universe-factory.net> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <libubox/uloop.h> -#include <libubox/runqueue.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <glob.h> - -#include <libubox/ustream.h> - -#include "procd.h" -#include "rcS.h" - -static struct runqueue q, r; - -struct initd { - struct ustream_fd fd; - struct runqueue_process proc; - char *file; - char *param; -}; - -static void pipe_cb(struct ustream *s, int bytes) -{ - char *newline, *str; - int len; - - do { - str = ustream_get_read_buf(s, NULL); - if (!str) - break; - newline = strchr(str, '\n'); - if (!newline) - break; - *newline = 0; - len = newline + 1 - str; - syslog(LOG_NOTICE, "%s", str); -#ifdef SHOW_BOOT_ON_CONSOLE - fprintf(stderr, "%s\n", str); -#endif - ustream_consume(s, len); - } while (1); -} - -static void q_initd_run(struct runqueue *q, struct runqueue_task *t) -{ - struct initd *s = container_of(t, struct initd, proc.task); - int pipefd[2]; - pid_t pid; - - DEBUG(2, "start %s %s \n", s->file, s->param); - if (pipe(pipefd) == -1) { - ERROR("Failed to create pipe\n"); - return; - } - - pid = fork(); - if (pid < 0) - return; - - if (pid) { - close(pipefd[1]); - s->fd.stream.string_data = true, - s->fd.stream.notify_read = pipe_cb, - runqueue_process_add(q, &s->proc, pid); - ustream_fd_init(&s->fd, pipefd[0]); - return; - } - close(pipefd[0]); - dup2(pipefd[1], STDOUT_FILENO); - dup2(pipefd[1], STDERR_FILENO); - - execlp(s->file, s->file, s->param, NULL); - exit(1); -} - -static void q_initd_complete(struct runqueue *q, struct runqueue_task *p) -{ - struct initd *s = container_of(p, struct initd, proc.task); - - DEBUG(2, "stop %s %s \n", s->file, s->param); - ustream_free(&s->fd.stream); - close(s->fd.fd.fd); - free(s); -} - -static void add_initd(struct runqueue *q, char *file, char *param) -{ - static const struct runqueue_task_type initd_type = { - .run = q_initd_run, - .cancel = runqueue_process_cancel_cb, - .kill = runqueue_process_kill_cb, - }; - struct initd *s; - char *p, *f; - - s = calloc_a(sizeof(*s), &f, strlen(file) + 1, &p, strlen(param) + 1); - if (!s) { - ERROR("Out of memory in %s.\n", file); - return; - } - s->proc.task.type = &initd_type; - s->proc.task.complete = q_initd_complete; - if (!strcmp(param, "stop") || !strcmp(param, "shutdown")) - s->proc.task.run_timeout = 15000; - s->param = p; - s->file = f; - strcpy(s->param, param); - strcpy(s->file, file); - runqueue_task_add(q, &s->proc.task, false); -} - -static int _rc(struct runqueue *q, char *path, const char *file, char *pattern, char *param) -{ - char *dir = alloca(2 + strlen(path) + strlen(file) + strlen(pattern)); - glob_t gl; - int j; - - if (!dir) { - ERROR("Out of memory in %s.\n", file); - return -1; - } - - DEBUG(2, "running %s/%s%s %s\n", path, file, pattern, param); - sprintf(dir, "%s/%s%s", path, file, pattern); - if (glob(dir, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) { - DEBUG(2, "glob failed on %s\n", dir); - return -1; - } - - for (j = 0; j < gl.gl_pathc; j++) - add_initd(q, gl.gl_pathv[j], param); - - globfree(&gl); - - return 0; -} - -int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *)) -{ - runqueue_init(&q); - q.empty_cb = q_empty; - q.max_running_tasks = 1; - - return _rc(&q, "/etc/rc.d", pattern, "*", param); -} - -int rc(const char *file, char *param) -{ - return _rc(&r, "/etc/init.d", file, "", param); -} - -static void r_empty(struct runqueue *q) -{ - -} - -static void __attribute__((constructor)) rc_init() { - runqueue_init(&r); - r.empty_cb = r_empty; - r.max_running_tasks = 8; -} @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> - * Copyright (C) 2015 Matthias Schiffer <mschiffer@universe-factory.net> - * - * 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 __PROCD_RCS_H -#define __PROCD_RCS_H - -#include <libubox/runqueue.h> - -extern int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *)); -extern int rc(const char *file, char *param); - -#endif diff --git a/service/service.c b/service/service.c index 90f4d7c..a983cee 100644 --- a/service/service.c +++ b/service/service.c @@ -21,8 +21,6 @@ #include "service.h" #include "instance.h" -#include "../rcS.h" - struct avl_tree services; static struct blob_buf b; static struct ubus_context *ctx; @@ -132,8 +130,6 @@ service_update(struct service *s, struct blob_attr **tb, bool add) vlist_flush(&s->instances); } - rc(s->name, "running"); - return 0; } @@ -30,10 +30,8 @@ enum { STATE_NONE = 0, STATE_EARLY, - STATE_INIT, STATE_RUNNING, STATE_SHUTDOWN, - STATE_HALT, __STATE_MAX, }; @@ -106,19 +104,13 @@ static void state_enter(void) service_start_early("ubus", ubus_cmd); break; - case STATE_INIT: + case STATE_RUNNING: LOG("- init -\n"); - procd_inittab(); - procd_inittab_run("respawn"); - procd_inittab_run("askconsole"); - procd_inittab_run("askfirst"); - procd_inittab_run("sysinit"); + procd_askconsole(); // switch to syslog log channel ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd"); - break; - case STATE_RUNNING: LOG("- init complete -\n"); break; @@ -126,11 +118,7 @@ static void state_enter(void) /* Redirect output to the console for the users' benefit */ set_console(); LOG("- shutdown -\n"); - procd_inittab_run("shutdown"); sync(); - break; - - case STATE_HALT: // To prevent killed processes from interrupting the sleep signal(SIGCHLD, SIG_IGN); LOG("- SIGTERM processes -\n"); |