From 1a1f24721f9b0bd3b3a1ce45c23bdb8eaf314d02 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 13 Jun 2015 12:25:45 +0200 Subject: [PATCH] Refactor: introduce telinit and a new initctl tool w/ API - Reduce size of `helpers.c`, for linking against new `initctl` tool, by moving out functions to `pid.c` and `exec.c` - Add `AF_UNIX` API to Finit, to complement old `/dev/initctl` FIFO - Let old FIFO API be used by init/telinit: `init ` - Move all advanced initctl code from `client.c` to `initctl.c`, yes its a bit confusing to call the *new* tool the same as the old FIFO but this is more in line with what, e.g Upstart does. - Move all advanced server side code from `plugins/initctl.c` to `api.c` - Update TODO with upcoming inetd syntax change and dynamic events. - Temporarily fix display of inetd services from `initctl status -v` Signed-off-by: Joachim Nilsson --- Makefile | 12 +- TODO.md | 15 ++ client.c | 178 +++-------------- exec.c | 356 +++++++++++++++++++++++++++++++++ finit.c | 21 ++ finit.h | 4 + helpers.c | 495 +--------------------------------------------- helpers.h | 1 - inetd.c | 54 +++++ inetd.h | 1 + initctl.c | 264 +++++++++++++++++++++++++ pid.c | 174 ++++++++++++++++ plugins/initctl.c | 85 +------- private.h | 1 + svc.c | 4 +- 15 files changed, 934 insertions(+), 731 deletions(-) create mode 100644 exec.c create mode 100644 initctl.c create mode 100644 pid.c diff --git a/Makefile b/Makefile index 2ebd78fb..ad210288 100644 --- a/Makefile +++ b/Makefile @@ -33,11 +33,11 @@ DEV = $(NAME)-dev ARCHTOOL = `which git-archive-all` ARCHIVE = $(PKG).tar ARCHIVEZ = ../$(ARCHIVE).xz -EXEC = finit reboot +EXEC = finit initctl reboot HEADERS = plugin.h svc.h helpers.h queue.h DISTFILES = LICENSE README CHANGELOG finit.conf services -OBJS = finit.o client.o conf.o helpers.o sig.o svc.o service.o \ - plugin.o tty.o inetd.o +OBJS = finit.o api.o client.o conf.o exec.o helpers.o pid.o sig.o \ + svc.o service.o plugin.o tty.o inetd.o TOPDIR = $(shell pwd) -include config.mk @@ -74,6 +74,8 @@ config.h: configure finit: $(OBJS) +initctl: initctl.o svc.o helpers.o + reboot: reboot.o $(DEPLIBS) install-exec: all @@ -83,8 +85,8 @@ install-exec: all printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \ $(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \ done - printf " INSTALL $(DESTDIR)$(sbindir)/initctl\n" - @ln -sf finit $(DESTDIR)$(sbindir)/initctl + printf " INSTALL $(DESTDIR)$(sbindir)/telinit\n" + @ln -sf finit $(DESTDIR)$(sbindir)/telinit $(MAKE) -C libite install-exec $(MAKE) -C plugins install diff --git a/TODO.md b/TODO.md index bd087670..d9024454 100644 --- a/TODO.md +++ b/TODO.md @@ -27,6 +27,10 @@ General * Add support for listening to netlink messages for GW, ADDR, IF UP/DOWN * Add to let Finit know that a service does not support reload (SIGHUP), but must be restarted (stop+start) +* Allow custom reload for processes like libreSwan's pluto + + service [2345] /sbin/pluto + * Allow process callbacks to be scripts. * Add support for a pipe/popen where we can listen for `STOP`, `START` and `RELOAD` on `STDOUT` from a script ... call it for example @@ -55,6 +59,17 @@ to achieve compatibility would be to add a plugin to finit which reads Inetd ----- +wkz says we need deny rules and better syntax! we agrees + + +wkz --> inetd telnet/tcp @!eth0 +wkz --> inetd 2323/tcp @eth0 +wkz --> 77/udp wait [2345] @finit/time + +jnn --> telnet@eth0,eth1/tcp +jnn --> 2323@eth2/tcp +jnn --> 3000/udp wait [2345] time/internal + Optimize interface filtering by using socket filter. The functions `inet_*_peek()` and `inetd_is_allowed()` used for interace filtering should be possible to rewrite as socket filters. diff --git a/client.c b/client.c index 3d045f28..1adb0337 100644 --- a/client.c +++ b/client.c @@ -1,4 +1,4 @@ -/* Finit client for querying status and control services +/* Simple telinit client * * Copyright (c) 2008-2010 Claudio Matsuoka * Copyright (c) 2008-2015 Joachim Nilsson @@ -27,22 +27,18 @@ #include #include "finit.h" -#include "helpers.h" -#include "service.h" - #include "libite/lite.h" -typedef struct { - char *cmd; - int (*cb)(char *arg); -} command_t; - - -static int do_send(struct init_request *rq, ssize_t len) +static int do_send(int cmd, int runlevel) { int fd; - int result = -1; - ssize_t num; + int result = 255; + ssize_t len; + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = cmd, + .runlevel = runlevel, + }; if (!fexist(FINIT_FIFO)) { fprintf(stderr, "%s does not support %s!\n", __progname, FINIT_FIFO); @@ -55,127 +51,22 @@ static int do_send(struct init_request *rq, ssize_t len) return 1; } - num = write(fd, rq, len); - if (num == len) { - num = read(fd, rq, len); - if (num == len && rq->cmd == INIT_CMD_ACK) - result = 0; - } - + len = write(fd, &rq, sizeof(rq)); + if (sizeof(rq) == len) + result = 0; close(fd); return result; } -static int toggle_debug(char *UNUSED(arg)) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = INIT_CMD_DEBUG, - }; - - return do_send(&rq, sizeof(rq)); -} - -static int set_runlevel(char *arg) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = INIT_CMD_RUNLVL, - .runlevel = (int)arg[0], - }; - - return do_send(&rq, sizeof(rq)); -} - -static int do_svc(int cmd, char *jobid) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = cmd, - }; - - if (!jobid) { - if (cmd == INIT_CMD_RELOAD_SVC) { - rq.cmd = INIT_CMD_RELOAD; - goto exit; - } - - return 1; - } - strlcpy(rq.data, jobid, sizeof(rq.data)); - -exit: - return do_send(&rq, sizeof(rq)); -} - -static int do_start (char *arg) { return do_svc(INIT_CMD_START_SVC, arg); } -static int do_stop (char *arg) { return do_svc(INIT_CMD_STOP_SVC, arg); } -static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD_SVC, arg); } -static int do_restart(char *arg) { return do_svc(INIT_CMD_RESTART_SVC, arg); } - -static int show_version(char *UNUSED(arg)) -{ - puts("v" VERSION); - return 0; -} - -/* In verbose mode we skip the header and each service description. - * This in favor of having all info on one line so a machine can more - * easily parse it. */ -static int show_status(char *UNUSED(arg)) -{ - svc_t *svc; - - if (!verbose) { - printf("# Status PID Runlevels Service Description\n"); - printf("====================================================================================\n"); - } - - for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { - char jobid[10]; - - if (svc_is_unique(svc)) - snprintf(jobid, sizeof(jobid), "%d", svc->job); - else - snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); - - 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("%-6s %7s %-6d %-9s %s %s\n", jobid, svc_status(svc), svc->pid, - runlevel_string(svc->runlevels), svc->cmd, args); - } else { - printf("%-6s %7s %-6d %-9s %-20s %s\n", jobid, svc_status(svc), svc->pid, - runlevel_string(svc->runlevels), svc->cmd, svc->desc); - } - } - - return 0; -} - +/* telinit q | telinit <1-6> */ static int usage(int rc) { - fprintf(stderr, "Usage: %s [OPTIONS] [ | ]\n\n" + fprintf(stderr, "Usage: %s \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" - " q | reload Reload *.conf in /etc/finit.d/\n" - " runlevel <1-6> Set new runlevel\n" - " status Show status of services\n" - " start Start stopped service\n" - " stop Stop running service\n" - " restart Restart (stop/start) running service\n" - " reload Reload (SIGHUP) running service\n" - " version Show Finit version\n\n", __progname); + " -V, --version Show Finit version\n\n", __progname); return rc; } @@ -183,54 +74,33 @@ static int usage(int rc) int client(int argc, char *argv[]) { int c; - command_t command[] = { - { "debug", toggle_debug }, - { "q", do_reload }, /* SysV init compat. */ - { "reload", do_reload }, - { "runlevel", set_runlevel }, - { "status", show_status }, - { "start", do_start }, - { "stop", do_stop }, - { "restart", do_restart }, - { "version", show_version }, - { NULL, NULL } - }; struct option long_options[] = { - {"debug", 0, NULL, 'd'}, {"help", 0, NULL, 'h'}, - {"verbose", 0, NULL, 'v'}, + {"version", 0, NULL, 'v'}, {NULL, 0, NULL, 0} }; verbose = 0; - while ((c = getopt_long(argc, argv, "h?dv", long_options, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) { switch(c) { - case 'd': - toggle_debug(NULL); - break; + case 'v': + return puts("v" VERSION) == EOF; case 'h': case '?': return usage(0); - - case 'v': - verbose = 1; - break; } } if (optind < argc) { - char *cmd = argv[optind++]; - char *job = optind < argc ? argv[optind] : NULL; + int req = (int)argv[optind][0]; /* Compat: 'init <1-9>' */ - if (strlen(cmd) == 1 && isdigit((int)cmd[0])) - return set_runlevel(cmd); + if (isdigit(req)) + return do_send(INIT_CMD_RUNLVL, req); - for (c = 0; command[c].cmd; c++) { - if (!strcmp(command[c].cmd, cmd)) - return command[c].cb(job); - } + if (req == 'q' || req == 'Q') + return do_send(INIT_CMD_RELOAD, 0); } return usage(1); diff --git a/exec.c b/exec.c new file mode 100644 index 00000000..6bfb8138 --- /dev/null +++ b/exec.c @@ -0,0 +1,356 @@ +/* Functions for exec'ing processes + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2015 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include /* isdigit() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "finit.h" +#include "sig.h" +#include "helpers.h" +#include "libite/lite.h" + +#define NUM_ARGS 16 + + +/* Wait for process completion, returns status of waitpid(2) syscall */ +int complete(char *cmd, int pid) +{ + int status = 0; + + if (waitpid(pid, &status, 0) == -1) { + if (errno == EINTR) + _e("Caught unblocked signal waiting for %s, aborting.", cmd); + else if (errno == ECHILD) + _e("Caught SIGCHLD waiting for %s, aborting.", cmd); + else + _e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno)); + + return -1; + } + + return status; +} + +int run(char *cmd) +{ + int status, result, i = 0; + char *args[NUM_ARGS + 1], *arg, *backup; + pid_t pid; + + /* We must create a copy that is possible to modify. */ + backup = arg = strdup(cmd); + if (!arg) + return 1; /* Failed allocating a string to be modified. */ + + /* Split command line into tokens of an argv[] array. */ + args[i++] = strsep(&arg, "\t "); + while (arg && i < NUM_ARGS) { + /* Handle run("su -c \"dbus-daemon --system\" messagebus"); + * => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */ + if (*arg == '\'' || *arg == '"') { + char *p, delim[2] = " "; + + delim[0] = arg[0]; + args[i++] = arg++; + strsep(&arg, delim); + p = arg - 1; + *p = *delim; + *arg++ = 0; + } else { + args[i++] = strsep(&arg, "\t "); + } + } + args[i] = NULL; +#if 0 + _e("Splitting: '%s' =>", cmd); + for (i = 0; args[i]; i++) + _e("\t%s", args[i]); +#endif + if (i == NUM_ARGS && args[i]) { + _e("Command too long: %s", cmd); + free(backup); + errno = EOVERFLOW; + return 1; + } + + pid = fork(); + if (0 == pid) { + int i; + FILE *fp; + struct sigaction sa; + + /* Reset signal handlers that were set by the parent process */ + for (i = 1; i < NSIG; i++) + DFLSIG(sa, i, 0); + + /* Always redirect stdio for run() */ + fp = fopen("/dev/null", "w"); + if (fp) { + int fd = fileno(fp); + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + } + + sig_unblock(); + execvp(args[0], args); + + _exit(1); /* Only if execv() fails. */ + } else if (-1 == pid) { + _pe("%s", args[0]); + free(backup); + + return -1; + } + + status = complete(args[0], pid); + if (-1 == status) { + free(backup); + return 1; + } + + result = WEXITSTATUS(status); + if (WIFEXITED(status)) { + _d("Started %s and ended OK: %d", args[0], result); + } else if (WIFSIGNALED(status)) { + _d("Process %s terminated by signal %d", args[0], WTERMSIG(status)); + if (!result) + result = 1; /* Must alert callee that the command did complete successfully. + * This is necessary since not all programs trap signals and + * change their return code accordingly. --Jocke */ + } + + free(backup); + + return result; +} + +int run_interactive(char *cmd, char *fmt, ...) +{ + int status, oldout = 1, olderr = 2; + char line[LINE_SIZE]; + va_list ap; + FILE *fp; + + if (!cmd) { + errno = EINVAL; + return 1; + } + + if (verbose && fmt) { + va_start(ap, fmt); + vsnprintf(line, sizeof(line), fmt, ap); + va_end(ap); + + print_desc("", line); + } + + /* Redirect output from cmd to a tempfile */ + fp = tmpfile(); + if (fp && !debug) { + oldout = dup(STDOUT_FILENO); + olderr = dup(STDERR_FILENO); + dup2(fileno(fp), STDOUT_FILENO); + dup2(fileno(fp), STDERR_FILENO); + } + + /* Run cmd ... */ + status = run(cmd); + + /* Restore stderr/stdout */ + if (fp && !debug) { + if (oldout >= 0) { + dup2(oldout, STDOUT_FILENO); + close(oldout); + } + if (olderr >= 0) { + dup2(olderr, STDERR_FILENO); + close(olderr); + } + } + + if (verbose && fmt) + print_result(status); + + /* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */ + if (fp && !debug) { + size_t len, written; + + rewind(fp); + do { + len = fread(line, 1, sizeof(line), fp); + written = fwrite(line, len, sizeof(char), stderr); + } while (len > 0 && written == len); + } + + if (fp) + fclose(fp); + + return status; +} + +pid_t run_getty(char *cmd, char *args[], int console) +{ + pid_t pid = fork(); + + if (!pid) { + int fd; + char c; + + if (console) { + /* Detach from initial controlling TTY */ + vhangup(); + + close(STDERR_FILENO); + close(STDOUT_FILENO); + close(STDIN_FILENO); + + /* Attach TTY to console */ + fd = open(CONSOLE, O_RDWR); + if (fd != STDIN_FILENO) + exit(1); + + dup2(0, STDIN_FILENO); + dup2(0, STDOUT_FILENO); + dup2(0, STDERR_FILENO); + + prctl(PR_SET_NAME, "console", 0, 0, 0); + } + + sig_unblock(); + + setsid(); + + if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) + _pe("Failed TIOCSCTTY"); + + while (!fexist(SYNC_SHUTDOWN)) { + static const char msg[] = "\nPlease press Enter to activate this console."; + + if (fexist(SYNC_STOPPED)) { + sleep(1); + continue; + } + + if (console) { + (void)write(STDERR_FILENO, msg, sizeof(msg)); + while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') + continue; + } + if (fexist(SYNC_STOPPED)) + continue; + + execv(cmd, args); + } + + if (console) + close(fd); + + exit(0); + } + + return pid; +} + + +int run_parts(char *dir, char *cmd) +{ + struct dirent **e; + int i, num; + + num = scandir(dir, &e, NULL, alphasort); + if (num < 0) { + _d("No files found in %s, skipping ...", dir); + return -1; + } + + for (i = 0; i < num; i++) { + int j = 0; + pid_t pid = 0; + mode_t mode; + char *args[NUM_ARGS]; + char *name = e[i]->d_name; + char path[CMD_SIZE]; + + snprintf(path, sizeof(path), "%s/%s", dir, name); + mode = fmode(path); + if (!S_ISEXEC(mode) || S_ISDIR(mode)) { + _d("Skipping %s ...", path); + continue; + } + + /* Fill in args[], starting with full path to executable */ + args[j++] = path; + + /* If the callee didn't supply a run_parts() argument */ + if (!cmd) { + /* Check if Sservice or Kservice notation is used */ + _d("Checking if %s is a sysvinit startstop script ...", name); + if (name[0] == 'S' && isdigit(name[1])) { + args[j++] = "start"; + } else if (name[0] == 'K' && isdigit(name[1])) { + args[j++] = "stop"; + } + } else { + args[j++] = cmd; + } + args[j++] = NULL; + + pid = fork(); + if (!pid) { + _d("Calling %s ...", path); + sig_unblock(); + execv(path, args); + exit(0); + } + + complete(path, pid); + } + + while (num--) + free(e[num]); + free(e); + + return 0; +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/finit.c b/finit.c index 2d3de132..92111f5d 100644 --- a/finit.c +++ b/finit.c @@ -53,11 +53,29 @@ char *console = NULL; uev_ctx_t *ctx = NULL; /* Main loop context */ +static int banner(void) +{ + if (!verbose) + return 0; + + delline(); +#ifdef INIT_HEADING + echo("%s", INIT_HEADING); +#else + echo("Finit v" VERSION); + echo("==================================================================="); +#endif + return 0; +} int main(int argc, char* argv[]) { uev_ctx_t loop; + /* + * finit/init/telinit client tool uses /dev/initctl pipe + * for compatibility but initctl client tool uses socket + */ if (getpid() != 1) return client(argc, argv); @@ -190,6 +208,9 @@ int main(int argc, char* argv[]) if (quiet) verbose = 0; + /* Start new initctl API responder */ + api_init(&loop); + /* * Enter main loop to monior /dev/initctl and services */ diff --git a/finit.h b/finit.h index e5697897..dcbd0b9f 100644 --- a/finit.h +++ b/finit.h @@ -73,6 +73,9 @@ #define LINE_SIZE 1024 #define BUF_SIZE 4096 +/* We reuse the INIT_CMD_ for the new initctl tool, but telinit only + * supports changing runlevel and reloading the configuration. */ +#define INIT_SOCKET _PATH_VARRUN "finit.sock" #define INIT_MAGIC 0x03091969 #define INIT_CMD_RUNLVL 1 #define INIT_CMD_DEBUG 2 /* Toggle Finit debug */ @@ -81,6 +84,7 @@ #define INIT_CMD_STOP_SVC 5 #define INIT_CMD_RELOAD_SVC 6 /* SIGHUP service */ #define INIT_CMD_RESTART_SVC 7 /* STOP + START service */ +#define INIT_CMD_QUERY_INETD 8 #define INIT_CMD_NACK 254 #define INIT_CMD_ACK 255 diff --git a/helpers.c b/helpers.c index 5b7a0e52..c136f4cd 100644 --- a/helpers.c +++ b/helpers.c @@ -1,7 +1,7 @@ /* Misc. utility functions and C-library extensions for finit and its plugins * * Copyright (c) 2008-2010 Claudio Matsuoka - * Copyright (c) 2008-2014 Joachim Nilsson + * Copyright (c) 2008-2015 Joachim Nilsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,36 +22,22 @@ * THE SOFTWARE. */ -#include /* isdigit() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include "finit.h" #include "helpers.h" #include "private.h" -#include "sig.h" #include "libite/lite.h" -#define NUM_ARGS 16 -#define NUM_SCRIPTS 128 /* ought to be enough for anyone */ /* * Helpers to replace system() calls @@ -162,164 +148,6 @@ char *runlevel_string(int levels) 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) -{ - if (!verbose) - return 0; - - delline(); -#ifdef INIT_HEADING - echo("%s", INIT_HEADING); -#else - echo("Finit v" VERSION); - echo("==================================================================="); -#endif - return 0; -} - -/** - * pidfile_read - Reads a PID value from a pidfile. - * @pidfile: File containing PID, usually in /var/run/.pid - * - * This function takes a @pidfile and returns the PID found therein. - * - * Returns: - * On invalid @pidfile -1 and @errno set to %EINVAL, when @pidfile does not exist -1 - * and errno set to %ENOENT. When the pidfile is empty or when its contents cannot - * be translated this function returns zero (0), on success this function returns - * a PID value greater than one. PID 1 is reserved for the system init process. - */ -pid_t pidfile_read(char *pidfile) -{ - pid_t pid = 0; - char buf[16]; - FILE *fp; - - if (!pidfile) { - errno = EINVAL; - return -1; - } - - if (!fexist(pidfile)) - return -1; - - fp = fopen(pidfile, "r"); - if (!fp) - return -1; - - if (fgets(buf, sizeof(buf), fp)) { - errno = 0; - pid = (pid_t)strtol(buf, NULL, 10); - if (errno) - pid = 0; /* Failed conversion. */ - } - fclose(fp); - - return pid; -} - -/** - * pidfile_poll - Poll for the existence of a pidfile and return PID - * @cmd: Process name, or command, called to expect a pidfile - * @path: Path to pidfile to poll for - * - * This function polls for the pidfile at @path for at most 5 seconds - * before timing out. If the file is created within that time span the - * file is read and its PID contents returned. - * - * Returns: - * The PID read from @path, or zero on timeout. - */ -pid_t pidfile_poll(char *cmd, char *path) -{ - pid_t pid = 0; - int tries = 0; - - /* Timeout = 100 * 50ms = 5s */ - while (!fexist(path) && tries++ < 100) { - /* Wait 50ms between retries */ - usleep(50000); - } - - if (!fexist(path)) { - _e("Timeout! No PID found for %s, pidfile %s does not exist?", cmd, path); - pid = 0; - } else { - pid = pidfile_read(path); - } - - return pid; -} - - -/** - * pid_alive - Check if a given process ID is running - * @pid: Process ID to check for. - * - * Returns: - * %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0) - */ -int pid_alive(pid_t pid) -{ - char name[24]; /* Enough for max pid_t */ - - snprintf(name, sizeof(name), "/proc/%d", pid); - - return fexist(name); -} - - -/** - * pid_get_name - Find name of a process - * @pid: PID of process to find. - * @name: Pointer to buffer where to return process name, may be %NULL - * @len: Length in bytes of @name buffer. - * - * If @name is %NULL, or @len is zero the function will return - * a static string. This may be useful to one-off calls. - * - * Returns: - * %NULL on error, otherwise a va - */ -char *pid_get_name(pid_t pid, char *name, size_t len) -{ - int ret = 1; - FILE *fp; - char *pname, path[32]; - static char line[64]; - - snprintf(path, sizeof(path), "/proc/%d/status", pid); - fp = fopen(path, "r"); - if (fp) { - if (fgets(line, sizeof (line), fp)) { - pname = line + 6; /* Skip first part of line --> "Name:\t" */ - chomp(pname); - if (name) - strlcpy(name, pname, len); - ret = 0; /* Found it! */ - } - - fclose(fp); - } - - if (ret) - return NULL; - - if (name) - return name; - - return pname; -} - - static int print_timestamp(void) { #if defined(CONFIG_PRINTK_TIME) @@ -393,307 +221,6 @@ int print_result(int fail) return fail; } -/* Wait for process completion, returns status of waitpid(2) syscall */ -int complete(char *cmd, int pid) -{ - int status = 0; - - if (waitpid(pid, &status, 0) == -1) { - if (errno == EINTR) - _e("Caught unblocked signal waiting for %s, aborting.", cmd); - else if (errno == ECHILD) - _e("Caught SIGCHLD waiting for %s, aborting.", cmd); - else - _e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno)); - - return -1; - } - - return status; -} - -int run(char *cmd) -{ - int status, result, i = 0; - char *args[NUM_ARGS + 1], *arg, *backup; - pid_t pid; - - /* We must create a copy that is possible to modify. */ - backup = arg = strdup(cmd); - if (!arg) - return 1; /* Failed allocating a string to be modified. */ - - /* Split command line into tokens of an argv[] array. */ - args[i++] = strsep(&arg, "\t "); - while (arg && i < NUM_ARGS) { - /* Handle run("su -c \"dbus-daemon --system\" messagebus"); - * => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */ - if (*arg == '\'' || *arg == '"') { - char *p, delim[2] = " "; - - delim[0] = arg[0]; - args[i++] = arg++; - strsep(&arg, delim); - p = arg - 1; - *p = *delim; - *arg++ = 0; - } else { - args[i++] = strsep(&arg, "\t "); - } - } - args[i] = NULL; -#if 0 - _e("Splitting: '%s' =>", cmd); - for (i = 0; args[i]; i++) - _e("\t%s", args[i]); -#endif - if (i == NUM_ARGS && args[i]) { - _e("Command too long: %s", cmd); - free(backup); - errno = EOVERFLOW; - return 1; - } - - pid = fork(); - if (0 == pid) { - int i; - FILE *fp; - struct sigaction sa; - - /* Reset signal handlers that were set by the parent process */ - for (i = 1; i < NSIG; i++) - DFLSIG(sa, i, 0); - - /* Always redirect stdio for run() */ - fp = fopen("/dev/null", "w"); - if (fp) { - int fd = fileno(fp); - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - } - - sig_unblock(); - execvp(args[0], args); - - _exit(1); /* Only if execv() fails. */ - } else if (-1 == pid) { - _pe("%s", args[0]); - free(backup); - - return -1; - } - - status = complete(args[0], pid); - if (-1 == status) { - free(backup); - return 1; - } - - result = WEXITSTATUS(status); - if (WIFEXITED(status)) { - _d("Started %s and ended OK: %d", args[0], result); - } else if (WIFSIGNALED(status)) { - _d("Process %s terminated by signal %d", args[0], WTERMSIG(status)); - if (!result) - result = 1; /* Must alert callee that the command did complete successfully. - * This is necessary since not all programs trap signals and - * change their return code accordingly. --Jocke */ - } - - free(backup); - - return result; -} - -int run_interactive(char *cmd, char *fmt, ...) -{ - int status, oldout = 1, olderr = 2; - char line[LINE_SIZE]; - va_list ap; - FILE *fp; - - if (!cmd) { - errno = EINVAL; - return 1; - } - - if (verbose && fmt) { - va_start(ap, fmt); - vsnprintf(line, sizeof(line), fmt, ap); - va_end(ap); - - print_desc("", line); - } - - /* Redirect output from cmd to a tempfile */ - fp = tmpfile(); - if (fp && !debug) { - oldout = dup(STDOUT_FILENO); - olderr = dup(STDERR_FILENO); - dup2(fileno(fp), STDOUT_FILENO); - dup2(fileno(fp), STDERR_FILENO); - } - - /* Run cmd ... */ - status = run(cmd); - - /* Restore stderr/stdout */ - if (fp && !debug) { - if (oldout >= 0) { - dup2(oldout, STDOUT_FILENO); - close(oldout); - } - if (olderr >= 0) { - dup2(olderr, STDERR_FILENO); - close(olderr); - } - } - - if (verbose && fmt) - print_result(status); - - /* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */ - if (fp && !debug) { - size_t len, written; - - rewind(fp); - do { - len = fread(line, 1, sizeof(line), fp); - written = fwrite(line, len, sizeof(char), stderr); - } while (len > 0 && written == len); - } - - if (fp) - fclose(fp); - - return status; -} - -pid_t run_getty(char *cmd, char *args[], int console) -{ - pid_t pid = fork(); - - if (!pid) { - int fd; - char c; - - if (console) { - /* Detach from initial controlling TTY */ - vhangup(); - - close(STDERR_FILENO); - close(STDOUT_FILENO); - close(STDIN_FILENO); - - /* Attach TTY to console */ - fd = open(CONSOLE, O_RDWR); - if (fd != STDIN_FILENO) - exit(1); - - dup2(0, STDIN_FILENO); - dup2(0, STDOUT_FILENO); - dup2(0, STDERR_FILENO); - - prctl(PR_SET_NAME, "console", 0, 0, 0); - } - - sig_unblock(); - - setsid(); - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) - _pe("Failed TIOCSCTTY"); - - while (!fexist(SYNC_SHUTDOWN)) { - static const char msg[] = "\nPlease press Enter to activate this console."; - - if (fexist(SYNC_STOPPED)) { - sleep(1); - continue; - } - - if (console) { - (void)write(STDERR_FILENO, msg, sizeof(msg)); - while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') - continue; - } - if (fexist(SYNC_STOPPED)) - continue; - - execv(cmd, args); - } - - if (console) - close(fd); - - exit(0); - } - - return pid; -} - -int run_parts(char *dir, char *cmd) -{ - struct dirent **e; - int i, num; - - num = scandir(dir, &e, NULL, alphasort); - if (num < 0) { - _d("No files found in %s, skipping ...", dir); - return -1; - } - - for (i = 0; i < num; i++) { - int j = 0, status; - pid_t pid = 0; - mode_t mode; - char *args[NUM_ARGS]; - char *name = e[i]->d_name; - char path[CMD_SIZE]; - - snprintf(path, sizeof(path), "%s/%s", dir, name); - mode = fmode(path); - if (!S_ISEXEC(mode) || S_ISDIR(mode)) { - _d("Skipping %s ...", path); - continue; - } - - /* Fill in args[], starting with full path to executable */ - args[j++] = path; - - /* If the callee didn't supply a run_parts() argument */ - if (!cmd) { - /* Check if Sservice or Kservice notation is used */ - _d("Checking if %s is a sysvinit startstop script ...", name); - if (name[0] == 'S' && isdigit(name[1])) { - args[j++] = "start"; - } else if (name[0] == 'K' && isdigit(name[1])) { - args[j++] = "stop"; - } - } else { - args[j++] = cmd; - } - args[j++] = NULL; - - pid = fork(); - if (!pid) { - _d("Calling %s ...", path); - sig_unblock(); - execv(path, args); - exit(0); - } - waitpid(pid, &status, 0); - } - - while (num--) - free(e[num]); - free(e); - - return 0; -} - #ifndef ENABLE_STATIC int getuser(char *username) { @@ -716,10 +243,6 @@ int getgroup(char *group) } #endif -/* - * Other convenience functions - */ - void chomp(char *str) { char *x = strrchr(str, 0x0a); diff --git a/helpers.h b/helpers.h index dacbc429..c08fd98a 100644 --- a/helpers.h +++ b/helpers.h @@ -93,7 +93,6 @@ 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/inetd.c b/inetd.c index b7af01c9..a316a57c 100644 --- a/inetd.c +++ b/inetd.c @@ -390,6 +390,60 @@ int inetd_match(inetd_t *inetd, char *service, char *proto, char *port) return 0; } +/* Compose presentable string of inetd filters: !eth0,eth1,eth2,!eth3 */ +int inetd_filter_str(inetd_t *inetd, char *str, size_t len) +{ + int prev = 0; + char buf[42]; + inetd_filter_t *filter; + + if (!inetd || !str || len <= 0) { + _e("Dafuq?"); + return 1; + } + + snprintf(str, len, "%s allow ", inetd->name); + LIST_FOREACH(filter, &inetd->filters, link) { + char ifname[IFNAMSIZ]; + + if (filter->deny) + continue; + + if (!strlen(filter->ifname)) + snprintf(ifname, sizeof(ifname), "ANY"); + else + strlcpy(ifname, filter->ifname, sizeof(ifname)); + + snprintf(buf, sizeof(buf), "%s%s:%d", prev ? "," : "", + ifname, inetd->port); + prev = 1; + strlcat(str, buf, len); + } + + prev = 0; + LIST_FOREACH(filter, &inetd->filters, link) { + char ifname[IFNAMSIZ]; + + if (!filter->deny) + continue; + if (!prev) { + snprintf(buf, sizeof(buf), " deny "); + strlcat(str, buf, len); + } + + if (!strlen(filter->ifname)) + snprintf(ifname, sizeof(ifname), "ANY"); + else + strlcpy(ifname, filter->ifname, sizeof(ifname)); + + snprintf(buf, sizeof(buf), "%s%s", prev ? "," : "", ifname); + prev = 1; + strlcat(str, buf, len); + } + + return 0; +} + /* * This function is called to add a new, unique, inetd service. When an * ifname is given as argument this means *only* run service on this diff --git a/inetd.h b/inetd.h index 0431411e..ea3b7e9c 100644 --- a/inetd.h +++ b/inetd.h @@ -65,6 +65,7 @@ int inetd_del (inetd_t *inetd); int inetd_init (inetd_t *inetd, void *arg, char *ifname, char *port); int inetd_match (inetd_t *inetd, char *service, char *proto, char *port); +int inetd_filter_str (inetd_t *inetd, char *str, size_t len); int inetd_allow (inetd_t *inetd, char *ifname); int inetd_deny (inetd_t *inetd, char *ifname); diff --git a/initctl.c b/initctl.c new file mode 100644 index 00000000..2956fe88 --- /dev/null +++ b/initctl.c @@ -0,0 +1,264 @@ +/* New client tool, complements old /dev/initctl API and telinit tool + * + * Copyright (c) 2015 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "finit.h" +#include "helpers.h" +#include "service.h" + +#include "libite/lite.h" + +typedef struct { + char *cmd; + int (*cb)(char *arg); +} command_t; + +int debug = 0; +int verbose = 0; + + +static int do_send(struct init_request *rq, ssize_t len) +{ + int sd, result = 255; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = INIT_SOCKET, + }; + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + if (-1 == sd) + return -1; + + if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) + goto error; + + if (write(sd, rq, len) != len) + goto error; + + if (read(sd, rq, len) != len) + goto error; + + result = 0; + goto exit; +error: + perror("Failed communicating with finit"); +exit: + close(sd); + return result; +} + +static int toggle_debug(char *UNUSED(arg)) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_DEBUG, + }; + + return do_send(&rq, sizeof(rq)); +} + +static int set_runlevel(char *arg) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_RUNLVL, + .runlevel = (int)arg[0], + }; + + return do_send(&rq, sizeof(rq)); +} + +static int do_svc(int cmd, char *jobid) +{ + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = cmd, + }; + + if (!jobid) { + if (cmd == INIT_CMD_RELOAD_SVC) { + rq.cmd = INIT_CMD_RELOAD; + goto exit; + } + + return 1; + } + strlcpy(rq.data, jobid, sizeof(rq.data)); + +exit: + return do_send(&rq, sizeof(rq)); +} + +static int do_start (char *arg) { return do_svc(INIT_CMD_START_SVC, arg); } +static int do_stop (char *arg) { return do_svc(INIT_CMD_STOP_SVC, arg); } +static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD_SVC, arg); } +static int do_restart(char *arg) { return do_svc(INIT_CMD_RESTART_SVC, arg); } + +static int show_version(char *UNUSED(arg)) +{ + puts("v" VERSION); + return 0; +} + +/* In verbose mode we skip the header and each service description. + * This in favor of having all info on one line so a machine can more + * easily parse it. */ +static int show_status(char *UNUSED(arg)) +{ + svc_t *svc; + + if (!verbose) { + printf("# Status PID Runlevels Service Description\n"); + printf("====================================================================================\n"); + } + + for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { + int inetd = svc_is_inetd(svc); + char jobid[10]; + + if (svc_is_unique(svc)) + snprintf(jobid, sizeof(jobid), "%d", svc->job); + else + snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); + + if (verbose) { + int internal = !strcmp("internal", svc->cmd); + char *info, args[80] = ""; + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_QUERY_INETD, + }; + + printf("%-6s %7s %-6d %-9s ", jobid, svc_status(svc), svc->pid, runlevel_string(svc->runlevels)); + if (inetd) { + snprintf(rq.data, sizeof(rq.data), "%s", jobid); + if (do_send(&rq, sizeof(rq))) { + snprintf(args, sizeof(args), "Unknown inetd"); + info = args; + } else { + info = rq.data; + if (!internal) { + char *ptr = strchr(info, ' '); + if (ptr) + info = ptr + 1; + } + } + + printf("%s %s\n", svc->cmd, info); + } else { + int i; + + for (i = 1; i < MAX_NUM_SVC_ARGS; i++) { + strlcat(args, svc->args[i], sizeof(args)); + strlcat(args, " ", sizeof(args)); + } + + printf("%s %s\n", svc->cmd, args); + } + } else { + printf("%-6s %7s %-6d %-9s %-20s %s\n", jobid, svc_status(svc), svc->pid, + runlevel_string(svc->runlevels), svc->cmd, svc->desc); + } + } + + return 0; +} + +static int usage(int rc) +{ + fprintf(stderr, "Usage: %s [OPTIONS] \n\n" + "Options:\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" + " runlevel <1-6> Set new runlevel\n" + " status Show status of services\n" + " start Start stopped service\n" + " stop Stop running service\n" + " restart Restart (stop/start) running service\n" + " reload Reload (SIGHUP) running service\n" + " version Show Finit version\n\n", __progname); + + return rc; +} + +int main(int argc, char *argv[]) +{ + int c; + command_t command[] = { + { "debug", toggle_debug }, + { "reload", do_reload }, + { "runlevel", set_runlevel }, + { "status", show_status }, + { "start", do_start }, + { "stop", do_stop }, + { "restart", do_restart }, + { "version", show_version }, + { NULL, NULL } + }; + struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + verbose = 0; + while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) { + switch(c) { + case 'h': + case '?': + return usage(0); + + case 'v': + verbose = 1; + break; + } + } + + if (optind < argc) { + char *cmd = argv[optind++]; + char *arg = optind < argc ? argv[optind] : NULL; + + for (c = 0; command[c].cmd; c++) { + if (!strcmp(command[c].cmd, cmd)) + return command[c].cb(arg); + } + } + + return usage(1); +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/pid.c b/pid.c new file mode 100644 index 00000000..8298f22d --- /dev/null +++ b/pid.c @@ -0,0 +1,174 @@ +/* Misc. utility functions and C-library extensions for finit and its plugins + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2015 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "helpers.h" +#include "libite/lite.h" + + +/** + * pidfile_read - Reads a PID value from a pidfile. + * @pidfile: File containing PID, usually in /var/run/.pid + * + * This function takes a @pidfile and returns the PID found therein. + * + * Returns: + * On invalid @pidfile -1 and @errno set to %EINVAL, when @pidfile does not exist -1 + * and errno set to %ENOENT. When the pidfile is empty or when its contents cannot + * be translated this function returns zero (0), on success this function returns + * a PID value greater than one. PID 1 is reserved for the system init process. + */ +pid_t pidfile_read(char *pidfile) +{ + pid_t pid = 0; + char buf[16]; + FILE *fp; + + if (!pidfile) { + errno = EINVAL; + return -1; + } + + if (!fexist(pidfile)) + return -1; + + fp = fopen(pidfile, "r"); + if (!fp) + return -1; + + if (fgets(buf, sizeof(buf), fp)) { + errno = 0; + pid = (pid_t)strtol(buf, NULL, 10); + if (errno) + pid = 0; /* Failed conversion. */ + } + fclose(fp); + + return pid; +} + +/** + * pidfile_poll - Poll for the existence of a pidfile and return PID + * @cmd: Process name, or command, called to expect a pidfile + * @path: Path to pidfile to poll for + * + * This function polls for the pidfile at @path for at most 5 seconds + * before timing out. If the file is created within that time span the + * file is read and its PID contents returned. + * + * Returns: + * The PID read from @path, or zero on timeout. + */ +pid_t pidfile_poll(char *cmd, char *path) +{ + pid_t pid = 0; + int tries = 0; + + /* Timeout = 100 * 50ms = 5s */ + while (!fexist(path) && tries++ < 100) { + /* Wait 50ms between retries */ + usleep(50000); + } + + if (!fexist(path)) { + _e("Timeout! No PID found for %s, pidfile %s does not exist?", cmd, path); + pid = 0; + } else { + pid = pidfile_read(path); + } + + return pid; +} + + +/** + * pid_alive - Check if a given process ID is running + * @pid: Process ID to check for. + * + * Returns: + * %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0) + */ +int pid_alive(pid_t pid) +{ + char name[24]; /* Enough for max pid_t */ + + snprintf(name, sizeof(name), "/proc/%d", pid); + + return fexist(name); +} + + +/** + * pid_get_name - Find name of a process + * @pid: PID of process to find. + * @name: Pointer to buffer where to return process name, may be %NULL + * @len: Length in bytes of @name buffer. + * + * If @name is %NULL, or @len is zero the function will return + * a static string. This may be useful to one-off calls. + * + * Returns: + * %NULL on error, otherwise a va + */ +char *pid_get_name(pid_t pid, char *name, size_t len) +{ + int ret = 1; + FILE *fp; + char *pname, path[32]; + static char line[64]; + + snprintf(path, sizeof(path), "/proc/%d/status", pid); + fp = fopen(path, "r"); + if (fp) { + if (fgets(line, sizeof (line), fp)) { + pname = line + 6; /* Skip first part of line --> "Name:\t" */ + chomp(pname); + if (name) + strlcpy(name, pname, len); + ret = 0; /* Found it! */ + } + + fclose(fp); + } + + if (ret) + return NULL; + + if (name) + return name; + + return pname; +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/plugins/initctl.c b/plugins/initctl.c index f04a35f2..58e850b5 100644 --- a/plugins/initctl.c +++ b/plugins/initctl.c @@ -1,7 +1,7 @@ -/* Optional /dev/initctl FIFO monitor +/* Optional /dev/initctl FIFO monitor, for receiving commands from telinit * * Copyright (c) 2008-2010 Claudio Matsuoka - * Copyright (c) 2008-2014 Joachim Nilsson + * Copyright (c) 2008-2015 Joachim Nilsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,48 +53,6 @@ static void fifo_open(void) } } -static svc_t *convert_jobid(char *jobid) -{ - int job, id = 1; - char *token; - - if (!jobid) - return NULL; - - token = strtok(jobid, ":"); - if (!token) { - job = atoi(jobid); - } else { - job = atoi(token); - token = strtok(NULL, ""); - if (token) - id = atoi(token); - } - - _d("Got job %d id %d ...", job, id); - return svc_find_by_jobid(job, id); -} - -static int do_start(char *jobid) -{ - return service_start(convert_jobid(jobid)); -} - -static int do_stop(char *jobid) -{ - return service_stop(convert_jobid(jobid)); -} - -static int do_reload(char *jobid) -{ - return service_reload(convert_jobid(jobid)); -} - -static int do_restart(char *jobid) -{ - return service_restart(convert_jobid(jobid)); -} - /* Standard reboot/shutdown utilities talk to init using /dev/initctl. * We should check if the fifo was recreated and reopen it. */ @@ -102,9 +60,7 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) { struct init_request rq; - _d("Receiving request on descriptor %d, from %s ...", fd, FINIT_FIFO); while (1) { - int result = 0; ssize_t len = read(fd, &rq, sizeof(rq)); if (len <= 0) { @@ -119,7 +75,6 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) } _d("Nothing to do, bailing out."); - break; } @@ -128,7 +83,6 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) break; } - _d("Magic OK ..."); switch (rq.cmd) { case INIT_CMD_RUNLVL: switch (rq.runlevel) { @@ -160,51 +114,16 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) } break; - case INIT_CMD_DEBUG: - debug = !debug; - break; - case INIT_CMD_RELOAD: reload_finit_d(); break; - case INIT_CMD_START_SVC: - result = do_start(rq.data); - break; - - case INIT_CMD_STOP_SVC: - result = do_stop(rq.data); - break; - - case INIT_CMD_RELOAD_SVC: - result = do_reload(rq.data); - break; - - case INIT_CMD_RESTART_SVC: - result = do_restart(rq.data); - break; - - case INIT_CMD_ACK: - _d("Client failed reading ACK."); - goto leave; - default: _d("Unsupported cmd: %d", rq.cmd); break; } - - if (result) - rq.cmd = INIT_CMD_NACK; - else - rq.cmd = INIT_CMD_ACK; - len = write(fd, &rq, sizeof(rq)); - if (len != sizeof(rq)) - _d("Failed sending ACK/NACK back to client."); - else - sleep(1); /* Give client time to read FIFO */ } -leave: close(fd); fifo_open(); } diff --git a/private.h b/private.h index 5df2b861..9f3bde86 100644 --- a/private.h +++ b/private.h @@ -30,6 +30,7 @@ uev_ctx_t *ctx; /* Main loop context */ +int api_init (uev_ctx_t *ctx); int client (int argc, char *argv[]); void service_bootstrap(void); diff --git a/svc.c b/svc.c index 84b333a3..3dd1768d 100644 --- a/svc.c +++ b/svc.c @@ -308,9 +308,9 @@ char *svc_status(svc_t *svc) return "running"; if (svc_is_inetd(svc)) - return "waiting"; + return "inetd"; - return "stopped"; + return "waiting"; } /* Same base service, return unique ID */