diff --git a/TODO.md b/TODO.md index 80684f2d..83ec7402 100644 --- a/TODO.md +++ b/TODO.md @@ -28,14 +28,9 @@ General service it monitors + `.sh`. * Add support for `/etc/sysctl.d` * Add compile-time supoprt for running `/bin/sh` instead of `getty` -* Add support for `init ` and `SIGHUP` to - have finit reload its `finit.conf`, but also -* Add support for inotify to automatically reload `finit.conf` * Implement `initctl stop|start|restart|reload|status ` and `service stop|start|restart|reload|status` on top * Add PRE and POST hooks for when switching between runlevels -* Add support for `init -v,--version | version` -* Cleanup move sources from top-level directory to `src/` and `include/` * Make sure to install `queue.h` to `$(PREFIX)/include/finit/queue.h` * Move `finit.conf` "check" command to plugin which checks `/etc/fstab` instead. This is the de-facto practice. But keep the check command diff --git a/client.c b/client.c index edb4d5dc..ef91bef9 100644 --- a/client.c +++ b/client.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ +#include #include #include @@ -31,107 +32,20 @@ #include "libite/lite.h" +typedef struct { + char *cmd; + int (*cb)(void); +} command_t; -static char *runlevel_string(svc_t *svc) -{ - int i, pos = 1;; - static char lvl[10] = "[]"; - for (i = 0; i < 10; i++) { - if (ISSET(svc->runlevels, i)) { - if (i == 0) - lvl[pos++] = 'S'; - else - lvl[pos++] = '0' + i; - } - } - lvl[pos++] = ']'; - lvl[pos] = 0; - - return lvl; -} - -static int status(void) -{ - svc_t *svc; - - printf("Status PID Runlevels Service Description\n"); - printf("==============================================================================\n"); - for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { - printf("%7s %-6d %-9s %-20s %s\n", - svc->pid ? "running" : "waiting", svc->pid, - runlevel_string(svc), svc->cmd, svc->desc); - } - - return 0; -} - -static int usage(int rc) -{ - fprintf(stderr, "Usage: %s [OPTIONS] [status | <1-6>]\n\n" - "Options:\n" - " -d, --debug Enable/Disable debug\n" - " -h, --help This help text\n\n" - "Commands:\n" - " status Show status of services\n\n", __progname); - - return rc; -} - -int client(int argc, char *argv[]) +static int do_send(struct init_request *rq, ssize_t len) { int fd; - int c; int result = -1; - ssize_t len; - struct { - char *cmd; - int (*cb)(void); - } command[] = { - { "status", status }, - { NULL, NULL } - }; - struct option long_options[] = { - {"debug", 0, NULL, 'd'}, - {"help", 0, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = 0 - }; - - while ((c = getopt_long(argc, argv, "h?d", long_options, NULL)) != EOF) { - switch(c) { - case 'd': - rq.cmd = INIT_CMD_DEBUG; - break; - - case 'h': - case '?': - return usage(0); - default: - return usage(1); - } - } - - if (!rq.cmd) { - if (argc < 2) { - fprintf(stderr, "Missing argument.\n"); - return usage(1); - } - - for (c = 0; command[c].cmd; c++) { - if (!strcmp(command[c].cmd, argv[1])) - return command[c].cb(); - } - - rq.cmd = INIT_CMD_RUNLVL; - rq.runlevel = (int)argv[1][0]; - } + ssize_t num; if (!fexist(FINIT_FIFO)) { - fprintf(stderr, "/sbin/init does not support %s!\n", FINIT_FIFO); + fprintf(stderr, "%s does not support %s!\n", __progname, FINIT_FIFO); return 1; } @@ -141,10 +55,10 @@ int client(int argc, char *argv[]) return 1; } - len = write(fd, &rq, sizeof(rq)); - if (len == sizeof(rq)) { - len = read(fd, &rq, sizeof(rq)); - if (len == sizeof(rq) && rq.cmd == INIT_CMD_ACK) + num = write(fd, rq, len); + if (num == len) { + num = read(fd, rq, len); + if (num == len && rq->cmd == INIT_CMD_ACK) result = 0; } @@ -153,6 +67,135 @@ int client(int argc, char *argv[]) return result; } +static int toggle_debug(void) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_DEBUG, + }; + + return do_send(&rq, sizeof(rq)); +} + +static int reload_conf(void) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_RELOAD, + }; + + return do_send(&rq, sizeof(rq)); +} + +static int set_runlevel(int lvl) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_RUNLVL, + .runlevel = lvl, + }; + + return do_send(&rq, sizeof(rq)); +} + +int show_version(void) +{ + return banner(); +} + +static int show_status(void) +{ + svc_t *svc; + + printf("Status PID Runlevels Service Description\n"); + printf("==============================================================================\n"); + for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { + printf("%7s %-6d %-9s %-20s %s\n", + svc->pid ? "running" : "waiting", svc->pid, + runlevel_string(svc->runlevels), svc->cmd, svc->desc); + if (verbose) { + int i; + char args[80] = ""; + + for (i = 1; i < MAX_NUM_SVC_ARGS; i++) { + strlcat(args, svc->args[i], sizeof(args)); + strlcat(args, " ", sizeof(args)); + } + printf(" %s\n", args); + } + } + + return 0; +} + +static int usage(int rc) +{ + fprintf(stderr, "Usage: %s [OPTIONS] [ | ]\n\n" + "Options:\n" + " -d, --debug Toggle Finit debug\n" + " -v, --verbose Verbose output\n" + " -h, --help This help text\n\n" + "Commands:\n" + " debug Toggle Finit debug\n" + " reload Reload *.conf in /etc/finit.d/\n" + " status Show status of services\n" + " version Show Finit version\n\n", __progname); + + return rc; +} + +int client(int argc, char *argv[]) +{ + int c; + command_t command[] = { + { "debug", toggle_debug }, + { "q", reload_conf }, /* SysV init compat. */ + { "reload", reload_conf }, +// { "runlevel", set_runlevel }, + { "status", show_status }, + { "version", show_version }, + { NULL, NULL } + }; + struct option long_options[] = { + {"debug", 0, NULL, 'd'}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + verbose = 0; + while ((c = getopt_long(argc, argv, "h?dv", long_options, NULL)) != EOF) { + switch(c) { + case 'd': + toggle_debug(); + break; + + case 'h': + case '?': + return usage(0); + + case 'v': + verbose = 1; + break; + } + } + + if (optind < argc) { + char *cmd = argv[optind]; + + /* Compat: 'init <1-9>' */ + if (strlen(cmd) == 1 && isdigit((int)cmd[0])) + return set_runlevel((int)cmd[0]); + + for (c = 0; command[c].cmd; c++) { + if (!strcmp(command[c].cmd, cmd)) + return command[c].cb(); + } + } + + return usage(1); +} + /** * Local Variables: * version-control: t diff --git a/conf.c b/conf.c index 3affdba2..dc799a64 100644 --- a/conf.c +++ b/conf.c @@ -54,6 +54,25 @@ static char *strip_line(char *line) return line; } +void parse_kernel_cmdline(void) +{ + FILE *fp; + char line[LINE_SIZE]; + + if ((fp = fopen("/proc/cmdline", "r")) != NULL) { + fgets(line, sizeof(line), fp); + _d("Kernel command line: %s", line); + + if (strstr(line, "finit_debug") || strstr(line, "--debug")) + debug = 1; + + if (!debug && strstr(line, "quiet")) + verbose = 0; + + fclose(fp); + } +} + /* Convert optional "[!123456789S]" string into a bitmask */ int parse_runlevels(char *runlevels) { @@ -378,6 +397,22 @@ int parse_finit_conf(char *file) return result; } +/* Called on SIGHUP or 'init q' */ +void reload_finit_d(void) +{ + /* Mark and sweep */ + svc_mark_dynamic(); + + /* Reload all *.conf in /etc/finit.d/ */ + parse_finit_d(rcsd); + + /* Reload dirty services */ + service_reload_dynamic(); + + /* Cleanup stale services */ + svc_clean_dynamic(service_unregister); +} + /** * Local Variables: diff --git a/finit.c b/finit.c index d270752c..37f5745d 100644 --- a/finit.c +++ b/finit.c @@ -52,34 +52,6 @@ char *console = NULL; uev_ctx_t *ctx = NULL; /* Main loop context */ -static void parse_kernel_cmdline(void) -{ - FILE *fp; - char line[LINE_SIZE]; - - if ((fp = fopen("/proc/cmdline", "r")) != NULL) { - fgets(line, sizeof(line), fp); - _d("Kernel command line: %s", line); - - if (strstr(line, "finit_debug") || strstr(line, "--debug")) - debug = 1; - - if (!debug && strstr(line, "quiet")) - verbose = 0; - - fclose(fp); - } -} - -static void banner(void) -{ - delline(); -#ifdef INIT_HEADING - echo("%s", INIT_HEADING); -#else - echo("Finit version " VERSION " (" WHOAMI ") " __DATE__ " " __TIME__); -#endif -} int main(int argc, char* argv[]) { diff --git a/finit.h b/finit.h index 51e66405..073340ad 100644 --- a/finit.h +++ b/finit.h @@ -76,6 +76,7 @@ #define INIT_MAGIC 0x03091969 #define INIT_CMD_RUNLVL 1 #define INIT_CMD_DEBUG 2 +#define INIT_CMD_RELOAD 3 #define INIT_CMD_ACK 255 struct init_request { @@ -99,9 +100,11 @@ extern char *console; extern char *__progname; /* conf.c */ -int parse_runlevels (char *runlevels); -int parse_finit_conf (char *file); -int parse_finit_d (char *dir); +void parse_kernel_cmdline (void); +int parse_runlevels (char *runlevels); +int parse_finit_conf (char *file); +int parse_finit_d (char *dir); +void reload_finit_d (void); #endif /* FINIT_H_ */ diff --git a/helpers.c b/helpers.c index 50884c0a..00190ddb 100644 --- a/helpers.c +++ b/helpers.c @@ -136,6 +136,50 @@ int atonum(char *str) return val; } +/** + * runlevel_string - Convert a bit encoded runlevel to .conf syntax + * @levels: Bit encoded runlevels + * + * Returns: + * Pointer to string on the form [2345] + */ +char *runlevel_string(int levels) +{ + int i, pos = 1;; + static char lvl[10] = "[]"; + + for (i = 0; i < 10; i++) { + if (ISSET(levels, i)) { + if (i == 0) + lvl[pos++] = 'S'; + else + lvl[pos++] = '0' + i; + } + } + lvl[pos++] = ']'; + lvl[pos] = 0; + + return lvl; +} + +/** + * banner - Show Finit version at boot or from cmdline + * + * This function prints the default Finit version, or a custom heading. + * + * Returns: + * This function is always successful, returning POSIX OK(0). + */ +int banner(void) +{ + delline(); +#ifdef INIT_HEADING + echo("%s", INIT_HEADING); +#else + echo("Finit version " VERSION " (" WHOAMI ") " __DATE__ " " __TIME__); +#endif + return 0; +} /** * pidfile_read - Reads a PID value from a pidfile. diff --git a/helpers.h b/helpers.h index 4d2d8257..aabc389d 100644 --- a/helpers.h +++ b/helpers.h @@ -95,6 +95,8 @@ int makepath (char *path); void ifconfig (char *ifname, char *addr, char *mask, int up); int atonum (char *str); +char *runlevel_string (int levels); +int banner (void); pid_t pidfile_read (char *pidfile); pid_t pidfile_poll (char *cmd, char *path); diff --git a/plugins/initctl.c b/plugins/initctl.c index e7dd08e9..52573c20 100644 --- a/plugins/initctl.c +++ b/plugins/initctl.c @@ -121,6 +121,10 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) debug = !debug; break; + case INIT_CMD_RELOAD: + reload_finit_d(); + break; + case INIT_CMD_ACK: _d("Client failed reading ACK."); goto leave; diff --git a/sig.c b/sig.c index b5fcbc39..5634136f 100644 --- a/sig.c +++ b/sig.c @@ -93,17 +93,7 @@ void do_shutdown(int sig) */ static void sighup_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - /* Mark and sweep */ - svc_mark_dynamic(); - - /* Reload all *.conf in /etc/finit.d/ */ - parse_finit_d(rcsd); - - /* Reload dirty services */ - service_reload_dynamic(); - - /* Cleanup stale services */ - svc_clean_dynamic(service_unregister); + reload_finit_d(); } /*