aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2015-04-25 22:58:04 +0200
committerMattias Andrée <maandree@operamail.com>2015-04-25 22:58:04 +0200
commitff7d8f209e2522d5065fe6244b910e80a92f389f (patch)
tree666b25f57d3049d7e59d2518801da922b586159f
parentfix telephony-and-music for update api (diff)
downloadbus-ff7d8f209e2522d5065fe6244b910e80a92f389f.tar.gz
bus-ff7d8f209e2522d5065fe6244b910e80a92f389f.tar.bz2
bus-ff7d8f209e2522d5065fe6244b910e80a92f389f.tar.xz
start on a more complex example
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r--doc/examples/daemon-depedencies/.gitignore10
-rw-r--r--doc/examples/daemon-depedencies/Makefile14
-rw-r--r--doc/examples/daemon-depedencies/announce.c27
-rw-r--r--doc/examples/daemon-depedencies/await-ready.c118
-rw-r--r--doc/examples/daemon-depedencies/await-started.c123
-rw-r--r--doc/examples/daemon-depedencies/cleanup.c24
-rwxr-xr-xdoc/examples/daemon-depedencies/d-network9
-rwxr-xr-xdoc/examples/daemon-depedencies/d-ntp11
-rwxr-xr-xdoc/examples/daemon-depedencies/d-ssh13
-rw-r--r--doc/examples/daemon-depedencies/init.c124
-rw-r--r--doc/examples/daemon-depedencies/require.c37
-rw-r--r--doc/examples/daemon-depedencies/start-daemon.c31
-rw-r--r--doc/examples/daemon-depedencies/test-daemon.c34
13 files changed, 575 insertions, 0 deletions
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 <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));
+ 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 <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));
+ }
+ }
+ 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 <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));
+ }
+ }
+ 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 <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-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 <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-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 <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));
+ }
+ }
+
+ 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 <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-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 <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));
+ bus_close(&bus);
+ } else if (!strcmp(argv[2], "started")) {
+ argv[2] = "ready";
+ goto retry;
+ }
+ return 0;
+
+fail:
+ perror("test-daemon");
+ return 1;
+}
+