summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-01-23 23:47:14 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-01-23 23:47:14 +0000
commit49cb17940e403431566dc7b5a312624f14eb25d0 (patch)
tree2f85adb6b0083eec04cce56fd1954889adcdd478 /src
parente62d3ae45e9bf3b97551b8879bf6c441ff961ec1 (diff)
downloads6-49cb17940e403431566dc7b5a312624f14eb25d0.tar.xz
Added fdholder, beta. Documentation will come next.
Diffstat (limited to 'src')
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-daemon1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-getdump1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-getdumpc4
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-list1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-listc4
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-retrieve1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-retrievec4
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-setdump1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-setdumpc4
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-store1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-storec4
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-transferdump1
-rw-r--r--src/fdholder/deps-exe/s6-fdholder-transferdumpc4
-rw-r--r--src/fdholder/deps-exe/s6-fdholderd4
-rw-r--r--src/fdholder/s6-fdholder-daemon.c156
-rw-r--r--src/fdholder/s6-fdholder-getdump.c58
-rw-r--r--src/fdholder/s6-fdholder-getdumpc.c82
-rw-r--r--src/fdholder/s6-fdholder-list.c52
-rw-r--r--src/fdholder/s6-fdholder-listc.c61
-rw-r--r--src/fdholder/s6-fdholder-retrieve.c62
-rw-r--r--src/fdholder/s6-fdholder-retrievec.c52
-rw-r--r--src/fdholder/s6-fdholder-setdump.c49
-rw-r--r--src/fdholder/s6-fdholder-setdumpc.c76
-rw-r--r--src/fdholder/s6-fdholder-store.c63
-rw-r--r--src/fdholder/s6-fdholder-storec.c46
-rw-r--r--src/fdholder/s6-fdholder-transferdump.c88
-rw-r--r--src/fdholder/s6-fdholder-transferdumpc.c51
-rw-r--r--src/fdholder/s6-fdholderd.c798
-rw-r--r--src/libs6/s6_fdholder_setdump.c6
29 files changed, 1732 insertions, 3 deletions
diff --git a/src/fdholder/deps-exe/s6-fdholder-daemon b/src/fdholder/deps-exe/s6-fdholder-daemon
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-daemon
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-getdump b/src/fdholder/deps-exe/s6-fdholder-getdump
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-getdump
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-getdumpc b/src/fdholder/deps-exe/s6-fdholder-getdumpc
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-getdumpc
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholder-list b/src/fdholder/deps-exe/s6-fdholder-list
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-list
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-listc b/src/fdholder/deps-exe/s6-fdholder-listc
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-listc
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholder-retrieve b/src/fdholder/deps-exe/s6-fdholder-retrieve
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-retrieve
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-retrievec b/src/fdholder/deps-exe/s6-fdholder-retrievec
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-retrievec
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholder-setdump b/src/fdholder/deps-exe/s6-fdholder-setdump
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-setdump
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-setdumpc b/src/fdholder/deps-exe/s6-fdholder-setdumpc
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-setdumpc
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholder-store b/src/fdholder/deps-exe/s6-fdholder-store
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-store
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-storec b/src/fdholder/deps-exe/s6-fdholder-storec
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-storec
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholder-transferdump b/src/fdholder/deps-exe/s6-fdholder-transferdump
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-transferdump
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/fdholder/deps-exe/s6-fdholder-transferdumpc b/src/fdholder/deps-exe/s6-fdholder-transferdumpc
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholder-transferdumpc
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/deps-exe/s6-fdholderd b/src/fdholder/deps-exe/s6-fdholderd
new file mode 100644
index 0000000..f3a3143
--- /dev/null
+++ b/src/fdholder/deps-exe/s6-fdholderd
@@ -0,0 +1,4 @@
+${LIBS6}
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/fdholder/s6-fdholder-daemon.c b/src/fdholder/s6-fdholder-daemon.c
new file mode 100644
index 0000000..18d189c
--- /dev/null
+++ b/src/fdholder/s6-fdholder-daemon.c
@@ -0,0 +1,156 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <skalibs/uint.h>
+#include <skalibs/gidstuff.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-daemon [ -v verbosity ] [ -d | -D ] [ -1 ] [ -c maxconn ] [ -n maxfds ] [ -b backlog ] [ -G gid,gid,... ] [ -g gid ] [ -u uid ] [ -U ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] path"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ unsigned int verbosity = 1 ;
+ int flag1 = 0 ;
+ int flagU = 0 ;
+ int flagreuse = 1 ;
+ unsigned int uid = 0, gid = 0 ;
+ gid_t gids[NGROUPS_MAX] ;
+ unsigned int gidn = (unsigned int)-1 ;
+ unsigned int maxconn = 0 ;
+ unsigned int maxfds = 0 ;
+ unsigned int backlog = (unsigned int)-1 ;
+ unsigned int timeout = 0 ;
+ unsigned int ltimeout = 0 ;
+ char const *rulesdir = 0 ;
+ char const *rulesfile = 0 ;
+ PROG = "s6-fdholder-daemon" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "Dd1Uv:c:n:b:u:g:G:t:T:i:x:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'D' : flagreuse = 0 ; break ;
+ case 'd' : flagreuse = 1 ; break ;
+ case '1' : flag1 = 1 ; break ;
+ case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
+ case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ;
+ case 'n' : if (!uint0_scan(l.arg, &maxfds)) dieusage() ; if (!maxfds) maxfds = 1 ; break ;
+ case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ;
+ case 'u' : if (!uint0_scan(l.arg, &uid)) dieusage() ; break ;
+ case 'g' : if (!uint0_scan(l.arg, &gid)) dieusage() ; break ;
+ case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ;
+ case 'U' : flagU = 1 ; uid = 0 ; gid = 0 ; gidn = (unsigned int)-1 ; break ;
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ case 'T' : if (!uint0_scan(l.arg, &ltimeout)) dieusage() ; break ;
+ case 'i' : rulesdir = l.arg ; rulesfile = 0 ; break ;
+ case 'x' : rulesfile = l.arg ; rulesdir = 0 ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (!argc) dieusage() ;
+ }
+ if (!rulesdir && !rulesfile) strerr_dief1x(100, "no access rights specified!") ;
+
+ {
+ unsigned int m = 0, pos = 0 ;
+ char const *newargv[30] ;
+ char fmt[UINT_FMT * 8 + GID_FMT * NGROUPS_MAX] ;
+ newargv[m++] = S6_BINPREFIX "s6-ipcserver-socketbinder" ;
+ if (!flagreuse) newargv[m++] = "-D" ;
+ if (backlog != (unsigned int)-1)
+ {
+ newargv[m++] = "-b" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, backlog) ;
+ fmt[pos++] = 0 ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = *argv++ ;
+ if (flagU || uid || gid || gidn != (unsigned int)-1)
+ {
+ newargv[m++] = S6_BINPREFIX "s6-applyuidgid" ;
+ if (flagU) newargv[m++] = "-Uz" ;
+ if (uid)
+ {
+ newargv[m++] = "-u" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, uid) ;
+ fmt[pos++] = 0 ;
+ }
+ if (gid)
+ {
+ newargv[m++] = "-g" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, gid) ;
+ fmt[pos++] = 0 ;
+ }
+ if (gidn != (unsigned int)-1)
+ {
+ newargv[m++] = "-G" ;
+ newargv[m++] = fmt + pos ;
+ pos += gid_fmtlist(fmt + pos, gids, gidn) ;
+ fmt[pos++] = 0 ;
+ }
+ newargv[m++] = "--" ;
+ }
+ newargv[m++] = S6_BINPREFIX "s6-fdholderd" ;
+ if (verbosity != 1)
+ {
+ newargv[m++] = "-v" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, verbosity) ;
+ fmt[pos++] = 0 ;
+ }
+ if (flag1) newargv[m++] = "-1" ;
+ if (maxconn)
+ {
+ newargv[m++] = "-c" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, maxconn) ;
+ fmt[pos++] = 0 ;
+ }
+ if (maxfds)
+ {
+ newargv[m++] = "-n" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, maxfds) ;
+ fmt[pos++] = 0 ;
+ }
+ if (timeout)
+ {
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, timeout) ;
+ fmt[pos++] = 0 ;
+ }
+ if (ltimeout)
+ {
+ newargv[m++] = "-T" ;
+ newargv[m++] = fmt + pos ;
+ pos += uint_fmt(fmt + pos, timeout) ;
+ fmt[pos++] = 0 ;
+ }
+ if (rulesdir)
+ {
+ newargv[m++] = "-i" ;
+ newargv[m++] = rulesdir ;
+ }
+ else if (rulesfile)
+ {
+ newargv[m++] = "-x" ;
+ newargv[m++] = rulesfile ;
+ }
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+ }
+}
diff --git a/src/fdholder/s6-fdholder-getdump.c b/src/fdholder/s6-fdholder-getdump.c
new file mode 100644
index 0000000..7ac88a2
--- /dev/null
+++ b/src/fdholder/s6-fdholder-getdump.c
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <execline/config.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-getdump [ -t timeout ] socket prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ unsigned int timeout = 0 ;
+ PROG = "s6-fdholder-retrieve" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (argc < 2) dieusage() ;
+ }
+
+ {
+ char const *newargv[12 + argc] ;
+ unsigned int m = 0 ;
+ char fmtt[UINT_FMT] ;
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = *argv++ ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-getdumpc" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "6" ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "7" ;
+ while (*argv) newargv[m++] = *argv++ ;
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+ }
+}
diff --git a/src/fdholder/s6-fdholder-getdumpc.c b/src/fdholder/s6-fdholder-getdumpc.c
new file mode 100644
index 0000000..ff7fd9d
--- /dev/null
+++ b/src/fdholder/s6-fdholder-getdumpc.c
@@ -0,0 +1,82 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/genalloc.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-getdumpc [ -t timeout ] prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ genalloc dump = GENALLOC_ZERO ;
+ tain_t deadline, halfinfinite ;
+ PROG = "s6-fdholder-getdumpc" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+ if (!argc) dieusage() ;
+
+ s6_fdholder_init(&a, 6) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ if (!s6_fdholder_getdump_g(&a, &dump, &deadline))
+ strerr_diefu1sys(111, "get dump") ;
+ s6_fdholder_free(&a) ;
+ tain_half(&halfinfinite, &tain_infinite_relative) ;
+ tain_add_g(&halfinfinite, &halfinfinite) ;
+ {
+ unsigned int n = genalloc_len(s6_fdholder_fd_t, &dump) ;
+ unsigned int pos = 0, i = 0 ;
+ char modifs[7 + UINT_FMT + (25 + TIMESTAMP + 4 * UINT_FMT) * n] ;
+ byte_copy(modifs + pos, 7, "S6_FD#=") ; pos += 7 ;
+ pos += uint_fmt(modifs + pos, n) ;
+ modifs[pos++] = 0 ;
+ for (; i < n ; i++)
+ {
+ s6_fdholder_fd_t *p = genalloc_s(s6_fdholder_fd_t, &dump) + i ;
+ unsigned int len = str_len(p->id) + 1 ;
+ if (uncoe(p->fd) < 0) strerr_diefu1sys(111, "uncoe") ;
+ byte_copy(modifs + pos, 6, "S6_FD_") ; pos += 6 ;
+ pos += uint_fmt(modifs + pos, i) ;
+ modifs[pos++] = '=' ;
+ pos += uint_fmt(modifs + pos, p->fd) ;
+ modifs[pos++] = 0 ;
+ byte_copy(modifs + pos, 8, "S6_FDID_") ; pos += 8 ;
+ pos += uint_fmt(modifs + pos, i) ;
+ modifs[pos++] = '=' ;
+ byte_copy(modifs + pos, len, p->id) ;
+ pos += len ;
+ if (tain_less(&p->limit, &halfinfinite))
+ {
+ byte_copy(modifs + pos, 11, "S6_FDLIMIT_") ; pos += 11 ;
+ pos += uint_fmt(modifs + pos, i) ;
+ modifs[pos++] = '=' ;
+ pos += timestamp_fmt(modifs + pos, &p->limit) ;
+ modifs[pos++] = 0 ;
+ }
+ }
+ pathexec_r(argv, envp, env_len(envp), modifs, pos) ;
+ }
+ strerr_dieexec(111, argv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-list.c b/src/fdholder/s6-fdholder-list.c
new file mode 100644
index 0000000..2c6f73e
--- /dev/null
+++ b/src/fdholder/s6-fdholder-list.c
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-list [ -t timeout ] [ -T ] socket"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[9] ;
+ unsigned int m = 0 ;
+ unsigned int timeout = 0 ;
+ int printexpire = 0 ;
+ char fmtt[UINT_FMT] ;
+ PROG = "s6-fdholder-list" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "d:t:T:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'T' : printexpire = 1 ; break ;
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (!argc) dieusage() ;
+
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-listc" ;
+ if (printexpire) newargv[m++] = "-T" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-listc.c b/src/fdholder/s6-fdholder-listc.c
new file mode 100644
index 0000000..fefb676
--- /dev/null
+++ b/src/fdholder/s6-fdholder-listc.c
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-listc [ -t timeout ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ stralloc sa = STRALLOC_ZERO, sb = STRALLOC_ZERO ;
+ unsigned int pos = 0 ;
+ int n ;
+ tain_t deadline ;
+ PROG = "s6-fdholder-listc" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+
+ s6_fdholder_init(&a, 6) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ n = s6_fdholder_list_g(&a, &sa, &deadline) ;
+ if (n < 0) strerr_diefu1sys(111, "get fd list") ;
+ while (n--)
+ {
+ register unsigned int len = str_len(sa.s + pos) ;
+ sb.len = 0 ;
+ if (!string_quote_nodelim_mustquote(&sb, sa.s + pos, len, 0, 0))
+ strerr_diefu1sys(111, "quote string") ;
+ if (buffer_put(buffer_1, sb.s, sb.len) < sb.len || buffer_put(buffer_1, "\n", 1) < 1)
+ strerr_diefu1sys(111, "buffer_put") ;
+ pos += len+1 ;
+ }
+ stralloc_free(&sb) ;
+ stralloc_free(&sa) ;
+ if (!buffer_flush(buffer_1)) strerr_diefu1sys(111, "write to stdout") ;
+ return 0 ;
+}
diff --git a/src/fdholder/s6-fdholder-retrieve.c b/src/fdholder/s6-fdholder-retrieve.c
new file mode 100644
index 0000000..3622580
--- /dev/null
+++ b/src/fdholder/s6-fdholder-retrieve.c
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <execline/config.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-retrieve [ -D ] [ -t timeout ] socket id prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ unsigned int timeout = 0 ;
+ int dodelete = 0 ;
+ PROG = "s6-fdholder-retrieve" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "Dt:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'D' : dodelete = 1 ; break ;
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (argc < 3) dieusage() ;
+ }
+
+ {
+ char const *newargv[13 + argc] ;
+ unsigned int m = 0 ;
+ char fmtt[UINT_FMT] ;
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = *argv++ ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-retrievec" ;
+ if (dodelete) newargv[m++] = "-D" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = *argv++ ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "6" ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "7" ;
+ while (*argv) newargv[m++] = *argv++ ;
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+ }
+}
diff --git a/src/fdholder/s6-fdholder-retrievec.c b/src/fdholder/s6-fdholder-retrievec.c
new file mode 100644
index 0000000..2aea31e
--- /dev/null
+++ b/src/fdholder/s6-fdholder-retrievec.c
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-retrievec [ -D ] [ -t timeout ] id prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ tain_t deadline ;
+ int fd ;
+ int dodelete = 0 ;
+ PROG = "s6-fdholder-retrievec" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "Dt:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'D' : dodelete = 1 ; break ;
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+ if (!argc) dieusage() ;
+
+ s6_fdholder_init(&a, 6) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ fd = s6_fdholder_retrieve_maybe_delete_g(&a, argv[0], dodelete, &deadline) ;
+ if (fd < 0) strerr_diefu2sys(111, "retrieve fd for id ", argv[0]) ;
+ else if (!fd)
+ {
+ if (uncoe(0) < 0) strerr_diefu1sys(111, "uncoe stdin") ;
+ }
+ else if (fd_move(0, fd) < 0) strerr_diefu1sys(111, "move fd") ;
+ pathexec_run(argv[1], argv+1, envp) ;
+ strerr_dieexec(111, argv[1]) ;
+}
diff --git a/src/fdholder/s6-fdholder-setdump.c b/src/fdholder/s6-fdholder-setdump.c
new file mode 100644
index 0000000..72be5f7
--- /dev/null
+++ b/src/fdholder/s6-fdholder-setdump.c
@@ -0,0 +1,49 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-setdump [ -t timeout ] socket"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[8] ;
+ unsigned int timeout = 0 ;
+ unsigned int m = 0 ;
+ char fmtt[UINT_FMT] ;
+ PROG = "s6-fdholder-setdump" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (!argc) dieusage() ;
+
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-setdumpc" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-setdumpc.c b/src/fdholder/s6-fdholder-setdumpc.c
new file mode 100644
index 0000000..8a74dba
--- /dev/null
+++ b/src/fdholder/s6-fdholder-setdumpc.c
@@ -0,0 +1,76 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-setdumpc [ -t timeout ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ tain_t deadline ;
+ unsigned int dumplen ;
+ char const *x ;
+ PROG = "s6-fdholder-setdumpc" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+
+ s6_fdholder_init(&a, 6) ;
+ x = env_get2(envp, "S6_FD#") ;
+ if (!x) strerr_dienotset(100, "S6_FD#") ;
+ if (!uint0_scan(x, &dumplen)) strerr_dieinvalid(100, "S6_FD#") ;
+ if (dumplen)
+ {
+ unsigned int i = 0 ;
+ s6_fdholder_fd_t dump[dumplen] ;
+ char s[11 + UINT_FMT] ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ for (; i < dumplen ; i++)
+ {
+ unsigned int fd, len ;
+ byte_copy(s, 6, "S6_FD_") ;
+ s[6 + uint_fmt(s+6, i)] = 0 ;
+ x = env_get2(envp, s) ;
+ if (!x) strerr_dienotset(100, s) ;
+ if (!uint0_scan(x, &fd)) strerr_dieinvalid(100, s) ;
+ dump[i].fd = fd ;
+ byte_copy(s, 8, "S6_FDID_") ;
+ s[8 + uint_fmt(s+8, i)] = 0 ;
+ x = env_get2(envp, s) ;
+ if (!x) strerr_dienotset(100, s) ;
+ len = str_len(x) ;
+ if (!len || len > S6_FDHOLDER_ID_SIZE) strerr_dieinvalid(100, s) ;
+ byte_copy(dump[i].id, len+1, x) ;
+ byte_copy(s, 11, "S6_FDLIMIT_") ;
+ s[11 + uint_fmt(s+11, i)] = 0 ;
+ x = env_get2(envp, s) ;
+ if (!x) tain_add_g(&dump[i].limit, &tain_infinite_relative) ;
+ else if (!timestamp_scan(x, &dump[i].limit)) strerr_dieinvalid(100, s) ;
+ }
+ if (!s6_fdholder_setdump_g(&a, dump, dumplen, &deadline))
+ strerr_diefu1sys(111, "set dump") ;
+ }
+ return 0 ;
+}
diff --git a/src/fdholder/s6-fdholder-store.c b/src/fdholder/s6-fdholder-store.c
new file mode 100644
index 0000000..76faa88
--- /dev/null
+++ b/src/fdholder/s6-fdholder-store.c
@@ -0,0 +1,63 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-store [ -d fd ] [ -t timeout ] [ -T fdtimeout ] socket id"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[12] ;
+ unsigned int timeout = 0, limit = 0 ;
+ unsigned int m = 0 ;
+ char fmtt[UINT_FMT] ;
+ char fmtl[UINT_FMT] ;
+ PROG = "s6-fdholder-store" ;
+ {
+ unsigned int fd = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "d:t:T:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'd' : if (!uint0_scan(l.arg, &fd)) dieusage() ; break ;
+ case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
+ case 'T' : if (!uint0_scan(l.arg, &limit)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (argc < 2) dieusage() ;
+ if (fd && fd_move(0, fd) < 0)
+ strerr_diefu1sys(111, "move file descriptor") ;
+ }
+
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-storec" ;
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ if (limit)
+ {
+ fmtl[uint_fmt(fmtl, limit)] = 0 ;
+ newargv[m++] = "-T" ;
+ newargv[m++] = fmtl ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[1] ;
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-storec.c b/src/fdholder/s6-fdholder-storec.c
new file mode 100644
index 0000000..57257da
--- /dev/null
+++ b/src/fdholder/s6-fdholder-storec.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-storec [ -t timeout ] [ -T fdtimeout ] id"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ tain_t deadline, limit ;
+ PROG = "s6-fdholder-storec" ;
+ {
+ unsigned int t = 0, T = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:T:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ if (T) tain_from_millisecs(&limit, T) ;
+ else limit = tain_infinite_relative ;
+ }
+ if (!argc) dieusage() ;
+
+ s6_fdholder_init(&a, 6) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ tain_add_g(&limit, &limit) ;
+ if (!s6_fdholder_store_g(&a, 0, argv[0], &limit, &deadline))
+ strerr_diefu1sys(111, "store fd") ;
+ return 0 ;
+}
diff --git a/src/fdholder/s6-fdholder-transferdump.c b/src/fdholder/s6-fdholder-transferdump.c
new file mode 100644
index 0000000..3f86d69
--- /dev/null
+++ b/src/fdholder/s6-fdholder-transferdump.c
@@ -0,0 +1,88 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/env.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <execline/config.h>
+#include <s6/config.h>
+
+#define USAGE "s6-fdholder-transferdump [ -t timeoutfrom:timeoutto ] socketfrom socketto"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[24] ;
+ unsigned int timeoutfrom = 0, timeoutto = 0 ;
+ unsigned int m = 0 ;
+ char fmtfrom[UINT_FMT] ;
+ char fmtto[UINT_FMT] ;
+ PROG = "s6-fdholder-setdump" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' :
+ {
+ unsigned int pos = uint_scan(l.arg, &timeoutfrom) ;
+ if (!pos)
+ {
+ if (l.arg[pos] != ':') dieusage() ;
+ timeoutfrom = 0 ;
+ }
+ if (!l.arg[pos]) timeoutto = 0 ;
+ else
+ {
+ if (l.arg[pos++] != ':') dieusage() ;
+ if (!l.arg[pos]) timeoutto = 0 ;
+ else if (!uint0_scan(l.arg + pos, &timeoutto)) dieusage() ;
+ }
+ break ;
+ }
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (argc < 2) dieusage() ;
+
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "7" ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdmove" ;
+ newargv[m++] = "0" ;
+ newargv[m++] = "6" ;
+ newargv[m++] = S6_BINPREFIX "s6-ipcclient" ;
+ newargv[m++] = "-l0" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[1] ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "6" ;
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdmove" ;
+ newargv[m++] = "1" ;
+ newargv[m++] = "7" ;
+ newargv[m++] = S6_BINPREFIX "s6-fdholder-transferdumpc" ;
+ if (timeoutfrom)
+ {
+ fmtfrom[uint_fmt(fmtfrom, timeoutfrom)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtfrom ;
+ }
+ if (timeoutto)
+ {
+ fmtto[uint_fmt(fmtto, timeoutto)] = 0 ;
+ newargv[m++] = "-T" ;
+ newargv[m++] = fmtto ;
+ }
+ newargv[m++] = 0 ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+}
diff --git a/src/fdholder/s6-fdholder-transferdumpc.c b/src/fdholder/s6-fdholder-transferdumpc.c
new file mode 100644
index 0000000..e0ed069
--- /dev/null
+++ b/src/fdholder/s6-fdholder-transferdumpc.c
@@ -0,0 +1,51 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/genalloc.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholder-transferdumpc [ -t timeoutfrom ] [ -T timeoutto ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ s6_fdholder_t a = S6_FDHOLDER_ZERO ;
+ genalloc dump = GENALLOC_ZERO ;
+ tain_t deadline, totto ;
+ PROG = "s6-fdholder-transferdumpc" ;
+ {
+ unsigned int t = 0, T = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "t:T:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ if (T) tain_from_millisecs(&totto, T) ;
+ else totto = tain_infinite_relative ;
+ }
+
+ s6_fdholder_init(&a, 0) ;
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+ if (!s6_fdholder_getdump_g(&a, &dump, &deadline))
+ strerr_diefu1sys(111, "get dump") ;
+ s6_fdholder_free(&a) ;
+ s6_fdholder_init(&a, 1) ;
+ tain_add_g(&deadline, &totto) ;
+ if (!s6_fdholder_setdump_g(&a, genalloc_s(s6_fdholder_fd_t, &dump), genalloc_len(s6_fdholder_fd_t, &dump), &deadline))
+ strerr_diefu1sys(111, "set dump") ;
+ return 0 ;
+}
diff --git a/src/fdholder/s6-fdholderd.c b/src/fdholder/s6-fdholderd.c
new file mode 100644
index 0000000..0404165
--- /dev/null
+++ b/src/fdholder/s6-fdholderd.c
@@ -0,0 +1,798 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <regex.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint.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/siovec.h>
+#include <skalibs/cdb.h>
+#include <skalibs/webipc.h>
+#include <skalibs/genset.h>
+#include <skalibs/avltreen.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/unixconnection.h>
+#include <s6/accessrules.h>
+#include <s6/s6-fdholder.h>
+
+#define USAGE "s6-fdholderd [ -v verbosity ] [ -1 ] [ -c maxconn ] [ -n maxfds ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ]"
+#define dieusage() strerr_dieusage(100, USAGE) ;
+
+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 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 = open_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 ;
+ }
+}
+
+ /* fd store */
+
+static genset *fdstore ;
+#define FD(i) genset_p(s6_fdholder_fd_t, fdstore, (i))
+static unsigned int maxfds = 1000 ;
+#define numfds genset_n(fdstore)
+static avltreen *fds_by_id ;
+static avltreen *fds_by_deadline ;
+
+static void *fds_id_dtok (unsigned int d, void *x)
+{
+ (void)x ;
+ return FD(d)->id ;
+}
+
+static int fds_id_cmp (void const *a, void const *b, void *x)
+{
+ (void)x ;
+ return str_diff((char const *)a, (char const *)b) ;
+}
+
+static void *fds_deadline_dtok (unsigned int d, void *x)
+{
+ (void)x ;
+ return &FD(d)->limit ;
+}
+
+static int fds_deadline_cmp (void const *a, void const *b, void *x)
+{
+ register tain_t const *aa = (tain_t const *)a ;
+ register tain_t const *bb = (tain_t const *)b ;
+ (void)x ;
+ return tain_less(aa, bb) ? -1 : tain_less(bb, aa) ;
+}
+
+static void fds_delete (unsigned int pp)
+{
+ avltreen_delete(fds_by_id, fds_id_dtok(pp, 0)) ;
+ avltreen_delete(fds_by_deadline, fds_deadline_dtok(pp, 0)) ;
+ genset_delete(fdstore, pp) ;
+}
+
+
+ /* client connection */
+
+typedef struct client_s client_t, *client_t_ref ;
+struct client_s
+{
+ unsigned int next ;
+ unsigned int xindex ;
+ tain_t deadline ;
+ regex_t rre ;
+ regex_t wre ;
+ unsigned int dumping ;
+ unsigned int flags ;
+ unixconnection_t connection ;
+} ;
+
+static genset *clients ;
+static unsigned int 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 (unsigned int cc, unsigned int prev)
+{
+ register client_t *c = CLIENT(cc) ;
+ CLIENT(prev)->next = c->next ;
+ client_free(c) ;
+ genset_delete(clients, cc) ;
+}
+
+static void removeclient (unsigned int *i, unsigned int 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 (unsigned int i, tain_t *deadline, iopause_fd *x, unsigned int *j)
+{
+ register 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 (unsigned int *cc, int fd, regex_t const *rre, regex_t const *wre, unsigned int flags)
+{
+ unsigned int 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 (unsigned int i, iopause_fd const *x)
+{
+ register 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 (unsigned int cc, unixmessage_t const *m)
+{
+ unsigned int 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, ENOSPC) ;
+ }
+ 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] ;
+ byte_copy(p->id, idlen, m->s + TAIN_PACK + 1) ;
+ byte_zero(p->id + idlen, S6_FDHOLDER_ID_SIZE + 1 - idlen) ;
+ for (;;)
+ {
+ unsigned int 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 (unsigned int cc, unixmessage_t const *m)
+{
+ unsigned int 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 ;
+ fd_close(FD(pp)->fd) ;
+ fds_delete(pp) ;
+ return 1 ;
+}
+
+static int do_retrieve (unsigned int cc, unixmessage_t const *m)
+{
+ int fd ;
+ unixmessage_t ans = { .s = "", .len = 1, .fds = &fd, .nfds = 1 } ;
+ unsigned int 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)
+{
+ siovec_t *v = (*(siovec_t **)data)++ ;
+ s6_fdholder_fd_t *p = (s6_fdholder_fd_t *)thing ;
+ v->s = p->id ;
+ v->len = str_len(p->id) + 1 ;
+ return 1 ;
+}
+
+static int do_list (unsigned int cc, unixmessage_t const *m)
+{
+ client_t *c = CLIENT(cc) ;
+ siovec_t v[numfds] ;
+ unixmessage_v_t ans = { .v = v, .vlen = 1+numfds, .fds = 0, .nfds = 0 } ;
+ siovec_t *vp = v + 1 ;
+ char pack[5] = "" ;
+ if (c->dumping || m->len || m->nfds) return (errno = EPROTO, 0) ;
+ uint32_pack_big(pack + 1, (uint32)numfds) ;
+ v[0].s = pack ; v[0].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
+{
+ siovec_t *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 = str_len(p->id) ;
+ tain_pack(blah->limit, &p->limit) ;
+ blah->limit[TAIN_PACK] = (unsigned char)len ;
+ blah->v->s = p->id ;
+ blah->v->len = len + 1 ;
+ *blah->fd++ = p->fd ;
+ blah->v += 2 ;
+ blah->limit += TAIN_PACK + 1 ;
+ return 1 ;
+}
+
+static int do_getdump (unsigned int cc, unixmessage_t const *m)
+{
+ unsigned int 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, (uint32)n) ;
+ uint32_pack_big(pack+5, (uint32)numfds) ;
+ if (!unixmessage_put(&c->connection.out, &ans)) return answer(c, errno) ;
+ }
+ if (n)
+ {
+ unsigned int i = 0 ;
+ unixmessage_v_t ans[n] ;
+ siovec_t v[numfds << 1] ;
+ int fds[numfds] ;
+ char limits[(TAIN_PACK+1) * numfds] ;
+ for (; i < numfds ; i++)
+ {
+ v[i<<1].s = limits + i * (TAIN_PACK+1) ;
+ v[i<<1].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 (unsigned int cc, unixmessage_t const *m)
+{
+ char pack[5] = "" ;
+ uint32 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 (unsigned int 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 ;
+ unsigned int len = m->len ;
+ unsigned int i = 0 ;
+ unsigned int indices[m->nfds] ;
+ for (; i < m->nfds ; i++)
+ {
+ s6_fdholder_fd_t *p ;
+ unsigned int 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) ;
+ byte_copy(p->id, idlen+1, s + TAIN_PACK + 1) ;
+ p->fd = m->fds[i] ;
+ char fmt[TIMESTAMP] ;
+ fmt[timestamp_fmt(fmt, &p->limit)] = 0 ;
+ 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 (unsigned int cc, unixmessage_t const *m)
+{
+ (void)cc ;
+ (void)m ;
+ return (errno = EPROTO, 0) ;
+}
+
+typedef int parsefunc_t (unsigned int, 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])])(*(unsigned int *)p, &mcopy))
+ {
+ unixmessage_drop(m) ;
+ return 0 ;
+ }
+ return 1 ;
+}
+
+static inline int client_read (unsigned int cc, iopause_fd const *x)
+{
+ register 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)
+{
+ register unsigned int varlen = str_len(var) ;
+ if (str_start(s, var) && (s[varlen] == '='))
+ {
+ int r = 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 = 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 fl = 0 ;
+ int rre_done = 0, wre_done = 0 ;
+ for (; *envp ; envp++)
+ {
+ if (str_start(*envp, "S6_FDHOLDER_GETDUMP=")) fl |= 1 ;
+ if (str_start(*envp, "S6_FDHOLDER_SETDUMP=")) fl |= 2 ;
+ if (!rre_done)
+ {
+ rre_done = makere(rre, *envp, "S6_FDHOLDER_RETRIEVE_REGEX") ;
+ if (rre_done < 0)
+ {
+ if (wre_done) regfree(wre) ;
+ return 0 ;
+ }
+ }
+ if (!wre_done)
+ {
+ wre_done = makere(wre, *envp, "S6_FDHOLDER_STORE_REGEX") ;
+ if (wre_done < 0)
+ {
+ if (rre_done) regfree(rre) ;
+ return 0 ;
+ }
+ }
+ }
+ if (!rre_done) defaultre(wre) ;
+ if (!wre_done) defaultre(wre) ;
+ *flags = fl ;
+ 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 ;
+ unsigned int uid, gid ;
+
+ if (ipc_eid(fd, &uid, &gid) < 0)
+ {
+ if (verbosity) strerr_warnwu1sys("getpeereid") ;
+ return 0 ;
+ }
+
+ switch (rulestype)
+ {
+ case 1 :
+ result = s6_accessrules_uidgid_fs(uid, gid, rules, &params) ; break ;
+ case 2 :
+ result = s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, &params) ; 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[UINT_FMT] ;
+ char fmtgid[UINT_FMT] ;
+ fmtuid[uint_fmt(fmtuid, uid)] = 0 ;
+ fmtgid[uint_fmt(fmtgid, gid)] = 0 ;
+ strerr_warnw4x("unused exec string in rules for uid ", fmtuid, " gid ", fmtgid) ;
+ }
+ if (params.env.s)
+ {
+ unsigned int 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(&params) ;
+ return 0 ;
+ }
+ envp[n] = 0 ;
+ if (!parse_env(envp, rre, wre, flags))
+ {
+ if (verbosity) strerr_warnwu1sys("parse_env") ;
+ s6_accessrules_params_free(&params) ;
+ return 0 ;
+ }
+ s6_accessrules_params_free(&params) ;
+ }
+ return 1 ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ int spfd ;
+ int flag1 = 0 ;
+ unsigned int maxconn = 40 ;
+ PROG = "s6-fdholderd" ;
+
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ unsigned int t = 0, T = 0 ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "v:1c:n:i:x:t:T:", &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 'n' : if (!uint0_scan(l.arg, &maxfds)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&answertto, t) ;
+ if (T) tain_from_millisecs(&lameduckdeadline, T) ;
+ }
+ if (!rulestype) strerr_dief1x(100, "no access rights specified!") ;
+ if (maxconn > S6_FDHOLDER_MAX) maxconn = S6_FDHOLDER_MAX ;
+ if (!maxconn) maxconn = 1 ;
+ {
+ struct rlimit fdlimit ;
+ if (getrlimit(RLIMIT_NOFILE, &fdlimit) < 0)
+ strerr_diefu1sys(111, "getrlimit") ;
+ if (fdlimit.rlim_cur != RLIM_INFINITY)
+ {
+ if (fdlimit.rlim_cur < 6)
+ strerr_dief1x(111, "open file limit too low") ;
+ if (maxfds > fdlimit.rlim_cur) maxfds = fdlimit.rlim_cur - 5 ;
+ }
+ }
+ if (!maxfds) maxfds = 1 ;
+ {
+ struct stat st ;
+ if (fstat(0, &st) < 0) strerr_diefu1sys(111, "fstat stdin") ;
+ if (!S_ISSOCK(st.st_mode)) strerr_dief1x(100, "stdin is not a socket") ;
+ }
+ 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. */
+ GENSETB_TYPE(client_t, 1+maxconn) clientblob ;
+ GENSETB_TYPE(s6_fdholder_fd_t, maxfds) fdblob ;
+ AVLTREEB_TYPE(maxfds) fdmap_id ;
+ AVLTREEB_TYPE(maxfds) fdmap_deadline ;
+ iopause_fd x[2 + maxconn] ;
+ /* Hope you enjoyed it! Have a nice day! */
+
+ GENSETB_init(client_t, &clientblob, 1+maxconn) ;
+ clients = &clientblob.info ;
+ sentinel = gensetb_new(&clientblob) ;
+ clientblob.storage[sentinel].next = sentinel ;
+ GENSETB_init(s6_fdholder_t, &fdblob, maxfds) ;
+ fdstore = &fdblob.info ;
+ avltreeb_init(&fdmap_id, maxfds, &fds_id_dtok, &fds_id_cmp, 0) ;
+ fds_by_id = &fdmap_id.info ;
+ avltreeb_init(&fdmap_deadline, maxfds, &fds_deadline_dtok, &fds_deadline_cmp, 0) ;
+ fds_by_deadline = &fdmap_deadline.info ;
+ x[0].fd = spfd ; x[0].events = IOPAUSE_READ ;
+ x[1].fd = 0 ;
+
+ if (flag1)
+ {
+ fd_write(1, "\n", 1) ;
+ fd_close(1) ;
+ }
+ tain_now_g() ;
+
+ for (;;)
+ {
+ tain_t deadline ;
+ unsigned int j = 2 ;
+ unsigned int i ;
+ int r = 1 ;
+
+ if (cont) tain_add_g(&deadline, &tain_infinite_relative) ;
+ else deadline = lameduckdeadline ;
+ if (avltreeb_min(&fdmap_deadline, &i) && tain_less(&FD(i)->limit, &deadline)) deadline = FD(i)->limit ;
+ x[1].events = (cont && (numconn < maxconn)) ? IOPAUSE_READ : 0 ;
+ for (i = clientblob.storage[sentinel].next ; i != sentinel ; i = clientblob.storage[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)) return 1 ;
+ for (;;)
+ {
+ if (!avltreeb_min(&fdmap_deadline, &i)) break ;
+ if (tain_future(&FD(i)->limit)) break ;
+ fd_close(FD(i)->fd) ;
+ fds_delete(i) ;
+ }
+ for (j = sentinel, i = clientblob.storage[sentinel].next ; i != sentinel ; j = i, i = clientblob.storage[i].next)
+ if (!tain_future(&clientblob.storage[i].deadline)) removeclient(&i, j) ;
+ continue ;
+ }
+
+ if (x[0].revents & IOPAUSE_READ) handle_signals() ;
+
+ for (j = sentinel, i = clientblob.storage[sentinel].next ; i != sentinel ; j = i, i = clientblob.storage[i].next)
+ if (!client_flush(i, x)) removeclient(&i, j) ;
+
+ for (j = sentinel, i = clientblob.storage[sentinel].next ; i != sentinel ; j = i, i = clientblob.storage[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 fd = ipc_accept_nb(x[1].fd, 0, 0, (int *)&i) ;
+ 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 0 ;
+}
diff --git a/src/libs6/s6_fdholder_setdump.c b/src/libs6/s6_fdholder_setdump.c
index 61c238c..b6fb7c4 100644
--- a/src/libs6/s6_fdholder_setdump.c
+++ b/src/libs6/s6_fdholder_setdump.c
@@ -30,7 +30,7 @@ int s6_fdholder_setdump (s6_fdholder_t *a, s6_fdholder_fd_t const *list, unsigne
if (!m.len || m.nfds) { unixmessage_drop(&m) ; return (errno = EPROTO, 0) ; }
if (m.s[0]) return (errno = m.s[0], 0) ;
if (m.len != 5) return (errno = EPROTO, 0) ;
- uint32_unpack_big(pack + 1, &trips) ;
+ uint32_unpack_big(m.s + 1, &trips) ;
if (trips != 1 + (ntot-1) / UNIXMESSAGE_MAXFDS) return (errno = EPROTO, 0) ;
}
for (i = 0 ; i < trips ; i++, ntot -= UNIXMESSAGE_MAXFDS)
@@ -49,9 +49,9 @@ int s6_fdholder_setdump (s6_fdholder_t *a, s6_fdholder_fd_t const *list, unsigne
v[1 + (j<<1)].s = pack + j * (TAIN_PACK+1) ;
v[1 + (j<<1)].len = TAIN_PACK + 1 ;
tain_pack(pack + j * (TAIN_PACK+1), &list->limit) ;
- pack[j * (TAIN_PACK+1) + TAIN_PACK] = (unsigned char)len + 1 ;
+ pack[j * (TAIN_PACK+1) + TAIN_PACK] = (unsigned char)len ;
v[2 + (j<<1)].s = (char *)list->id ;
- v[2 + (j<<1)].len = len ;
+ v[2 + (j<<1)].len = len + 1 ;
fds[j] = list->fd ;
}
if (!unixmessage_putv(&a->connection.out, &m)) return 0 ;