aboutsummaryrefslogtreecommitdiffstats
path: root/doc/examples/daemon-dependencies
diff options
context:
space:
mode:
Diffstat (limited to 'doc/examples/daemon-dependencies')
-rw-r--r--doc/examples/daemon-dependencies/.gitignore10
-rw-r--r--doc/examples/daemon-dependencies/Makefile14
-rw-r--r--doc/examples/daemon-dependencies/README19
-rw-r--r--doc/examples/daemon-dependencies/announce.c28
-rw-r--r--doc/examples/daemon-dependencies/await-ready.c122
-rw-r--r--doc/examples/daemon-dependencies/await-started.c127
-rw-r--r--doc/examples/daemon-dependencies/cleanup.c25
-rwxr-xr-xdoc/examples/daemon-dependencies/d-network9
-rwxr-xr-xdoc/examples/daemon-dependencies/d-ntp11
-rwxr-xr-xdoc/examples/daemon-dependencies/d-ssh13
-rw-r--r--doc/examples/daemon-dependencies/init.c127
-rw-r--r--doc/examples/daemon-dependencies/require.c38
-rw-r--r--doc/examples/daemon-dependencies/start-daemon.c32
-rw-r--r--doc/examples/daemon-dependencies/test-daemon.c35
14 files changed, 610 insertions, 0 deletions
diff --git a/doc/examples/daemon-dependencies/.gitignore b/doc/examples/daemon-dependencies/.gitignore
new file mode 100644
index 0000000..0dac119
--- /dev/null
+++ b/doc/examples/daemon-dependencies/.gitignore
@@ -0,0 +1,10 @@
+run/
+announce
+await-ready
+await-started
+cleanup
+init
+require
+start-daemon
+test-daemon
+
diff --git a/doc/examples/daemon-dependencies/Makefile b/doc/examples/daemon-dependencies/Makefile
new file mode 100644
index 0000000..bf6fe88
--- /dev/null
+++ b/doc/examples/daemon-dependencies/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-dependencies/README b/doc/examples/daemon-dependencies/README
new file mode 100644
index 0000000..a9f5783
--- /dev/null
+++ b/doc/examples/daemon-dependencies/README
@@ -0,0 +1,19 @@
+Use-case example.
+
+This example shows how bus can be used in a init
+system to provide "aggressivly" parallel startup
+of daemons.
+
+
+First of, run make to build this example.
+
+To start the example run ./init. It will print in
+red export-statement you may want to run i other
+terminals. You will need to select at least one
+daemon, for example you can run `./init d-ntp`.
+The available pretend daemons are: d-network,
+d-ntp and d-ssh.
+
+When you are done run ./cleanup with BUS_INIT
+exported with the value printed by ./init.
+
diff --git a/doc/examples/daemon-dependencies/announce.c b/doc/examples/daemon-dependencies/announce.c
new file mode 100644
index 0000000..d928adb
--- /dev/null
+++ b/doc/examples/daemon-dependencies/announce.c
@@ -0,0 +1,28 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#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, 0));
+ t(bus_close(&bus));
+ return 0;
+
+fail:
+ perror("announce");
+ return 1;
+}
diff --git a/doc/examples/daemon-dependencies/await-ready.c b/doc/examples/daemon-dependencies/await-ready.c
new file mode 100644
index 0000000..fea2382
--- /dev/null
+++ b/doc/examples/daemon-dependencies/await-ready.c
@@ -0,0 +1,122 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#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, 0));
+ }
+ }
+ 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) {
+ if (fork() == 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(msg, ' ');
+ 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, 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-dependencies/await-started.c b/doc/examples/daemon-dependencies/await-started.c
new file mode 100644
index 0000000..99ba14f
--- /dev/null
+++ b/doc/examples/daemon-dependencies/await-started.c
@@ -0,0 +1,127 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#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, 0));
+ }
+ }
+ 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) {
+ if (fork() == 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(msg, ' ');
+ 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_RDONLY));
+ started = calloc(argc, 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-dependencies/cleanup.c b/doc/examples/daemon-dependencies/cleanup.c
new file mode 100644
index 0000000..f9ead6d
--- /dev/null
+++ b/doc/examples/daemon-dependencies/cleanup.c
@@ -0,0 +1,25 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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-dependencies/d-network b/doc/examples/daemon-dependencies/d-network
new file mode 100755
index 0000000..1b8c7dd
--- /dev/null
+++ b/doc/examples/daemon-dependencies/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-dependencies/d-ntp b/doc/examples/daemon-dependencies/d-ntp
new file mode 100755
index 0000000..0f29c7c
--- /dev/null
+++ b/doc/examples/daemon-dependencies/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-dependencies/d-ssh b/doc/examples/daemon-dependencies/d-ssh
new file mode 100755
index 0000000..487354e
--- /dev/null
+++ b/doc/examples/daemon-dependencies/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-dependencies/init.c b/doc/examples/daemon-dependencies/init.c
new file mode 100644
index 0000000..b7182c6
--- /dev/null
+++ b/doc/examples/daemon-dependencies/init.c
@@ -0,0 +1,127 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#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-dependencies/require.c b/doc/examples/daemon-dependencies/require.c
new file mode 100644
index 0000000..e378431
--- /dev/null
+++ b/doc/examples/daemon-dependencies/require.c
@@ -0,0 +1,38 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#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, 0));
+ }
+ }
+
+ bus_close(&bus);
+ return 0;
+
+fail:
+ perror("require");
+ bus_close(&bus);
+ return 1;
+}
+
diff --git a/doc/examples/daemon-dependencies/start-daemon.c b/doc/examples/daemon-dependencies/start-daemon.c
new file mode 100644
index 0000000..7c224d5
--- /dev/null
+++ b/doc/examples/daemon-dependencies/start-daemon.c
@@ -0,0 +1,32 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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-dependencies/test-daemon.c b/doc/examples/daemon-dependencies/test-daemon.c
new file mode 100644
index 0000000..32ee545
--- /dev/null
+++ b/doc/examples/daemon-dependencies/test-daemon.c
@@ -0,0 +1,35 @@
+#include <bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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, 0));
+ bus_close(&bus);
+ } else if (!strcmp(argv[2], "started")) {
+ argv[2] = "ready";
+ goto retry;
+ }
+ return 0;
+
+fail:
+ perror("test-daemon");
+ return 1;
+}
+