From ff7d8f209e2522d5065fe6244b910e80a92f389f Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 25 Apr 2015 22:58:04 +0200 Subject: start on a more complex example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- doc/examples/daemon-depedencies/.gitignore | 10 ++ doc/examples/daemon-depedencies/Makefile | 14 +++ doc/examples/daemon-depedencies/announce.c | 27 ++++++ doc/examples/daemon-depedencies/await-ready.c | 118 ++++++++++++++++++++++ doc/examples/daemon-depedencies/await-started.c | 123 +++++++++++++++++++++++ doc/examples/daemon-depedencies/cleanup.c | 24 +++++ doc/examples/daemon-depedencies/d-network | 9 ++ doc/examples/daemon-depedencies/d-ntp | 11 +++ doc/examples/daemon-depedencies/d-ssh | 13 +++ doc/examples/daemon-depedencies/init.c | 124 ++++++++++++++++++++++++ doc/examples/daemon-depedencies/require.c | 37 +++++++ doc/examples/daemon-depedencies/start-daemon.c | 31 ++++++ doc/examples/daemon-depedencies/test-daemon.c | 34 +++++++ 13 files changed, 575 insertions(+) create mode 100644 doc/examples/daemon-depedencies/.gitignore create mode 100644 doc/examples/daemon-depedencies/Makefile create mode 100644 doc/examples/daemon-depedencies/announce.c create mode 100644 doc/examples/daemon-depedencies/await-ready.c create mode 100644 doc/examples/daemon-depedencies/await-started.c create mode 100644 doc/examples/daemon-depedencies/cleanup.c create mode 100755 doc/examples/daemon-depedencies/d-network create mode 100755 doc/examples/daemon-depedencies/d-ntp create mode 100755 doc/examples/daemon-depedencies/d-ssh create mode 100644 doc/examples/daemon-depedencies/init.c create mode 100644 doc/examples/daemon-depedencies/require.c create mode 100644 doc/examples/daemon-depedencies/start-daemon.c create mode 100644 doc/examples/daemon-depedencies/test-daemon.c diff --git a/doc/examples/daemon-depedencies/.gitignore b/doc/examples/daemon-depedencies/.gitignore new file mode 100644 index 0000000..0dac119 --- /dev/null +++ b/doc/examples/daemon-depedencies/.gitignore @@ -0,0 +1,10 @@ +run/ +announce +await-ready +await-started +cleanup +init +require +start-daemon +test-daemon + diff --git a/doc/examples/daemon-depedencies/Makefile b/doc/examples/daemon-depedencies/Makefile new file mode 100644 index 0000000..bf6fe88 --- /dev/null +++ b/doc/examples/daemon-depedencies/Makefile @@ -0,0 +1,14 @@ +COMMANDS = announce await-ready await-started cleanup init require start-daemon test-daemon + +all: ${COMMANDS} + +%: %.c + ${CC} -Wall -Wextra -pedantic -std=c99 -lbus -o $@ $< + +clean: + -rm ${COMMANDS} + -rm -r run + + +.PHONY: all clean + diff --git a/doc/examples/daemon-depedencies/announce.c b/doc/examples/daemon-depedencies/announce.c new file mode 100644 index 0000000..3aacb55 --- /dev/null +++ b/doc/examples/daemon-depedencies/announce.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; + + +int main(int argc, char *argv[]) +{ + bus_t bus; + if (argc < 3) + return fprintf(stderr, "USAGE: %s state daemon", *argv), 2; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + sprintf(arg, "%ji %s %s", (intmax_t)getppid(), argv[1], argv[2]); + t(bus_write(&bus, arg)); + t(bus_close(&bus)); + return 0; + +fail: + perror("announce"); + return 1; +} diff --git a/doc/examples/daemon-depedencies/await-ready.c b/doc/examples/daemon-depedencies/await-ready.c new file mode 100644 index 0000000..03df950 --- /dev/null +++ b/doc/examples/daemon-depedencies/await-ready.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; +static int argc; +static char **argv; +static int remaining = 0; +static char *started = NULL; +static char msg[BUS_MEMORY_SIZE]; + + +static void announce_wait(pid_t pid) +{ + bus_t bus; + int i; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + for (i = 1; i < argc; i++) { + if (!started[i]) { + sprintf(arg, "%ji awaiting-ready %s", (intmax_t)pid, argv[i]); + t(bus_write(&bus, arg)); + } + } + t(bus_close(&bus)); + return; + +fail: + perror("await-ready"); +} + + +static int callback(const char *message, void *user_data) +{ + int i; + char *arg2; + char *arg3; + pid_t pid; + pid_t ppid; + + if (!message) { + ppid = getppid(); + pid = fork(); + if (pid == 0) { + announce_wait(ppid); + exit(0); + } else { + (void) waitpid(pid, NULL, 0); /* Let's pretend everything will go swimmingly. */ + } + return 1; + } + + strncpy(msg, message, BUS_MEMORY_SIZE - 1); + msg[BUS_MEMORY_SIZE - 1] = 0; + + arg2 = strchr(message, ' '); + if (!arg2) + return 1; + arg3 = strchr(++arg2, ' '); + if (!arg3) + return 1; + *arg3++ = 0; + + if (strcmp(arg2, "ready")) + return 1; + + for (i = 1; i < argc; i++) + if (!started[i] && !strcmp(argv[i], arg3)) + started[i] = 1, remaining--; + + return !!remaining; + (void) user_data; +} + + +int main(int argc_, char *argv_[]) +{ + bus_t bus; + int i; + + argc = argc_; + argv = argv_; + + if (argc < 2) + return fprintf(stderr, "USAGE: %s daemon...", *argv), 2; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_RDONLY)); + started = calloc(argc - 1, sizeof(char)); + t(started == NULL); + + started[0] = 1; + for (i = 1; i < argc; i++) { + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/ready-daemons\" >/dev/null", argv[i]); + if (!WEXITSTATUS(system(arg))) + started[i] = 1; + else + remaining++; + } + + if (remaining) + bus_read(&bus, callback, NULL); + + bus_close(&bus); + free(started); + return 0; + +fail: + perror("await-ready"); + bus_close(&bus); + free(started); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/await-started.c b/doc/examples/daemon-depedencies/await-started.c new file mode 100644 index 0000000..152f02c --- /dev/null +++ b/doc/examples/daemon-depedencies/await-started.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; +static int argc; +static char **argv; +static int remaining = 0; +static char *started = NULL; +static char msg[BUS_MEMORY_SIZE]; + + +static void announce_wait(pid_t pid) +{ + bus_t bus; + int i; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + for (i = 1; i < argc; i++) { + if (!started[i]) { + sprintf(arg, "%ji awaiting-started %s", (intmax_t)pid, argv[i]); + t(bus_write(&bus, arg)); + } + } + t(bus_close(&bus)); + return; + +fail: + perror("await-started"); +} + + +static int callback(const char *message, void *user_data) +{ + int i; + char *arg2; + char *arg3; + pid_t pid; + pid_t ppid; + + if (!message) { + ppid = getppid(); + pid = fork(); + if (pid == 0) { + announce_wait(ppid); + exit(0); + } else { + (void) waitpid(pid, NULL, 0); /* Let's pretend everything will go swimmingly. */ + } + return 1; + } + + strncpy(msg, message, BUS_MEMORY_SIZE - 1); + msg[BUS_MEMORY_SIZE - 1] = 0; + + arg2 = strchr(message, ' '); + if (!arg2) + return 1; + arg3 = strchr(++arg2, ' '); + if (!arg3) + return 1; + *arg3++ = 0; + + if (strcmp(arg2, "started") && strcmp(arg2, "ready")) + return 1; + + for (i = 1; i < argc; i++) + if (!started[i] && !strcmp(argv[i], arg3)) + started[i] = 1, remaining--; + + return !!remaining; + (void) user_data; +} + + +int main(int argc_, char *argv_[]) +{ + bus_t bus; + int i; + + argc = argc_; + argv = argv_; + + if (argc < 2) + return fprintf(stderr, "USAGE: %s daemon...", *argv), 2; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + started = calloc(argc - 1, sizeof(char)); + t(started == NULL); + + started[0] = 1; + for (i = 1; i < argc; i++) { + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/started-daemons\" >/dev/null", argv[i]); + if (!WEXITSTATUS(system(arg))) { + started[i] = 1; + } else { + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/ready-daemons\" >/dev/null", argv[i]); + if (!WEXITSTATUS(system(arg))) + started[i] = 1; + else + remaining++; + } + } + + if (remaining) + bus_read(&bus, callback, NULL); + + bus_close(&bus); + free(started); + return 0; + +fail: + perror("await-started"); + bus_close(&bus); + free(started); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/cleanup.c b/doc/examples/daemon-depedencies/cleanup.c new file mode 100644 index 0000000..d3803c3 --- /dev/null +++ b/doc/examples/daemon-depedencies/cleanup.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + + +int main() +{ + char *bus_address = getenv("BUS_INIT"); + if (!bus_address || !*bus_address) { + fprintf(stderr, "$BUS_INIT has not been set, its export statement " + "should have been printed in bold red by ./init\n"); + return 1; + } + t(bus_unlink(bus_address)); + return 0; + +fail: + perror("cleanup"); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/d-network b/doc/examples/daemon-depedencies/d-network new file mode 100755 index 0000000..1b8c7dd --- /dev/null +++ b/doc/examples/daemon-depedencies/d-network @@ -0,0 +1,9 @@ +#!/bin/sh +PATH=.:$PATH +d=d-network + +echo $d: starting +sleep 2 +echo $d: ready +announce ready $d + diff --git a/doc/examples/daemon-depedencies/d-ntp b/doc/examples/daemon-depedencies/d-ntp new file mode 100755 index 0000000..0f29c7c --- /dev/null +++ b/doc/examples/daemon-depedencies/d-ntp @@ -0,0 +1,11 @@ +#!/bin/sh +PATH=.:$PATH +d=d-ntp + +require d-network +echo $d: started +announce started $d +await-ready d-network +echo $d: ready +announce ready $d + diff --git a/doc/examples/daemon-depedencies/d-ssh b/doc/examples/daemon-depedencies/d-ssh new file mode 100755 index 0000000..487354e --- /dev/null +++ b/doc/examples/daemon-depedencies/d-ssh @@ -0,0 +1,13 @@ +#!/bin/sh +PATH=.:$PATH +d=d-ssh + +require d-network +echo $d: starting +sleep 1 +echo $d: started +announce started $d +sleep 1 +echo $d: ready +announce ready $d + diff --git a/doc/examples/daemon-depedencies/init.c b/doc/examples/daemon-depedencies/init.c new file mode 100644 index 0000000..09a6abf --- /dev/null +++ b/doc/examples/daemon-depedencies/init.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char msg[BUS_MEMORY_SIZE]; +static int argc; +static char **argv; +static char arg[4098]; + + +static void start_daemons() +{ + int i; + for (i = 1; i < argc; i++) + if (fork() == 0) + execl("./start-daemon", "./start-daemon", argv[i], NULL); +} + + +static int callback(const char *message, void *user_data) +{ + pid_t pid; + char *arg2; + char *arg3; + if (!message) { + pid = fork(); + t(pid == -1); + if (pid == 0) { + if (fork() == 0) { + start_daemons(); + } + exit(0); + } else { + (void) waitpid(pid, NULL, 0); /* Let's pretend everything will go swimmingly. */ + } + return 1; + } + + strncpy(msg, message, BUS_MEMORY_SIZE - 1); + msg[BUS_MEMORY_SIZE - 1] = 0; + + pid = fork(); + t(pid == -1); + + if (pid == 0) { + if (fork() == 0) { + arg2 = strchr(msg, ' '); + if (arg2 == NULL) + exit(0); + arg3 = strchr(++arg2, ' '); + if (arg3 == NULL) + exit(0); + *arg3++ = 0; + if (!strcmp(arg2, "require")) { + execl("./start-daemon", "./start-daemon", arg3, NULL); + } else if (!strcmp(arg2, "awaiting-started")) { + execl("./test-daemon", "./test-daemon", arg3, "started", NULL); + } else if (!strcmp(arg2, "awaiting-ready") || !strcmp(arg2, "awaiting")) { + execl("./test-daemon", "./test-daemon", arg3, "ready", NULL); + } else if (!strcmp(arg2, "started")) { + sprintf(arg, + "grep '^%s\\$' < \"${XDG_RUNTIME_DIR}/started-daemons\" >/dev/null || " + "echo %s >> \"${XDG_RUNTIME_DIR}/started-daemons\"", + arg3, arg3); + execlp("sh", "sh", "-c", arg, NULL); + } else if (!strcmp(arg2, "ready")) { + sprintf(arg, + "grep '^%s\\$' < \"${XDG_RUNTIME_DIR}/ready-daemons\" >/dev/null || " + "echo %s >> \"${XDG_RUNTIME_DIR}/ready-daemons\"", + arg3, arg3); + execlp("sh", "sh", "-c", arg, NULL); + } + } + exit(0); + } else { + (void) waitpid(pid, NULL, 0); /* Let's pretend everything will go swimmingly. */ + } + + return 1; + (void) user_data; + +fail: + perror("init"); + return -1; +} + + +int main(int argc_, char *argv_[]) +{ + char *bus_address = NULL; + bus_t bus; + argv = argv_; + argc = argc_; + if (argc < 2) { + fprintf(stderr, "USAGE: %s daemon...\n", *argv); + return 1; + } + t(setenv("XDG_RUNTIME_DIR", "./run", 1)); /* Real init systems with not have the period. */ + system("mkdir -p -- \"${XDG_RUNTIME_DIR}\""); + system("truncate -s 0 -- \"${XDG_RUNTIME_DIR}/started-daemons\""); + system("truncate -s 0 -- \"${XDG_RUNTIME_DIR}/ready-daemons\""); + t(bus_create(NULL, 1, &bus_address)); + fprintf(stderr, "\033[00;01;31mexport BUS_INIT=%s\033[00m\n", bus_address); + fprintf(stderr, "\033[00;31mexport XDG_RUNTIME_DIR=./run\033[00m\n"); + t(setenv("BUS_INIT", bus_address, 1)); + t(bus_open(&bus, bus_address, BUS_RDONLY)); + t(bus_read(&bus, callback, NULL)); + bus_close(&bus); + free(bus_address); + return 0; + +fail: + perror("init"); + bus_close(&bus); + free(bus_address); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/require.c b/doc/examples/daemon-depedencies/require.c new file mode 100644 index 0000000..b6f7945 --- /dev/null +++ b/doc/examples/daemon-depedencies/require.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; + + +int main(int argc, char *argv[]) +{ + bus_t bus; + int i; + if (argc < 2) + return fprintf(stderr, "USAGE: %s daemon...", *argv), 2; + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + + for (i = 1; i < argc; i++) { + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/started-daemons\" >/dev/null", argv[i]); + if (WEXITSTATUS(system(arg))) { + sprintf(arg, "%ji require %s", (intmax_t)getppid(), argv[i]); + t(bus_write(&bus, arg)); + } + } + + bus_close(&bus); + return 0; + +fail: + perror("require"); + bus_close(&bus); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/start-daemon.c b/doc/examples/daemon-depedencies/start-daemon.c new file mode 100644 index 0000000..acb85ad --- /dev/null +++ b/doc/examples/daemon-depedencies/start-daemon.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; + + +int main(int argc, char *argv[]) +{ + if (argc != 2) + return fprintf(stderr, "This program should be called from ./init\n"), 2; + + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/started-daemons\" >/dev/null", argv[1]); + if (!WEXITSTATUS(system(arg))) + return 0; + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/ready-daemons\" >/dev/null", argv[1]); + if (!WEXITSTATUS(system(arg))) + return 0; + + sprintf(arg, "./%s", argv[1]); + execlp(arg, arg, NULL); + perror("start-daemon"); + return 1; +} + diff --git a/doc/examples/daemon-depedencies/test-daemon.c b/doc/examples/daemon-depedencies/test-daemon.c new file mode 100644 index 0000000..86095a1 --- /dev/null +++ b/doc/examples/daemon-depedencies/test-daemon.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#define t(stmt) if (stmt) goto fail + + +static char arg[4098]; + + +int main(int argc, char *argv[]) +{ + bus_t bus; + if (argc != 3) + return fprintf(stderr, "This program should be called from ./init\n"), 2; +retry: + sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/%s-daemons\" >/dev/null", argv[1], argv[2]); + if (!WEXITSTATUS(system(arg))) { + t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY)); + sprintf(arg, "0 %s %s", argv[2], argv[1]); + t(bus_write(&bus, arg)); + bus_close(&bus); + } else if (!strcmp(argv[2], "started")) { + argv[2] = "ready"; + goto retry; + } + return 0; + +fail: + perror("test-daemon"); + return 1; +} + -- cgit v1.2.3-70-g09d2