diff options
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | doc/index.html | 2 | ||||
-rw-r--r-- | doc/upgrade.html | 5 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/include/s6-rc/connection-common.h | 22 | ||||
-rw-r--r-- | src/include/s6-rc/connection.h | 16 | ||||
-rw-r--r-- | src/include/s6-rc/db.h | 76 | ||||
-rw-r--r-- | src/libs6rc/s6rc_connection_end.c | 14 | ||||
-rw-r--r-- | src/libs6rc/s6rc_connection_start.c | 22 | ||||
-rw-r--r-- | src/libs6rc/s6rc_monitor.c | 15 | ||||
-rw-r--r-- | src/libs6rcd/s6rcd.h | 9 | ||||
-rw-r--r-- | src/libs6rcd/s6rcd_db_load.c | 17 | ||||
-rw-r--r-- | src/libs6rcd/s6rcd_livedir_init.c | 124 | ||||
-rw-r--r-- | src/libs6rcd/s6rcd_livesubdir_create.c | 35 | ||||
-rw-r--r-- | src/s6-rc/s6-rcd.c | 770 | ||||
-rw-r--r-- | src/serverlib/deps-lib/s6rc (renamed from src/libs6rc/deps-lib/s6rc) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc-servicedir-internal.h (renamed from src/libs6rc/s6rc-servicedir-internal.h) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_check_depcycles.c (renamed from src/libs6rc/s6rc_db_check_depcycles.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_check_pipelines.c (renamed from src/libs6rc/s6rc_db_check_pipelines.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_check_revdeps.c (renamed from src/libs6rc/s6rc_db_check_revdeps.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_read.c (renamed from src/libs6rc/s6rc_db_read.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_read_sizes.c (renamed from src/libs6rc/s6rc_db_read_sizes.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_db_read_uint32.c (renamed from src/libs6rc/s6rc_db_read_uint32.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_graph_closure.c (renamed from src/libs6rc/s6rc_graph_closure.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_livedir_create.c (renamed from src/libs6rc/s6rc_livedir_create.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_livedir_prefix.c (renamed from src/libs6rc/s6rc_livedir_prefix.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_livedir_prefixsize.c (renamed from src/libs6rc/s6rc_livedir_prefixsize.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_lock.c (renamed from src/libs6rc/s6rc_lock.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_read_uint.c (renamed from src/libs6rc/s6rc_read_uint.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_sanitize_dir.c (renamed from src/libs6rc/s6rc_sanitize_dir.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_block.c (renamed from src/libs6rc/s6rc_servicedir_block.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_copy_offline.c (renamed from src/libs6rc/s6rc_servicedir_copy_offline.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_copy_online.c (renamed from src/libs6rc/s6rc_servicedir_copy_online.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_internal.c (renamed from src/libs6rc/s6rc_servicedir_internal.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_manage.c (renamed from src/libs6rc/s6rc_servicedir_manage.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_unblock.c (renamed from src/libs6rc/s6rc_servicedir_unblock.c) | 0 | ||||
-rw-r--r-- | src/serverlib/s6rc_servicedir_unsupervise.c (renamed from src/libs6rc/s6rc_servicedir_unsupervise.c) | 0 |
37 files changed, 1135 insertions, 2 deletions
@@ -1,5 +1,13 @@ Changelog for s6-rc. +In 1.0.0.0 +---------- + + - New model: s6-rc is now event-based. + - New service types: virtuals and externals. + - New program: s6-rcd. + + In 0.5.2.0 ---------- diff --git a/doc/index.html b/doc/index.html index 08cad57..1217a1c 100644 --- a/doc/index.html +++ b/doc/index.html @@ -67,7 +67,7 @@ requirement if you link against the shared version of the skalibs library. </li> <ul> <li> The current released version of s6-rc is -<a href="s6-rc-0.5.2.0.tar.gz">0.5.2.0</a>. </li> +<a href="s6-rc-1.0.0.0.tar.gz">1.0.0.0</a>. </li> <li> Alternatively, you can checkout a copy of the <a href="//git.skarnet.org/cgi-bin/cgit.cgi/s6-rc/">s6-rc git repository</a>: diff --git a/doc/upgrade.html b/doc/upgrade.html index 9312335..c51f0c7 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -30,6 +30,11 @@ minor and bugfix version changes. <h1> What has changed in s6-rc </h1> +<h2> in 1.0.0.0 </h2> + +<ul> +</ul> + <h2> in 0.5.2.0 </h2> <ul> diff --git a/package/info b/package/info index dadf0dd..6249dfe 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=s6-rc -version=0.5.2.0 +version=1.0.0.0 category=admin package_macro_name=S6RC diff --git a/src/include/s6-rc/connection-common.h b/src/include/s6-rc/connection-common.h new file mode 100644 index 0000000..b78d459 --- /dev/null +++ b/src/include/s6-rc/connection-common.h @@ -0,0 +1,22 @@ +/* ISC license. */ + +#ifndef S6RC_CONNECTION_COMMON_H +#define S6RC_CONNECTION_COMMON_H + +#include <skalibs/textmessage.h> + +#define S6RC_CONNECTION_BUFSIZE 4096 + +typedef struct s6rc_connection_s s6rc_connection_t, *s6rc_connection_t_ref ; +struct s6rc_connection_s +{ + textmessage_sender_t out ; + textmessage_receiver_t in ; + char inbuf[S6RC_CONNECTION_BUFSIZE] ; +} ; +#define S6RC_CONNECTION_ZERO { .out = TEXTMESSAGE_SENDER_ZERO, .in = TEXTMESSAGE_RECEIVER_ZERO, .inbuf = "" } + +#define S6RC_MONITOR_BANNER "s6-rc monitor: after\n" +#define S6RC_MONITOR_BANNERLEN (sizeof(S6RC_MONITOR_BANNER) - 1) + +#endif diff --git a/src/include/s6-rc/connection.h b/src/include/s6-rc/connection.h new file mode 100644 index 0000000..f6d5eda --- /dev/null +++ b/src/include/s6-rc/connection.h @@ -0,0 +1,16 @@ +/* ISC license. */ + +#ifndef S6_RC_CONNECTION_H +#define S6_RC_CONNECTION_H + +#include <skalibs/tai.h> +#include <skalibs/textmessage.h> + +#include <s6-rc/connection-common.h> + +extern int s6rc_connection_start (s6rc_connection_t *, char const *, tain_t const *, tain_t *) ; +#define s6rc_connection_start_g(path, deadline) s6rc_connection_start(path, (deadline), &STAMP) + +extern void s6rc_connection_end (s6rc_connection_t *) ; + +#endif diff --git a/src/include/s6-rc/db.h b/src/include/s6-rc/db.h new file mode 100644 index 0000000..0f03967 --- /dev/null +++ b/src/include/s6-rc/db.h @@ -0,0 +1,76 @@ +/* ISC license. */ + +#ifndef S6RC_DB_H +#define S6RC_DB_H + +#include <stdint.h> +#include <skalibs/diuint32.h> +#include <skalibs/buffer.h> + +#define S6RC_DB_BANNER_START "s6rc-db: start\n" +#define S6RC_DB_BANNER_START_LEN (sizeof(S6RC_DB_BANNER_START) - 1) +#define S6RC_DB_BANNER_END "\ns6rc-db: end\n" +#define S6RC_DB_BANNER_END_LEN (sizeof(S6RC_DB_BANNER_END) - 1) + +#define S6RC_DB_FLAG_ESSENTIAL 0x00000001U + + +typedef struct s6rc_oneshot_s s6rc_oneshot_t, *s6rc_oneshot_t_ref ; +struct s6rc_oneshot_s +{ + uint32_t argc[2] ; + uint32_t argv[2] ; +} ; + +typedef struct s6rc_longrun_s s6rc_longrun_t, *s6rc_longrun_t_ref ; +struct s6rc_longrun_s +{ + uint32_t consumer ; + uint32_t nproducers ; + uint32_t producers ; +} ; + +typedef union s6rc_longshot_u s6rc_longshot_t, *s6rc_longshot_t_ref ; +union s6rc_longshot_u +{ + s6rc_oneshot_t oneshot ; + s6rc_longrun_t longrun ; +} ; + +typedef struct s6rc_service_s s6rc_service_t, *s6rc_service_t_ref ; +struct s6rc_service_s +{ + uint32_t name ; + uint32_t flags ; + uint32_t deps[2] ; + uint32_t ndeps[2] ; + uint32_t timeout[2] ; + s6rc_longshot_t x ; +} ; + +typedef struct s6rc_db_s s6rc_db_t, *s6rc_db_t_ref ; +struct s6rc_db_s +{ + s6rc_service_t *services ; + unsigned int nshort ; + unsigned int nlong ; + unsigned int stringlen ; + unsigned int nargvs ; + unsigned int ndeps ; + unsigned int nproducers ; + char *string ; + char const **argvs ; + uint32_t *deps ; + uint32_t *producers ; +} ; + +extern int s6rc_db_read_uint32 (buffer *, uint32_t *) ; + +extern int s6rc_db_read_sizes (int, s6rc_db_t *) ; +extern int s6rc_db_read (int, s6rc_db_t *) ; + +extern int s6rc_db_check_pipelines (s6rc_db_t const *, diuint32 *) ; +extern int s6rc_db_check_depcycles (s6rc_db_t const *, int, diuint32 *) ; +extern int s6rc_db_check_revdeps (s6rc_db_t const *) ; + +#endif diff --git a/src/libs6rc/s6rc_connection_end.c b/src/libs6rc/s6rc_connection_end.c new file mode 100644 index 0000000..e993881 --- /dev/null +++ b/src/libs6rc/s6rc_connection_end.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include <skalibs/djbunix.h> +#include <skalibs/textmessage.h> + +#include <s6-rc/connection-common.h> +#include <s6-rc/connection.h> + +void s6rc_connection_end (s6rc_connection_t *a) +{ + fd_close(textmessage_sender_fd(&a->out)) ; + textmessage_sender_free(&a->out) ; + textmessage_receiver_free(&a->in) ; +} diff --git a/src/libs6rc/s6rc_connection_start.c b/src/libs6rc/s6rc_connection_start.c new file mode 100644 index 0000000..33b2b1a --- /dev/null +++ b/src/libs6rc/s6rc_connection_start.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <skalibs/djbunix.h> +#include <skalibs/webipc.h> +#include <skalibs/textmessage.h> + +#include <s6-rc/connection-common.h> +#include <s6-rc/connection.h> + +int s6rc_connection_start (s6rc_connection_t *a, char const *path, tain_t const *deadline, tain_t *stamp) +{ + int fd = ipc_stream_nbcoe() ; + if (fd < 0) return 0 ; + if (!ipc_timed_connect(fd, path, deadline, stamp)) + { + fd_close(fd) ; + return 0 ; + } + textmessage_sender_init(&a->out, fd) ; + textmessage_receiver_init(&a->in, fd, a->inbuf, S6RC_CONNECTION_BUFSIZE, TEXTMESSAGE_MAXLEN) ; + return 1 ; +} diff --git a/src/libs6rc/s6rc_monitor.c b/src/libs6rc/s6rc_monitor.c new file mode 100644 index 0000000..bd27e8b --- /dev/null +++ b/src/libs6rc/s6rc_monitor.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <skalibs/djbunix.h> +#include <skalibs/webipc.h> +#include <skalibs/textmessage.h> + +#include <s6-rc/connection-common.h> +#include <s6-rc/connection.h> + +int s6rc_monitor (s6rc_connection_t *a, textmessage_receiver_t *asyncin, char *asyncbuf, size_t asyncbufsize, tain_t const *deadline, tain_t *stamp) +{ + if (!textmessage_timed_send(&a->out, "M", 1, deadline, stamp)) return 0 ; + if (!textmessage_recv_channel(textmessage_receiver_fd(&a->in), asyncin, asyncbuf, asyncbufsize, S6RC_MONITOR_BANNER, S6RC_MONITOR_BANNERLEN, deadline, stamp)) return 0 ; + return 1 ; +} diff --git a/src/libs6rcd/s6rcd.h b/src/libs6rcd/s6rcd.h new file mode 100644 index 0000000..a9326b7 --- /dev/null +++ b/src/libs6rcd/s6rcd.h @@ -0,0 +1,9 @@ +/* ISC license. */ + +#include <s6-rc/db.h> + +extern int s6rcd_livedir_init (char const *, char const *, char const *, char const *, int *) +extern int s6rcd_livesubdir_create (char *, char const *, char const *) ; + +extern int s6rcd_db_load (s6rc_db_t *, char const *) ; +extern int s6rcd_db_read_sizes (s6rc_db_sizes_t *, char const *) ; diff --git a/src/libs6rcd/s6rcd_db_load.c b/src/libs6rcd/s6rcd_db_load.c new file mode 100644 index 0000000..68aa11e --- /dev/null +++ b/src/libs6rcd/s6rcd_db_load.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include <s6-rc/db.h> +#include "s6rcd.h" + +int s6rcd_db_load (s6rc_db_t *db, char const *compiled) +{ + if (!s6rcd_db_read_sizes(db, compiled)) return 0 ; + +} diff --git a/src/libs6rcd/s6rcd_livedir_init.c b/src/libs6rcd/s6rcd_livedir_init.c new file mode 100644 index 0000000..f252dba --- /dev/null +++ b/src/libs6rcd/s6rcd_livedir_init.c @@ -0,0 +1,124 @@ +/* ISC license. */ + +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> +#include <skalibs/webipc.h> + +#include "s6rcd.h" + +#ifdef NAME_MAX +# define S6RC_NAME_MAX NAME_MAX +#else +# define S6RC_NAME_MAX 63 +#endif + +static inline int mksubdirs (char *s) +{ + size_t n = strlen(s) ; + size_t i = 0 ; + for (; i < n ; i++) + { + if (s[i] == '/') + { + int r ; + s[i] = 0 ; + r = mkdir(s, 0755) ; + s[i] = '/' ; + if (r < 0 && errno != EEXIST) break ; + } + } + return i >= n ; +} + +int s6rcd_livedir_init (char const *livedir, char const *scandir, char const *prefix, char const *compiled, int *sock) +{ + size_t plen = strlen(prefix) ; + size_t llen = strlen(livedir) ; + struct stat st ; + char ltmp[llen + 9] ; + if (plen >= S6RC_NAME_MAX) + strerr_dief1x(100, "prefix is too long") ; + + memcpy(ltmp, livedir, llen + 1) ; + if (!mksubdirs(ltmp, len)) + strerr_diefu2sys(111, "create subdirectories of ", s) ; + if (mkdir(ltmp, 0755) < 0 && errno != EEXIST) + strerr_diefu2sys(111, "mkdir ", ltmp) ; + + memcpy(ltmp + llen, "/s", 3) ; + *sock = ipc_stream() ; + if (*sock < 0) + strerr_diefu1sys(111, "create socket") ; + if (ipc_bind_reuse(*sock, ltmp) < 0) + strerr_diefu2sys(111, "bind to ", ltmp) ; + + memcpy(ltmp + llen + 1, "scandir", 8) ; + if (lstat(ltmp, &st) < 0) + { + if (errno != ENOENT) + strerr_diefu2sys(111, "lstat ", ltmp) ; + if (symlink(scandir, ltmp) < 0) + strerr_diefu4sys(111, "symlink ", ltmp, " to ", scandir) ; + } + else + { + size_t slen = strlen(scandir) ; + char stmp[slen + 1] ; + if (!S_ISLNK(st.st_mode)) + strerr_dief3x(100, "file ", ltmp, " exists and is not a symbolic link") ; + if (readlink(ltmp, stmp, slen + 1) < 0) + strerr_diefu2sys(111, "readlink ", ltmp) ; + if (strncmp(scandir, stmp, slen + 1)) + strerr_dief4x(100, "provided scandir ", scandir, " does not match the contents of existing ", ltmp) ; + } + + memcpy(ltmp + llen + 1, "prefix", 7) ; + if (stat(ltmp, &st) < 0) + { + if (errno != ENOENT) + strerr_diefu2sys(111, "stat ", ltmp) ; + if (!openwritenclose_unsafe(ltmp, prefix, strlen(prefix))) + strerr_diefu2sys(111, "write prefix to ", ltmp) ; + } + else + { + if (!S_IFREG(st.st_mode)) + strerr_dief3x(100, "file ", ltmp, " exists and is not a regular file") ; + if (st.st_size != plen) + strerr_dief4x(100, "provided prefix ", prefix, " does not match the contents of existing ", ltmp) ; + { + char stmp[plen] ; + ssize_t r = openreadnclose(ltmp, ptmp, plen) ; + if (r != plen) + strerr_diefu2sys(111, "read ", ltmp) ; + if (memcmp(ptmp, prefix, plen)) + strerr_dief4x(100, "provided prefix ", prefix, " does not match the contents of existing ", ltmp) ; + } + } + + memcpy(ltmp + llen + 1, "live", 5) ; + if (lstat(ltmp, &st) < 0) + { + char name[12] ; + if (errno != ENOENT) strerr_diefu2sys(111, "lstat ", ltmp) ; + if (!s6rcd_livesubdir_create(name, live, compiled)) + strerr_diefu2sys(111, "create live subdirectory in ", live) ; + if (symlink(name, ltmp) < 0) + strerr_diefu4sys(111, "symlink ", ltmp, " to ", name) ; + return 0 ; + } + if (!S_ISLNK(st.st_mode)) + strerr_dief3x(100, "livesubdir ", ltmp, " exists and is not a symbolic link") ; + if (stat(ltmp, &st) < 0) + strerr_diefu2sys(111, "stat ", ltmp) ; + if (!S_ISDIR(st.st_mode)) + strerr_dief4x(100, "livesubdir ", ltmp, " exists and is not a symbolic link", " to a directory") ; + return 1 ; +} diff --git a/src/libs6rcd/s6rcd_livesubdir_create.c b/src/libs6rcd/s6rcd_livesubdir_create.c new file mode 100644 index 0000000..ff989aa --- /dev/null +++ b/src/libs6rcd/s6rcd_livesubdir_create.c @@ -0,0 +1,35 @@ +/* ISC license. */ + +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include <skalibs/djbunix.h> + +#include "s6rcd.h" + +int s6rcd_livesubdir_create (char *name, char const *live, char const *compiled) +{ + size_t llen = strlen(live) ; + size_t clen = strlen(compiled) ; + char cfn[clen + 13] ; + char lfn[llen + 25] ; + memcpy(lfn, live, llen) ; + memcpy(lfn + llen, "/live:XXXXXX", 13) ; + if (!mkdtemp(lfn)) return 0 ; + + memcpy(lfn + llen + 12, "/compiled", 10) ; + if (symlink(compiled, lfn) < 0) return 0 ; + strerr_diefu4sys(111, "symlink ", compiled, " to ", realfn + llen + 1) ; + + memcpy(cfn, compiled, clen) ; + memcpy(cfn + clen, "/servicedirs", 13) ; + memcpy(lfn + llen + 13, "servicedirs", 12) ; + if (!hiercopy(cfn, lfn)) return 0 ; + + lfn[llen + 12] = 0 ; + if (chmod(lfn, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) return 0 ; + memcpy(name, lfn + llen + 1, 12) ; + return 1 ; +} diff --git a/src/s6-rc/s6-rcd.c b/src/s6-rc/s6-rcd.c new file mode 100644 index 0000000..7c7b586 --- /dev/null +++ b/src/s6-rc/s6-rcd.c @@ -0,0 +1,770 @@ +/* ISC license. */ + +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/resource.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <regex.h> + +#include <skalibs/posixplz.h> +#include <skalibs/posixishard.h> +#include <skalibs/types.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/sgetopt.h> +#include <skalibs/env.h> +#include <skalibs/bytestr.h> +#include <skalibs/error.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/djbunix.h> +#include <skalibs/sig.h> +#include <skalibs/iopause.h> +#include <skalibs/selfpipe.h> +#include <skalibs/cdb.h> +#include <skalibs/getpeereid.h> +#include <skalibs/webipc.h> + +#include <s6/accessrules.h> + +#define USAGE "s6-rcd [ -v verbosity ] [ -1 ] [ -C maxconn ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] [ -c compiled ] [ -l livedir ]" +#define dieusage() strerr_dieusage(100, USAGE) ; + +#define S6RC_MAXCONN 64 + +static unsigned int verbosity = 1 ; +static int cont = 1 ; +static tain_t answertto = TAIN_INFINITE_RELATIVE ; +static tain_t lameduckdeadline = TAIN_INFINITE_RELATIVE ; +static tain_t const nano1 = { .sec = TAI_ZERO, .nano = 1 } ; + +static char const *scandir = S6RC_SCANDIR_DEFAULT ; +static char const *livedir = S6RC_LIVEDIR_DEFAULT ; + +static unsigned int rulestype = 0 ; +static char const *rules = 0 ; +static int cdbfd = -1 ; +static struct cdb cdbmap = CDB_ZERO ; + +static void handle_signals (void) +{ + for (;;) switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read()") ; + case 0 : return ; + case SIGTERM : + { + if (cont) + { + cont = 0 ; + tain_add_g(&lameduckdeadline, &lameduckdeadline) ; + } + break ; + } + case SIGHUP : + { + int fd ; + struct cdb c = CDB_ZERO ; + if (rulestype != 2) break ; + fd = openc_readb(rules) ; + if (fd < 0) break ; + if (cdb_init(&c, fd) < 0) + { + fd_close(fd) ; + break ; + } + cdb_free(&cdbmap) ; + fd_close(cdbfd) ; + cdbfd = fd ; + cdbmap = c ; + break ; + } + default : break ; + } +} + + + /* client connection */ + +typedef struct client_s client_t, *client_t_ref ; +struct client_s +{ + uint32_t next ; + uint32_t xindex ; + tain_t deadline ; + regex_t rre ; + regex_t wre ; + unixconnection_t connection ; +} ; + +static genset *clients ; +static uint32_t sentinel ; +#define CLIENT(i) genset_p(client_t, clients, (i)) +#define numconn (genset_n(clients) - 1) + +static inline void client_free (client_t *c) +{ + fd_close(unixmessage_sender_fd(&c->connection.out)) ; + unixconnection_free(&c->connection) ; + regfree(&c->rre) ; + regfree(&c->wre) ; +} + +static inline void client_delete (uint32_t cc, uint32_t prev) +{ + client_t *c = CLIENT(cc) ; + CLIENT(prev)->next = c->next ; + client_free(c) ; + genset_delete(clients, cc) ; +} + +static void removeclient (uint32_t *i, uint32_t j) +{ + client_delete(*i, j) ; + *i = j ; +} + +static void client_setdeadline (client_t *c) +{ + tain_t blah ; + tain_half(&blah, &tain_infinite_relative) ; + tain_add_g(&blah, &blah) ; + if (tain_less(&blah, &c->deadline)) + tain_add_g(&c->deadline, &answertto) ; +} + +static inline int client_prepare_iopause (uint32_t i, tain_t *deadline, iopause_fd *x, uint32_t *j) +{ + client_t *c = CLIENT(i) ; + if (tain_less(&c->deadline, deadline)) *deadline = c->deadline ; + if (!unixmessage_sender_isempty(&c->connection.out) || !unixmessage_receiver_isempty(&c->connection.in) || (cont && !unixmessage_receiver_isfull(&c->connection.in))) + { + x[*j].fd = unixmessage_sender_fd(&c->connection.out) ; + x[*j].events = (!unixmessage_receiver_isempty(&c->connection.in) || (cont && !unixmessage_receiver_isfull(&c->connection.in)) ? IOPAUSE_READ : 0) | (!unixmessage_sender_isempty(&c->connection.out) ? IOPAUSE_WRITE : 0) ; + c->xindex = (*j)++ ; + } + else c->xindex = 0 ; + return !!c->xindex ; +} + +static inline void client_add (uint32_t *cc, int fd, regex_t const *rre, regex_t const *wre, unsigned int flags) +{ + uint32_t i ; + client_t *c ; + i = genset_new(clients) ; + c = CLIENT(i) ; + tain_add_g(&c->deadline, &answertto) ; + c->rre = *rre ; + c->wre = *wre ; + c->dumping = 0 ; + c->flags = flags ; + unixconnection_init(&c->connection, fd, fd) ; + c->next = CLIENT(sentinel)->next ; + CLIENT(sentinel)->next = i ; + *cc = i ; +} + +static inline int client_flush (uint32_t i, iopause_fd const *x) +{ + client_t *c = CLIENT(i) ; + if (c->xindex && (x[c->xindex].revents & IOPAUSE_WRITE)) + { + if (unixconnection_flush(&c->connection)) + tain_add_g(&c->deadline, &tain_infinite_relative) ; + else if (!error_isagain(errno)) return 0 ; + } + return 1 ; +} + +static int answer (client_t *c, char e) +{ + unixmessage_t m = { .s = &e, .len = 1, .fds = 0, .nfds = 0 } ; + if (!unixmessage_put(&c->connection.out, &m)) return 0 ; + client_setdeadline(c) ; + return 1 ; +} + +static int do_store (uint32_t cc, unixmessage_t const *m) +{ + uint32_t pp, idlen ; + client_t *c = CLIENT(cc) ; + s6_fdholder_fd_t *p ; + if (c->dumping || m->len < TAIN_PACK + 3 || m->nfds != 1) return (errno = EPROTO, 0) ; + idlen = (unsigned char)m->s[TAIN_PACK] ; + if (idlen > S6_FDHOLDER_ID_SIZE || idlen + 2 + TAIN_PACK != m->len || m->s[1 + TAIN_PACK + idlen]) return (errno = EPROTO, 0) ; + if (regexec(&c->wre, m->s + TAIN_PACK + 1, 0, 0, 0)) + { + unixmessage_drop(m) ; + return answer(c, EPERM) ; + } + if (numfds >= maxfds) + { + unixmessage_drop(m) ; + return answer(c, ENFILE) ; + } + if (avltreen_search(fds_by_id, m->s + TAIN_PACK + 1, &pp)) + { + unixmessage_drop(m) ; + return answer(c, EBUSY) ; + } + if (!answer(c, 0)) return 0 ; + pp = genset_new(fdstore) ; p = FD(pp) ; + tain_unpack(m->s, &p->limit) ; p->fd = m->fds[0] ; + memcpy(p->id, m->s + TAIN_PACK + 1, idlen) ; + memset(p->id + idlen, 0, S6_FDHOLDER_ID_SIZE + 1 - idlen) ; + for (;;) + { + uint32_t dummy ; + if (!avltreen_search(fds_by_deadline, &p->limit, &dummy)) break ; + tain_add(&p->limit, &p->limit, &nano1) ; + } + avltreen_insert(fds_by_id, pp) ; + avltreen_insert(fds_by_deadline, pp) ; + return 1 ; +} + +static int do_delete (uint32_t cc, unixmessage_t const *m) +{ + uint32_t pp, idlen ; + client_t *c = CLIENT(cc) ; + if (c->dumping || m->len < 3 || m->nfds) return (errno = EPROTO, 0) ; + idlen = (unsigned char)m->s[0] ; + if (idlen > S6_FDHOLDER_ID_SIZE || idlen + 2 != m->len || m->s[idlen + 1]) return (errno = EPROTO, 0) ; + if (regexec(&c->wre, m->s + 1, 0, 0, 0)) return answer(c, EPERM) ; + if (!avltreen_search(fds_by_id, m->s + 1, &pp)) return answer(c, ENOENT) ; + if (!answer(c, 0)) return 0 ; + fds_close_and_delete(pp) ; + return 1 ; +} + +static int do_retrieve (uint32_t cc, unixmessage_t const *m) +{ + int fd ; + unixmessage_t ans = { .s = "", .len = 1, .fds = &fd, .nfds = 1 } ; + uint32_t pp, idlen ; + client_t *c = CLIENT(cc) ; + if (c->dumping || m->len < 4 || m->nfds) return (errno = EPROTO, 0) ; + idlen = (unsigned char)m->s[1] ; + if (idlen > S6_FDHOLDER_ID_SIZE || idlen + 3 != m->len || m->s[idlen + 2]) return (errno = EPROTO, 0) ; + if (regexec(&c->rre, m->s + 2, 0, 0, 0)) return answer(c, EPERM) ; + if (m->s[0] && regexec(&c->wre, m->s + 2, 0, 0, 0)) return answer(c, EPERM) ; + if (!avltreen_search(fds_by_id, m->s + 2, &pp)) return answer(c, ENOENT) ; + fd = FD(pp)->fd ; + if (!unixmessage_put_and_close(&c->connection.out, &ans, m->s[0] ? unixmessage_bits_closeall : unixmessage_bits_closenone)) return 0 ; + if (m->s[0]) fds_delete(pp) ; + return 1 ; +} + +static int fill_siovec_with_ids_iter (char *thing, void *data) +{ + struct iovec *v = (*(struct iovec **)data)++ ; + s6_fdholder_fd_t *p = (s6_fdholder_fd_t *)thing ; + v->iov_base = p->id ; + v->iov_len = strlen(p->id) + 1 ; + return 1 ; +} + +static int do_list (uint32_t cc, unixmessage_t const *m) +{ + client_t *c = CLIENT(cc) ; + struct iovec v[1+numfds] ; + unixmessage_v_t ans = { .v = v, .vlen = 1+numfds, .fds = 0, .nfds = 0 } ; + struct iovec *vp = v + 1 ; + char pack[5] = "" ; + if (c->dumping || m->len || m->nfds) return (errno = EPROTO, 0) ; + if (!(c->flags & 4)) return answer(c, EPERM) ; + uint32_pack_big(pack + 1, (uint32_t)numfds) ; + v[0].iov_base = pack ; v[0].iov_len = 5 ; + genset_iter(fdstore, &fill_siovec_with_ids_iter, &vp) ; + if (!unixmessage_putv(&c->connection.out, &ans)) return answer(c, errno) ; + client_setdeadline(c) ; + return 1 ; +} + +typedef struct getdumpiter_s getdumpiter_t, *getdumpiter_t_ref ; +struct getdumpiter_s +{ + struct iovec *v ; + int *fd ; + char *limit ; +} ; + +static int getdump_iter (char *thing, void *stuff) +{ + s6_fdholder_fd_t *p = (s6_fdholder_fd_t *)thing ; + getdumpiter_t *blah = stuff ; + unsigned char len = strlen(p->id) ; + tain_pack(blah->limit, &p->limit) ; + blah->limit[TAIN_PACK] = len ; + blah->v->iov_base = p->id ; + blah->v->iov_len = len + 1 ; + *blah->fd++ = p->fd ; + blah->v += 2 ; + blah->limit += TAIN_PACK + 1 ; + return 1 ; +} + +static int do_getdump (uint32_t cc, unixmessage_t const *m) +{ + uint32_t n = numfds ? 1 + ((numfds-1) / UNIXMESSAGE_MAXFDS) : 0 ; + client_t *c = CLIENT(cc) ; + if (c->dumping || m->len || m->nfds) return (errno = EPROTO, 0) ; + if (!(c->flags & 1)) return answer(c, EPERM) ; + { + char pack[9] = "" ; + unixmessage_t ans = { .s = pack, .len = 9, .fds = 0, .nfds = 0 } ; + uint32_pack_big(pack+1, n) ; + uint32_pack_big(pack+5, numfds) ; + if (!unixmessage_put(&c->connection.out, &ans)) return answer(c, errno) ; + } + if (n) + { + uint32_t i = 0 ; + unixmessage_v_t ans[n] ; + struct iovec v[numfds << 1] ; + int fds[numfds] ; + char limits[(TAIN_PACK+1) * numfds] ; + for (; i < numfds ; i++) + { + v[i<<1].iov_base = limits + i * (TAIN_PACK+1) ; + v[i<<1].iov_len = TAIN_PACK+1 ; + } + { + getdumpiter_t state = { .v = v+1, .fd = fds, .limit = limits } ; + genset_iter(fdstore, &getdump_iter, &state) ; + } + for (i = 0 ; i < n-1 ; i++) + { + ans[i].v = v + (i<<1) * UNIXMESSAGE_MAXFDS ; + ans[i].vlen = UNIXMESSAGE_MAXFDS << 1 ; + ans[i].fds = fds + i * UNIXMESSAGE_MAXFDS ; + ans[i].nfds = UNIXMESSAGE_MAXFDS ; + } + ans[n-1].v = v + ((n-1)<<1) * UNIXMESSAGE_MAXFDS ; + ans[n-1].vlen = (1 + (numfds-1) % UNIXMESSAGE_MAXFDS) << 1 ; + ans[n-1].fds = fds + (n-1) * UNIXMESSAGE_MAXFDS ; + ans[n-1].nfds = 1 + (numfds - 1) % UNIXMESSAGE_MAXFDS ; + for (i = 0 ; i < n ; i++) + { + if (!unixmessage_putv(&c->connection.out, ans + i)) + { + int e = errno ; + ++i ; + while (i--) unixmessage_unput(&c->connection.out) ; + return answer(c, e) ; + } + } + } + client_setdeadline(c) ; + return 1 ; +} + +static int do_setdump (uint32_t cc, unixmessage_t const *m) +{ + char pack[5] = "" ; + uint32_t n ; + unixmessage_t ans = { .s = pack, .len = 5, .fds = 0, .nfds = 0 } ; + client_t *c = CLIENT(cc) ; + if (c->dumping || m->len != 4 || m->nfds) return (errno = EPROTO, 0) ; + if (!(c->flags & 2)) return answer(c, EPERM) ; + uint32_unpack_big(m->s, &n) ; + if (n > maxfds || n + numfds > maxfds) return answer(c, ENFILE) ; + c->dumping = n ; + n = n ? 1 + (n-1) / UNIXMESSAGE_MAXFDS : 0 ; + uint32_pack_big(pack+1, n) ; + if (!unixmessage_put(&c->connection.out, &ans)) return answer(c, errno) ; + return 1 ; +} + +static int do_setdump_data (uint32_t cc, unixmessage_t const *m) +{ + client_t *c = CLIENT(cc) ; + if (!m->nfds || m->nfds > c->dumping || m->len < m->nfds * (TAIN_PACK + 3)) + return (errno = EPROTO, 0) ; + if (!(c->flags & 2)) + { + unixmessage_drop(m) ; + return answer(c, EPERM) ; + } + if (numfds + m->nfds > maxfds) + { + unixmessage_drop(m) ; + return answer(c, ENFILE) ; + } + { + char const *s = m->s ; + size_t len = m->len ; + uint32_t i = 0 ; + uint32_t indices[m->nfds] ; + for (; i < m->nfds ; i++) + { + s6_fdholder_fd_t *p ; + uint32_t oldid, idlen ; + if (len < TAIN_PACK + 3) break ; + idlen = (unsigned char)s[TAIN_PACK] ; + if (idlen > S6_FDHOLDER_ID_SIZE || len < TAIN_PACK + 2 + idlen || s[TAIN_PACK + 1 + idlen]) break ; + indices[i] = genset_new(fdstore) ; + p = FD(indices[i]) ; + tain_unpack(s, &p->limit) ; + memcpy(p->id, s + TAIN_PACK + 1, idlen+1) ; + p->fd = m->fds[i] ; + if (avltreen_search(fds_by_id, p->id, &oldid)) fds_close_and_delete(oldid) ; + avltreen_insert(fds_by_id, indices[i]) ; + avltreen_insert(fds_by_deadline, indices[i]) ; + s += TAIN_PACK + 2 + idlen ; len -= TAIN_PACK + 2 + idlen ; + } + if (i < m->nfds || len) + { + while (i--) fds_delete(indices[i]) ; + return (errno = EPROTO, 0) ; + } + } + c->dumping -= m->nfds ; + return answer(c, c->dumping ? EAGAIN : 0) ; +} + +static int do_error (uint32_t cc, unixmessage_t const *m) +{ + (void)cc ; + (void)m ; + return (errno = EPROTO, 0) ; +} + +typedef int parsefunc_t (uint32_t, unixmessage_t const *) ; +typedef parsefunc_t *parsefunc_t_ref ; + +static inline int parse_protocol (unixmessage_t const *m, void *p) +{ + static parsefunc_t_ref const f[8] = + { + &do_store, + &do_delete, + &do_retrieve, + &do_list, + &do_getdump, + &do_setdump, + &do_setdump_data, + &do_error + } ; + unixmessage_t mcopy = { .s = m->s + 1, .len = m->len - 1, .fds = m->fds, .nfds = m->nfds } ; + if (!m->len) + { + unixmessage_drop(m) ; + return (errno = EPROTO, 0) ; + } + if (!(*f[byte_chr("SDRL?!.", 7, m->s[0])])(*(uint32_t *)p, &mcopy)) + { + unixmessage_drop(m) ; + return 0 ; + } + return 1 ; +} + +static inline int client_read (uint32_t cc, iopause_fd const *x) +{ + client_t *c = CLIENT(cc) ; + return !unixmessage_receiver_isempty(&c->connection.in) || (c->xindex && (x[c->xindex].revents & IOPAUSE_READ)) ? + unixmessage_handle(&c->connection.in, &parse_protocol, &cc) > 0 : 1 ; +} + + + /* Environment on new connections */ + +static int makere (regex_t *re, char const *s, char const *var) +{ + size_t varlen = strlen(var) ; + if (str_start(s, var) && (s[varlen] == '=')) + { + int r = skalibs_regcomp(re, s + varlen + 1, REG_EXTENDED | REG_NOSUB) ; + if (r) + { + if (verbosity) + { + char buf[256] ; + regerror(r, re, buf, 256) ; + strerr_warnw6x("invalid ", var, " value: ", s + varlen + 1, ": ", buf) ; + } + return -1 ; + } + else return 1 ; + } + return 0 ; +} + +static void defaultre (regex_t *re) +{ + int r = skalibs_regcomp(re, ".^", REG_EXTENDED | REG_NOSUB) ; + if (r) + { + char buf[256] ; + regerror(r, re, buf, 256) ; + strerr_diefu2x(100, "compile .^ into a regular expression: ", buf) ; + } +} + +static inline int parse_env (char const *const *envp, regex_t *rre, regex_t *wre, unsigned int *flags, unsigned int *donep) +{ + unsigned int done = 0 ; + unsigned int fl = 0 ; + for (; *envp ; envp++) + { + if (str_start(*envp, "S6_FDHOLDER_GETDUMP=")) fl |= 1 ; + if (str_start(*envp, "S6_FDHOLDER_SETDUMP=")) fl |= 2 ; + if (str_start(*envp, "S6_FDHOLDER_LIST=")) fl |= 4 ; + if (!(done & 1)) + { + int r = makere(rre, *envp, "S6_FDHOLDER_RETRIEVE_REGEX") ; + if (r < 0) + { + if (done & 2) regfree(wre) ; + return 0 ; + } + else if (r) done |= 1 ; + } + if (!(done & 2)) + { + int r = makere(wre, *envp, "S6_FDHOLDER_STORE_REGEX") ; + if (r < 0) + { + if (done & 1) regfree(rre) ; + return 0 ; + } + else if (r) done |= 2 ; + } + } + *flags = fl ; + *donep = done ; + return 1 ; +} + +static inline int new_connection (int fd, regex_t *rre, regex_t *wre, unsigned int *flags) +{ + s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ; + s6_accessrules_result_t result = S6_ACCESSRULES_ERROR ; + uid_t uid ; + gid_t gid ; + unsigned int done = 0 ; + + if (getpeereid(fd, &uid, &gid) < 0) + { + if (verbosity) strerr_warnwu1sys("getpeereid") ; + return 0 ; + } + + switch (rulestype) + { + case 1 : + result = s6_accessrules_uidgid_fs(uid, gid, rules, ¶ms) ; break ; + case 2 : + result = s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, ¶ms) ; break ; + default : break ; + } + if (result != S6_ACCESSRULES_ALLOW) + { + if (verbosity && (result == S6_ACCESSRULES_ERROR)) + strerr_warnw1sys("error while checking rules") ; + return 0 ; + } + if (params.exec.len && verbosity) + { + char fmtuid[UID_FMT] ; + char fmtgid[GID_FMT] ; + fmtuid[uid_fmt(fmtuid, uid)] = 0 ; + fmtgid[gid_fmt(fmtgid, gid)] = 0 ; + strerr_warnw4x("unused exec string in rules for uid ", fmtuid, " gid ", fmtgid) ; + } + if (params.env.s) + { + size_t n = byte_count(params.env.s, params.env.len, '\0') ; + char const *envp[n+1] ; + if (!env_make(envp, n, params.env.s, params.env.len)) + { + if (verbosity) strerr_warnwu1sys("env_make") ; + s6_accessrules_params_free(¶ms) ; + return 0 ; + } + envp[n] = 0 ; + if (!parse_env(envp, rre, wre, flags, &done)) + { + if (verbosity) strerr_warnwu1sys("parse_env") ; + s6_accessrules_params_free(¶ms) ; + return 0 ; + } + } + s6_accessrules_params_free(¶ms) ; + if (!(done & 1)) defaultre(rre) ; + if (!(done & 2)) defaultre(wre) ; + return 1 ; +} + + +int main (int argc, char const *const *argv, char const *const *envp) +{ + int spfd ; + int flag1 = 0 ; + uint32_t maxconn = 4 ; + char const *compiled = S6RC_COMPILED_DEFAULT ; + char const *prefix = "" ; + PROG = "s6-rcd" ; + + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0, T = 0 ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "v:1C:i:x:t:T:c:l:s:p:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; + case '1' : flag1 = 1 ; break ; + case 'i' : rules = l.arg ; rulestype = 1 ; break ; + case 'x' : rules = l.arg ; rulestype = 2 ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ; + case 'C' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; break ; + case 'c' : compiled = l.arg ; break ; + case 'l' : livedir = l.arg ; break ; + case 's' : scandir = l.arg ; break ; + case 'p' : prefix = l.arg ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&answertto, t) ; + if (T) tain_from_millisecs(&lameduckdeadline, T) ; + } + + if (maxconn > S6RC_MAXCONN) maxconn = S6RC_MAXCONN ; + if (!maxconn) maxconn = 1 ; + if (livedir[0] != '/') + strerr_dief2x(100, livedir, " is not an absolute path") ; + if (scandir[0] != '/') + strerr_dief2x(100, scandir, " is not an absolute path") ; + if (strchr(prefix, '/') || strchr(prefix, '\n')) + strerr_dief1x(100, "prefix cannot contain a / or a newline") ; + if (flag1) + { + if (fcntl(1, F_GETFD) < 0) + strerr_dief1sys(100, "called with option -1 but stdout said") ; + } + else close(1) ; + + spfd = selfpipe_init() ; + if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + { + sigset_t set ; + sigemptyset(&set) ; + sigaddset(&set, SIGTERM) ; + sigaddset(&set, SIGHUP) ; + if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; + } + + if (rulestype == 2) + { + cdbfd = open_readb(rules) ; + if (cdbfd < 0) strerr_diefu3sys(111, "open ", rules, " for reading") ; + if (cdb_init(&cdbmap, cdbfd) < 0) + strerr_diefu2sys(111, "cdb_init ", rules) ; + } + + { + /* Hello, stack. I have a present for you. */ + genset clientinfo, fdinfo ; + avltreen fdidinfo, fddeadlineinfo ; + iopause_fd x[2 + maxconn] ; + client_t clientstorage[1+maxconn] ; + uint32_t clientfreelist[1+maxconn] ; + s6_fdholder_fd_t fdstorage[maxfds] ; + uint32_t fdfreelist[maxfds] ; + avlnode fdidstorage[maxfds] ; + uint32_t fdidfreelist[maxfds] ; + avlnode fddeadlinestorage[maxfds] ; + uint32_t fddeadlinefreelist[maxfds] ; + /* Hope you enjoyed it! Have a nice day! */ + + GENSET_init(&clientinfo, client_t, clientstorage, clientfreelist, 1+maxconn) ; + clients = &clientinfo ; + sentinel = genset_new(clients) ; + clientstorage[sentinel].next = sentinel ; + GENSET_init(&fdinfo, s6_fdholder_fd_t, fdstorage, fdfreelist, maxfds) ; + fdstore = &fdinfo ; + avltreen_init(&fdidinfo, fdidstorage, fdidfreelist, maxfds, &fds_id_dtok, &fds_id_cmp, 0) ; + fds_by_id = &fdidinfo ; + avltreen_init(&fddeadlineinfo, fddeadlinestorage, fddeadlinefreelist, maxfds, &fds_deadline_dtok, &fds_deadline_cmp, 0) ; + fds_by_deadline = &fddeadlineinfo ; + + x[0].fd = spfd ; x[0].events = IOPAUSE_READ ; + x[1].fd = 0 ; + + if (flag1) + { + fd_write(1, "\n", 1) ; + fd_close(1) ; + } + + /* We are long-lived and have to check absolute fd deadlines, + so we purposefully remain in wallclock mode. */ + tain_now_g() ; + + for (;;) + { + tain_t deadline ; + uint32_t j = 2 ; + uint32_t i ; + int r = 1 ; + + if (cont) tain_add_g(&deadline, &tain_infinite_relative) ; + else deadline = lameduckdeadline ; + if (avltreen_min(fds_by_deadline, &i) && tain_less(&FD(i)->limit, &deadline)) deadline = FD(i)->limit ; + x[1].events = (cont && (numconn < maxconn)) ? IOPAUSE_READ : 0 ; + for (i = clientstorage[sentinel].next ; i != sentinel ; i = clientstorage[i].next) + if (client_prepare_iopause(i, &deadline, x, &j)) r = 0 ; + if (!cont && r) break ; + + r = iopause_g(x, j, &deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + + if (!r) + { + if (!cont && !tain_future(&lameduckdeadline)) break ; + for (;;) + { + if (!avltreen_min(fds_by_deadline, &i)) break ; + if (tain_future(&FD(i)->limit)) break ; + fds_close_and_delete(i) ; + } + for (j = sentinel, i = clientstorage[sentinel].next ; i != sentinel ; j = i, i = clientstorage[i].next) + if (!tain_future(&clientstorage[i].deadline)) removeclient(&i, j) ; + continue ; + } + + if (x[0].revents & IOPAUSE_READ) handle_signals() ; + + for (j = sentinel, i = clientstorage[sentinel].next ; i != sentinel ; j = i, i = clientstorage[i].next) + if (!client_flush(i, x)) removeclient(&i, j) ; + + for (j = sentinel, i = clientstorage[sentinel].next ; i != sentinel ; j = i, i = clientstorage[i].next) + if (!client_read(i, x)) removeclient(&i, j) ; + + if (x[1].revents & IOPAUSE_READ) + { + regex_t rre, wre ; + unsigned int flags = 0 ; + int dummy ; + int fd = ipc_accept_nb(x[1].fd, 0, 0, &dummy) ; + if (fd < 0) + if (!error_isagain(errno)) strerr_diefu1sys(111, "accept") ; + else continue ; + else if (!new_connection(fd, &rre, &wre, &flags)) fd_close(fd) ; + else client_add(&i, fd, &rre, &wre, flags) ; + } + } + return ((!!numfds) | (!!numconn << 1)) ; + } +} diff --git a/src/libs6rc/deps-lib/s6rc b/src/serverlib/deps-lib/s6rc index 52c220f..52c220f 100644 --- a/src/libs6rc/deps-lib/s6rc +++ b/src/serverlib/deps-lib/s6rc diff --git a/src/libs6rc/s6rc-servicedir-internal.h b/src/serverlib/s6rc-servicedir-internal.h index a4af0b9..a4af0b9 100644 --- a/src/libs6rc/s6rc-servicedir-internal.h +++ b/src/serverlib/s6rc-servicedir-internal.h diff --git a/src/libs6rc/s6rc_db_check_depcycles.c b/src/serverlib/s6rc_db_check_depcycles.c index 5f8339e..5f8339e 100644 --- a/src/libs6rc/s6rc_db_check_depcycles.c +++ b/src/serverlib/s6rc_db_check_depcycles.c diff --git a/src/libs6rc/s6rc_db_check_pipelines.c b/src/serverlib/s6rc_db_check_pipelines.c index 68121e2..68121e2 100644 --- a/src/libs6rc/s6rc_db_check_pipelines.c +++ b/src/serverlib/s6rc_db_check_pipelines.c diff --git a/src/libs6rc/s6rc_db_check_revdeps.c b/src/serverlib/s6rc_db_check_revdeps.c index 0097d06..0097d06 100644 --- a/src/libs6rc/s6rc_db_check_revdeps.c +++ b/src/serverlib/s6rc_db_check_revdeps.c diff --git a/src/libs6rc/s6rc_db_read.c b/src/serverlib/s6rc_db_read.c index 3991b4f..3991b4f 100644 --- a/src/libs6rc/s6rc_db_read.c +++ b/src/serverlib/s6rc_db_read.c diff --git a/src/libs6rc/s6rc_db_read_sizes.c b/src/serverlib/s6rc_db_read_sizes.c index 433af2e..433af2e 100644 --- a/src/libs6rc/s6rc_db_read_sizes.c +++ b/src/serverlib/s6rc_db_read_sizes.c diff --git a/src/libs6rc/s6rc_db_read_uint32.c b/src/serverlib/s6rc_db_read_uint32.c index b26bf46..b26bf46 100644 --- a/src/libs6rc/s6rc_db_read_uint32.c +++ b/src/serverlib/s6rc_db_read_uint32.c diff --git a/src/libs6rc/s6rc_graph_closure.c b/src/serverlib/s6rc_graph_closure.c index 7c3a8f9..7c3a8f9 100644 --- a/src/libs6rc/s6rc_graph_closure.c +++ b/src/serverlib/s6rc_graph_closure.c diff --git a/src/libs6rc/s6rc_livedir_create.c b/src/serverlib/s6rc_livedir_create.c index fd23a07..fd23a07 100644 --- a/src/libs6rc/s6rc_livedir_create.c +++ b/src/serverlib/s6rc_livedir_create.c diff --git a/src/libs6rc/s6rc_livedir_prefix.c b/src/serverlib/s6rc_livedir_prefix.c index 09fe263..09fe263 100644 --- a/src/libs6rc/s6rc_livedir_prefix.c +++ b/src/serverlib/s6rc_livedir_prefix.c diff --git a/src/libs6rc/s6rc_livedir_prefixsize.c b/src/serverlib/s6rc_livedir_prefixsize.c index d897fe6..d897fe6 100644 --- a/src/libs6rc/s6rc_livedir_prefixsize.c +++ b/src/serverlib/s6rc_livedir_prefixsize.c diff --git a/src/libs6rc/s6rc_lock.c b/src/serverlib/s6rc_lock.c index d3ae2b5..d3ae2b5 100644 --- a/src/libs6rc/s6rc_lock.c +++ b/src/serverlib/s6rc_lock.c diff --git a/src/libs6rc/s6rc_read_uint.c b/src/serverlib/s6rc_read_uint.c index 1f148ac..1f148ac 100644 --- a/src/libs6rc/s6rc_read_uint.c +++ b/src/serverlib/s6rc_read_uint.c diff --git a/src/libs6rc/s6rc_sanitize_dir.c b/src/serverlib/s6rc_sanitize_dir.c index 9f647a9..9f647a9 100644 --- a/src/libs6rc/s6rc_sanitize_dir.c +++ b/src/serverlib/s6rc_sanitize_dir.c diff --git a/src/libs6rc/s6rc_servicedir_block.c b/src/serverlib/s6rc_servicedir_block.c index bfa6440..bfa6440 100644 --- a/src/libs6rc/s6rc_servicedir_block.c +++ b/src/serverlib/s6rc_servicedir_block.c diff --git a/src/libs6rc/s6rc_servicedir_copy_offline.c b/src/serverlib/s6rc_servicedir_copy_offline.c index 6581a4f..6581a4f 100644 --- a/src/libs6rc/s6rc_servicedir_copy_offline.c +++ b/src/serverlib/s6rc_servicedir_copy_offline.c diff --git a/src/libs6rc/s6rc_servicedir_copy_online.c b/src/serverlib/s6rc_servicedir_copy_online.c index e676d5a..e676d5a 100644 --- a/src/libs6rc/s6rc_servicedir_copy_online.c +++ b/src/serverlib/s6rc_servicedir_copy_online.c diff --git a/src/libs6rc/s6rc_servicedir_internal.c b/src/serverlib/s6rc_servicedir_internal.c index b70061f..b70061f 100644 --- a/src/libs6rc/s6rc_servicedir_internal.c +++ b/src/serverlib/s6rc_servicedir_internal.c diff --git a/src/libs6rc/s6rc_servicedir_manage.c b/src/serverlib/s6rc_servicedir_manage.c index 5449f35..5449f35 100644 --- a/src/libs6rc/s6rc_servicedir_manage.c +++ b/src/serverlib/s6rc_servicedir_manage.c diff --git a/src/libs6rc/s6rc_servicedir_unblock.c b/src/serverlib/s6rc_servicedir_unblock.c index 2a10bfd..2a10bfd 100644 --- a/src/libs6rc/s6rc_servicedir_unblock.c +++ b/src/serverlib/s6rc_servicedir_unblock.c diff --git a/src/libs6rc/s6rc_servicedir_unsupervise.c b/src/serverlib/s6rc_servicedir_unsupervise.c index 2d15a70..2d15a70 100644 --- a/src/libs6rc/s6rc_servicedir_unsupervise.c +++ b/src/serverlib/s6rc_servicedir_unsupervise.c |