summaryrefslogtreecommitdiff
path: root/src/libs6
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-12-05 22:26:11 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-12-05 22:26:11 +0000
commit90b12bd71bb9fc79a4640b9112c13ef529d0196a (patch)
tree523b3f4ee2969e7a729bab2ba749c4b924ae62af /src/libs6
downloads6-90b12bd71bb9fc79a4640b9112c13ef529d0196a.tar.xz
Initial commit
Diffstat (limited to 'src/libs6')
-rwxr-xr-xsrc/libs6/deps-exe/s6-ftrigrd5
-rwxr-xr-xsrc/libs6/deps-exe/s6lockd3
-rwxr-xr-xsrc/libs6/deps-exe/s6lockd-helper1
-rwxr-xr-xsrc/libs6/deps-lib/s633
-rw-r--r--src/libs6/ftrig1.h23
-rw-r--r--src/libs6/ftrig1_free.c25
-rw-r--r--src/libs6/ftrig1_make.c65
-rw-r--r--src/libs6/ftrigr1_zero.c5
-rw-r--r--src/libs6/ftrigr_check.c40
-rw-r--r--src/libs6/ftrigr_end.c14
-rw-r--r--src/libs6/ftrigr_start.c10
-rw-r--r--src/libs6/ftrigr_startf.c12
-rw-r--r--src/libs6/ftrigr_subscribe.c43
-rw-r--r--src/libs6/ftrigr_unsubscribe.c36
-rw-r--r--src/libs6/ftrigr_update.c43
-rw-r--r--src/libs6/ftrigr_wait_and.c28
-rw-r--r--src/libs6/ftrigr_wait_or.c31
-rw-r--r--src/libs6/ftrigr_zero.c5
-rw-r--r--src/libs6/ftrigw_clean.c39
-rw-r--r--src/libs6/ftrigw_fifodir_make.c26
-rw-r--r--src/libs6/ftrigw_notify.c8
-rw-r--r--src/libs6/ftrigw_notifyb.c67
-rw-r--r--src/libs6/s6-ftrigrd.c266
-rw-r--r--src/libs6/s6_supervise_lock.c10
-rw-r--r--src/libs6/s6_supervise_lock_mode.c54
-rw-r--r--src/libs6/s6_svc_main.c40
-rw-r--r--src/libs6/s6_svc_write.c22
-rw-r--r--src/libs6/s6_svstatus_pack.c13
-rw-r--r--src/libs6/s6_svstatus_read.c17
-rw-r--r--src/libs6/s6_svstatus_unpack.c29
-rw-r--r--src/libs6/s6_svstatus_write.c16
-rw-r--r--src/libs6/s6lock_acquire.c38
-rw-r--r--src/libs6/s6lock_check.c25
-rw-r--r--src/libs6/s6lock_end.c14
-rw-r--r--src/libs6/s6lock_release.c28
-rw-r--r--src/libs6/s6lock_start.c12
-rw-r--r--src/libs6/s6lock_startf.c14
-rw-r--r--src/libs6/s6lock_update.c31
-rw-r--r--src/libs6/s6lock_wait_and.c27
-rw-r--r--src/libs6/s6lock_wait_or.c30
-rw-r--r--src/libs6/s6lock_zero.c5
-rw-r--r--src/libs6/s6lockd-helper.c27
-rw-r--r--src/libs6/s6lockd.c316
43 files changed, 1596 insertions, 0 deletions
diff --git a/src/libs6/deps-exe/s6-ftrigrd b/src/libs6/deps-exe/s6-ftrigrd
new file mode 100755
index 0000000..4b86d93
--- /dev/null
+++ b/src/libs6/deps-exe/s6-ftrigrd
@@ -0,0 +1,5 @@
+ftrig1_free.o
+ftrig1_make.o
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/libs6/deps-exe/s6lockd b/src/libs6/deps-exe/s6lockd
new file mode 100755
index 0000000..e027835
--- /dev/null
+++ b/src/libs6/deps-exe/s6lockd
@@ -0,0 +1,3 @@
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/libs6/deps-exe/s6lockd-helper b/src/libs6/deps-exe/s6lockd-helper
new file mode 100755
index 0000000..e7187fe
--- /dev/null
+++ b/src/libs6/deps-exe/s6lockd-helper
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/libs6/deps-lib/s6 b/src/libs6/deps-lib/s6
new file mode 100755
index 0000000..502694e
--- /dev/null
+++ b/src/libs6/deps-lib/s6
@@ -0,0 +1,33 @@
+ftrigr1_zero.o
+ftrigr_check.o
+ftrigr_end.o
+ftrigr_start.o
+ftrigr_startf.o
+ftrigr_subscribe.o
+ftrigr_unsubscribe.o
+ftrigr_update.o
+ftrigr_wait_and.o
+ftrigr_wait_or.o
+ftrigr_zero.o
+ftrigw_clean.o
+ftrigw_fifodir_make.o
+ftrigw_notify.o
+ftrigw_notifyb.o
+s6_supervise_lock.o
+s6_supervise_lock_mode.o
+s6_svc_main.o
+s6_svc_write.o
+s6_svstatus_pack.o
+s6_svstatus_read.o
+s6_svstatus_unpack.o
+s6_svstatus_write.o
+s6lock_acquire.o
+s6lock_check.o
+s6lock_end.o
+s6lock_release.o
+s6lock_start.o
+s6lock_startf.o
+s6lock_update.o
+s6lock_wait_and.o
+s6lock_wait_or.o
+s6lock_zero.o
diff --git a/src/libs6/ftrig1.h b/src/libs6/ftrig1.h
new file mode 100644
index 0000000..229de66
--- /dev/null
+++ b/src/libs6/ftrig1.h
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#ifndef FTRIG1_H
+#define FTRIG1_H
+
+#include <skalibs/stralloc.h>
+
+#define FTRIG1_PREFIX "ftrig1"
+#define FTRIG1_PREFIXLEN (sizeof FTRIG1_PREFIX - 1)
+
+typedef struct ftrig1_s ftrig1_t, *ftrig1_t_ref ;
+struct ftrig1_s
+{
+ int fd ;
+ int fdw ;
+ stralloc name ;
+} ;
+#define FTRIG1_ZERO { .fd = -1, .fdw = -1, .name = STRALLOC_ZERO }
+
+extern int ftrig1_make (ftrig1_t *, char const *) ;
+extern void ftrig1_free (ftrig1_t *) ;
+
+#endif
diff --git a/src/libs6/ftrig1_free.c b/src/libs6/ftrig1_free.c
new file mode 100644
index 0000000..091dc87
--- /dev/null
+++ b/src/libs6/ftrig1_free.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include "ftrig1.h"
+
+void ftrig1_free (ftrig1_t *p)
+{
+ if (p->name.s)
+ {
+ unlink(p->name.s) ;
+ stralloc_free(&p->name) ;
+ }
+ if (p->fd >= 0)
+ {
+ fd_close(p->fd) ;
+ p->fd = -1 ;
+ }
+ if (p->fdw >= 0)
+ {
+ fd_close(p->fdw) ;
+ p->fdw = -1 ;
+ }
+}
diff --git a/src/libs6/ftrig1_make.c b/src/libs6/ftrig1_make.c
new file mode 100644
index 0000000..7aedd08
--- /dev/null
+++ b/src/libs6/ftrig1_make.c
@@ -0,0 +1,65 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h> /* for rename() */
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/random.h>
+#include "ftrig1.h"
+
+int ftrig1_make (ftrig1_t *f, char const *path)
+{
+ ftrig1_t ff = FTRIG1_ZERO ;
+ unsigned int pathlen = str_len(path) ;
+ int e = 0 ;
+ char tmp[pathlen + 46 + FTRIG1_PREFIXLEN] ;
+
+ byte_copy(tmp, pathlen, path) ;
+ tmp[pathlen] = '/' ; tmp[pathlen+1] = '.' ;
+ byte_copy(tmp + pathlen + 2, FTRIG1_PREFIXLEN, FTRIG1_PREFIX) ;
+ tmp[pathlen + 2 + FTRIG1_PREFIXLEN] = ':' ;
+ if (!timestamp(tmp + pathlen + 3 + FTRIG1_PREFIXLEN)) return 0 ;
+ tmp[pathlen + 28 + FTRIG1_PREFIXLEN] = ':' ;
+ if (random_name(tmp + pathlen + 29 + FTRIG1_PREFIXLEN, 16) < 16) return 0 ;
+ tmp[pathlen + 45 + FTRIG1_PREFIXLEN] = 0 ;
+
+ {
+ mode_t m = umask(0) ;
+ if (mkfifo(tmp, S_IRUSR|S_IWUSR|S_IWGRP|S_IWOTH) == -1)
+ {
+ umask(m) ;
+ return 0 ;
+ }
+ umask(m) ;
+ }
+
+ if (!stralloc_catb(&ff.name, tmp, pathlen+1)) { e = errno ; goto err0 ; }
+ if (!stralloc_catb(&ff.name, tmp + pathlen + 2, FTRIG1_PREFIXLEN + 44))
+ {
+ e = errno ; goto err1 ;
+ }
+ ff.fd = open_read(tmp) ;
+ if (ff.fd == -1) { e = errno ; goto err1 ; }
+ ff.fdw = open_write(tmp) ;
+ if (ff.fdw == -1) { e = errno ; goto err2 ; }
+ if (rename(tmp, ff.name.s) == -1) goto err3 ;
+ *f = ff ;
+ return 1 ;
+
+ err3:
+ e = errno ;
+ fd_close(ff.fdw) ;
+ err2:
+ fd_close(ff.fd) ;
+ err1:
+ stralloc_free(&ff.name) ;
+ err0:
+ unlink(tmp) ;
+ errno = e ;
+ return 0 ;
+}
diff --git a/src/libs6/ftrigr1_zero.c b/src/libs6/ftrigr1_zero.c
new file mode 100644
index 0000000..967b4e0
--- /dev/null
+++ b/src/libs6/ftrigr1_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <s6/ftrigr.h>
+
+ftrigr1_t const ftrigr1_zero = FTRIGR1_ZERO ;
diff --git a/src/libs6/ftrigr_check.c b/src/libs6/ftrigr_check.c
new file mode 100644
index 0000000..147deca
--- /dev/null
+++ b/src/libs6/ftrigr_check.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/gensetdyn.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_check (ftrigr_t *a, uint16 id, char *c)
+{
+ ftrigr1_t *p ;
+ if (!id--) return (errno = EINVAL, -1) ;
+ p = GENSETDYN_P(ftrigr1_t, &a->data, id) ;
+ if (!p) return (errno = EINVAL, -1) ;
+ switch (p->state)
+ {
+ case FR1STATE_WAITACKDATA :
+ {
+ *c = p->what ;
+ *p = ftrigr1_zero ;
+ gensetdyn_delete(&a->data, id) ;
+ return 1 ;
+ }
+ case FR1STATE_LISTENING :
+ {
+ register unsigned int r = p->count ;
+ if (r) *c = p->what ;
+ p->count = 0 ;
+ return (int)r ;
+ }
+ case FR1STATE_WAITACK :
+ {
+ errno = p->what ;
+ *p = ftrigr1_zero ;
+ gensetdyn_delete(&a->data, id) ;
+ return -1 ;
+ }
+ default: return (errno = EINVAL, -1) ;
+ }
+ return 0 ;
+}
diff --git a/src/libs6/ftrigr_end.c b/src/libs6/ftrigr_end.c
new file mode 100644
index 0000000..f35f06c
--- /dev/null
+++ b/src/libs6/ftrigr_end.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+void ftrigr_end (ftrigr_ref a)
+{
+ gensetdyn_free(&a->data) ;
+ genalloc_free(uint16, &a->list) ;
+ skaclient_end(&a->connection) ;
+ *a = ftrigr_zero ;
+}
diff --git a/src/libs6/ftrigr_start.c b/src/libs6/ftrigr_start.c
new file mode 100644
index 0000000..baf9ce5
--- /dev/null
+++ b/src/libs6/ftrigr_start.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_start (ftrigr_t *a, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+ return skaclient_start_b(&a->connection, &a->buffers, path, FTRIGR_BANNER1, FTRIGR_BANNER1_LEN, FTRIGR_BANNER2, FTRIGR_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/libs6/ftrigr_startf.c b/src/libs6/ftrigr_startf.c
new file mode 100644
index 0000000..28c81aa
--- /dev/null
+++ b/src/libs6/ftrigr_startf.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_startf (ftrigr_ref a, tain_t const *deadline, tain_t *stamp)
+{
+ char const *cargv[2] = { FTRIGRD_PROG, 0 } ;
+ char const *cenvp[1] = { 0 } ;
+ return skaclient_startf_b(&a->connection, &a->buffers, cargv[0], cargv, cenvp, SKACLIENT_OPTION_WAITPID, FTRIGR_BANNER1, FTRIGR_BANNER1_LEN, FTRIGR_BANNER2, FTRIGR_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/libs6/ftrigr_subscribe.c b/src/libs6/ftrigr_subscribe.c
new file mode 100644
index 0000000..d645931
--- /dev/null
+++ b/src/libs6/ftrigr_subscribe.c
@@ -0,0 +1,43 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/siovec.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+uint16 ftrigr_subscribe (ftrigr_t *a, char const *path, char const *re, uint32 options, tain_t const *deadline, tain_t *stamp)
+{
+ unsigned int pathlen = str_len(path) ;
+ unsigned int relen = str_len(re) ;
+ unsigned int i ;
+ char err ;
+ char tmp[15] = "--L" ;
+ siovec_t v[3] = { { .s = tmp, .len = 15 }, { .s = (char *)path, .len = pathlen + 1 }, { .s = (char *)re, .len = relen + 1 } } ;
+ if (!gensetdyn_new(&a->data, &i)) return 0 ;
+ uint16_pack_big(tmp, (uint16)i) ;
+ uint32_pack_big(tmp+3, options) ;
+ uint32_pack_big(tmp+7, (uint32)pathlen) ;
+ uint32_pack_big(tmp+11, (uint32)relen) ;
+ if (!skaclient_sendv(&a->connection, v, 3, &skaclient_default_cb, &err, deadline, stamp))
+ {
+ gensetdyn_delete(&a->data, i) ;
+ return 0 ;
+ }
+ if (err)
+ {
+ gensetdyn_delete(&a->data, i) ;
+ return (errno = err, 0) ;
+ }
+ {
+ register ftrigr1_t *p = GENSETDYN_P(ftrigr1_t, &a->data, i) ;
+ p->options = options ;
+ p->state = FR1STATE_LISTENING ;
+ p->count = 0 ;
+ p->what = 0 ;
+ }
+ return (uint16)(i+1) ;
+}
diff --git a/src/libs6/ftrigr_unsubscribe.c b/src/libs6/ftrigr_unsubscribe.c
new file mode 100644
index 0000000..4833571
--- /dev/null
+++ b/src/libs6/ftrigr_unsubscribe.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_unsubscribe (ftrigr_ref a, uint16 i, tain_t const *deadline, tain_t *stamp)
+{
+ ftrigr1_t *p ;
+ if (!i--) return (errno = EINVAL, 0) ;
+ p = GENSETDYN_P(ftrigr1_t, &a->data, i) ;
+ if (!p) return (errno = EINVAL, 0) ;
+ switch (p->state)
+ {
+ case FR1STATE_WAITACK :
+ case FR1STATE_WAITACKDATA :
+ {
+ char dummy ;
+ ftrigr_check(a, i+1, &dummy) ;
+ return 1 ;
+ }
+ default : break ;
+ }
+ {
+ char err ;
+ char pack[3] = "--U" ;
+ uint16_pack_big(pack, i) ;
+ if (!skaclient_send(&a->connection, pack, 3, &skaclient_default_cb, &err, deadline, stamp)) return 0 ;
+ if (err) return (errno = err, 0) ;
+ }
+ *p = ftrigr1_zero ;
+ return gensetdyn_delete(&a->data, i) ;
+}
diff --git a/src/libs6/ftrigr_update.c b/src/libs6/ftrigr_update.c
new file mode 100644
index 0000000..ad69714
--- /dev/null
+++ b/src/libs6/ftrigr_update.c
@@ -0,0 +1,43 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include <s6/ftrigr.h>
+
+static int msghandler (unixmessage_t const *m, void *context)
+{
+ ftrigr_t *a = (ftrigr_t *)context ;
+ ftrigr1_t *p ;
+ uint16 id ;
+ if (m->len != 4 || m->nfds) return (errno = EPROTO, 0) ;
+ uint16_unpack_big(m->s, &id) ;
+ p = GENSETDYN_P(ftrigr1_t, &a->data, id) ;
+ if (!p) return 1 ;
+ if (p->state != FR1STATE_LISTENING) return (errno = EINVAL, 0) ;
+ if (!genalloc_readyplus(uint16, &a->list, 1)) return 0 ;
+ switch (m->s[2])
+ {
+ case 'd' :
+ p->state = FR1STATE_WAITACK ;
+ break ;
+ case '!' :
+ if (p->options & FTRIGR_REPEAT) p->count++ ;
+ else p->state = FR1STATE_WAITACKDATA ;
+ break ;
+ default : return (errno = EPROTO, 0) ;
+ }
+ p->what = m->s[3] ;
+ id++ ; genalloc_append(uint16, &a->list, &id) ;
+ return 1 ;
+}
+
+int ftrigr_update (ftrigr_t *a)
+{
+ genalloc_setlen(uint16, &a->list, 0) ;
+ return skaclient_update(&a->connection, &msghandler, a) ;
+}
diff --git a/src/libs6/ftrigr_wait_and.c b/src/libs6/ftrigr_wait_and.c
new file mode 100644
index 0000000..f854a8d
--- /dev/null
+++ b/src/libs6/ftrigr_wait_and.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_wait_and (ftrigr_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { -1, IOPAUSE_READ, 0 } ;
+ x.fd = ftrigr_fd(a) ;
+ for (; n ; n--, idlist++)
+ {
+ for (;;)
+ {
+ char dummy ;
+ register int r = ftrigr_check(a, *idlist, &dummy) ;
+ if (r < 0) return r ;
+ else if (r) break ;
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return r ;
+ else if (!r) return (errno = ETIMEDOUT, -1) ;
+ else if (ftrigr_update(a) < 0) return -1 ;
+ }
+ }
+ return 1 ;
+}
diff --git a/src/libs6/ftrigr_wait_or.c b/src/libs6/ftrigr_wait_or.c
new file mode 100644
index 0000000..8a01d85
--- /dev/null
+++ b/src/libs6/ftrigr_wait_or.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <s6/ftrigr.h>
+
+int ftrigr_wait_or (ftrigr_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline, tain_t *stamp, char *c)
+{
+ iopause_fd x = { -1, IOPAUSE_READ | IOPAUSE_EXCEPT, 0 } ;
+ x.fd = ftrigr_fd(a) ;
+ if (x.fd < 0) return -1 ;
+ for (;;)
+ {
+ register unsigned int i = 0 ;
+ register int r ;
+ for (; i < n ; i++)
+ {
+ r = ftrigr_check(a, idlist[i], c) ;
+ if (r < 0) return r ;
+ else if (r) return i ;
+ }
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ else if (!r) return (errno = ETIMEDOUT, -1) ;
+ else if (ftrigr_update(a) < 0) return -1 ;
+ }
+ return (errno = EPROTO, -1) ; /* can't happen */
+}
diff --git a/src/libs6/ftrigr_zero.c b/src/libs6/ftrigr_zero.c
new file mode 100644
index 0000000..b09ddb6
--- /dev/null
+++ b/src/libs6/ftrigr_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <s6/ftrigr.h>
+
+ftrigr_t const ftrigr_zero = FTRIGR_ZERO ;
diff --git a/src/libs6/ftrigw_clean.c b/src/libs6/ftrigw_clean.c
new file mode 100644
index 0000000..1198828
--- /dev/null
+++ b/src/libs6/ftrigw_clean.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/direntry.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include "ftrig1.h"
+#include <s6/ftrigw.h>
+
+int ftrigw_clean (char const *path)
+{
+ unsigned int pathlen = str_len(path) ;
+ int e = 0 ;
+ DIR *dir = opendir(path) ;
+ if (!dir) return 0 ;
+ {
+ char tmp[pathlen + FTRIG1_PREFIXLEN + 45] ;
+ byte_copy(tmp, pathlen, path) ;
+ tmp[pathlen] = '/' ; tmp[pathlen + FTRIG1_PREFIXLEN + 44] = 0 ;
+ for (;;)
+ {
+ direntry *d ;
+ int fd ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (str_diffn(d->d_name, FTRIG1_PREFIX, FTRIG1_PREFIXLEN)) continue ;
+ if (str_len(d->d_name) != FTRIG1_PREFIXLEN + 43) continue ;
+ byte_copy(tmp + pathlen + 1, FTRIG1_PREFIXLEN + 43, d->d_name) ;
+ fd = open_write(tmp) ;
+ if (fd >= 0) fd_close(fd) ;
+ else if ((errno == ENXIO) && (unlink(tmp) < 0)) e = errno ;
+ }
+ }
+ if (errno) e = errno ;
+ dir_close(dir) ;
+ return e ? (errno = e, 0) : 1 ;
+}
diff --git a/src/libs6/ftrigw_fifodir_make.c b/src/libs6/ftrigw_fifodir_make.c
new file mode 100644
index 0000000..1a69a8e
--- /dev/null
+++ b/src/libs6/ftrigw_fifodir_make.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <s6/ftrigw.h>
+
+int ftrigw_fifodir_make (char const *path, int gid, int force)
+{
+ mode_t m = umask(0) ;
+ if (mkdir(path, 0700) == -1)
+ {
+ struct stat st ;
+ umask(m) ;
+ if (errno != EEXIST) return 0 ;
+ if (stat(path, &st) == -1) return 0 ;
+ if (st.st_uid != getuid()) return (errno = EACCES, 0) ;
+ if (!S_ISDIR(st.st_mode)) return (errno = ENOTDIR, 0) ;
+ if (!force) return 1 ;
+ }
+ else umask(m) ;
+ if ((gid >= 0) && (chown(path, -1, gid) == -1)) return 0 ;
+ if (chmod(path, (gid >= 0) ? 03730 : 01733) == -1) return 0 ;
+ return 1 ;
+}
diff --git a/src/libs6/ftrigw_notify.c b/src/libs6/ftrigw_notify.c
new file mode 100644
index 0000000..230dad6
--- /dev/null
+++ b/src/libs6/ftrigw_notify.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <s6/ftrigw.h>
+
+int ftrigw_notify (char const *path, char c)
+{
+ return ftrigw_notifyb(path, &c, 1) ;
+}
diff --git a/src/libs6/ftrigw_notifyb.c b/src/libs6/ftrigw_notifyb.c
new file mode 100644
index 0000000..345a3cc
--- /dev/null
+++ b/src/libs6/ftrigw_notifyb.c
@@ -0,0 +1,67 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/direntry.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/sig.h>
+#include <skalibs/djbunix.h>
+#include "ftrig1.h"
+#include <s6/ftrigw.h>
+
+int ftrigw_notifyb (char const *path, char const *s, unsigned int len)
+{
+ unsigned int i = 0 ;
+ struct skasigaction old ;
+ DIR *dir = opendir(path) ;
+ if (!dir) return -1 ;
+ if (skasigaction(SIGPIPE, &SKASIG_IGN, &old) < 0) return -1 ;
+ {
+ unsigned int pathlen = str_len(path) ;
+ char tmp[pathlen + FTRIG1_PREFIXLEN + 45] ;
+ byte_copy(tmp, pathlen, path) ;
+ tmp[pathlen] = '/' ; tmp[pathlen + FTRIG1_PREFIXLEN + 44] = 0 ;
+ for (;;)
+ {
+ direntry *d ;
+ int fd ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (str_diffn(d->d_name, FTRIG1_PREFIX, FTRIG1_PREFIXLEN)) continue ;
+ if (str_len(d->d_name) != FTRIG1_PREFIXLEN + 43) continue ;
+ byte_copy(tmp + pathlen + 1, FTRIG1_PREFIXLEN + 43, d->d_name) ;
+ fd = open_write(tmp) ;
+ if (fd == -1)
+ {
+ if (errno == ENXIO) unlink(tmp) ;
+ }
+ else
+ {
+ register int r = fd_write(fd, s, len) ;
+ if ((r < 0) || (unsigned int)r < len)
+ {
+ if (errno == EPIPE) unlink(tmp) ;
+ /* what to do if EGAIN ? full fifo -> fix the reader !
+ There's a race condition in extreme cases though ;
+ but it's still better to be nonblocking - the writer
+ shouldn't get in trouble because of a bad reader. */
+ fd_close(fd) ;
+ }
+ else
+ {
+ fd_close(fd) ;
+ i++ ;
+ }
+ }
+ }
+ }
+ {
+ int e = errno ;
+ skasigaction(SIGPIPE, &old, 0) ;
+ dir_close(dir) ;
+ return e ? (errno = e, -1) : (int)i ;
+ }
+}
diff --git a/src/libs6/s6-ftrigrd.c b/src/libs6/s6-ftrigrd.c
new file mode 100644
index 0000000..b766f36
--- /dev/null
+++ b/src/libs6/s6-ftrigrd.c
@@ -0,0 +1,266 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <signal.h>
+#include <regex.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/sig.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/iopause.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include "ftrig1.h"
+#include <s6/ftrigr.h>
+
+#define FTRIGRD_MAXREADS 32
+#define FTRIGRD_BUFSIZE 16
+
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+
+typedef struct ftrigio_s ftrigio_t, *ftrigio_t_ref ;
+struct ftrigio_s
+{
+ unsigned int xindex ;
+ ftrig1_t trig ;
+ buffer b ;
+ char buf[FTRIGRD_BUFSIZE] ;
+ regex_t re ;
+ stralloc sa ;
+ uint32 options ;
+ uint16 id ; /* given by client */
+} ;
+#define FTRIGIO_ZERO { .xindex = 0, .trig = FTRIG1_ZERO, .b = BUFFER_INIT(0, -1, 0, 0), .buf = "", .sa = STRALLOC_ZERO, .options = 0, .id = 0 }
+static ftrigio_t const fzero = FTRIGIO_ZERO ;
+
+static genalloc a = GENALLOC_ZERO ; /* array of ftrigio_t */
+
+static void ftrigio_deepfree (ftrigio_t_ref p)
+{
+ ftrig1_free(&p->trig) ;
+ stralloc_free(&p->sa) ;
+ regfree(&p->re) ;
+ *p = fzero ;
+}
+
+static void cleanup (void)
+{
+ register unsigned int i = genalloc_len(ftrigio_t, &a) ;
+ for (; i ; i--) ftrigio_deepfree(genalloc_s(ftrigio_t, &a) + i - 1) ;
+ genalloc_setlen(ftrigio_t, &a, 0) ;
+}
+
+static void trig (uint16 id, char what, char info)
+{
+ char pack[4] ;
+ unixmessage_t m = { .s = pack, .len = 4, .fds = 0, .nfds = 0 } ;
+ uint16_pack_big(pack, id) ;
+ pack[2] = what ; pack[3] = info ;
+ if (!unixmessage_put(unixmessage_sender_x, &m))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "build answer") ;
+ }
+}
+
+static void answer (char c)
+{
+ unixmessage_t m = { &c, 1, 0, 0 } ;
+ if (!unixmessage_put(unixmessage_sender_1, &m))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "unixmessage_put") ;
+ }
+}
+
+static void remove (unsigned int i)
+{
+ register unsigned int n = genalloc_len(ftrigio_t, &a) - 1 ;
+ ftrigio_deepfree(genalloc_s(ftrigio_t, &a) + i) ;
+ genalloc_s(ftrigio_t, &a)[i] = genalloc_s(ftrigio_t, &a)[n] ;
+ genalloc_setlen(ftrigio_t, &a, n) ;
+}
+
+static inline int ftrigio_read (ftrigio_t *p)
+{
+ unsigned int n = FTRIGRD_MAXREADS ;
+ while (n--)
+ {
+ regmatch_t pmatch ;
+ unsigned int blen ;
+ register int r = sanitize_read(buffer_fill(&p->b)) ;
+ if (!r) break ;
+ if (r < 0) return (trig(p->id, 'd', errno), 0) ;
+ blen = buffer_len(&p->b) ;
+ if (!stralloc_readyplus(&p->sa, blen+1)) dienomem() ;
+ buffer_getnofill(&p->b, p->sa.s + p->sa.len, blen) ;
+ p->sa.len += blen ;
+ p->sa.s[p->sa.len] = 0 ;
+ while (!regexec(&p->re, p->sa.s, 1, &pmatch, REG_NOTBOL | REG_NOTEOL))
+ {
+ trig(p->id, '!', p->sa.s[pmatch.rm_eo - 1]) ;
+ if (!(p->options & FTRIGR_REPEAT)) return 0 ;
+ byte_copy(p->sa.s, p->sa.len + 1 - pmatch.rm_eo, p->sa.s + pmatch.rm_eo) ;
+ p->sa.len -= pmatch.rm_eo ;
+ }
+ }
+ return 1 ;
+}
+
+static int parse_protocol (unixmessage_t const *m, void *context)
+{
+ uint16 id ;
+ if (m->len < 3 || m->nfds)
+ {
+ cleanup() ;
+ strerr_dief1x(100, "invalid client request") ;
+ }
+ uint16_unpack_big(m->s, &id) ;
+ switch (m->s[2])
+ {
+ case 'U' : /* unsubscribe */
+ {
+ register unsigned int i = genalloc_len(ftrigio_t, &a) ;
+ for (; i ; i--) if (genalloc_s(ftrigio_t, &a)[i-1].id == id) break ;
+ if (i) remove(i-1) ;
+ answer(0) ;
+ break ;
+ }
+ case 'L' : /* subscribe to path and match re */
+ {
+ ftrigio_t f = FTRIGIO_ZERO ;
+ uint32 pathlen, relen ;
+ int r ;
+ if (m->len < 18)
+ {
+ answer(EPROTO) ;
+ break ;
+ }
+ uint32_unpack_big(m->s + 3, &f.options) ;
+ uint32_unpack_big(m->s + 7, &pathlen) ;
+ uint32_unpack_big(m->s + 11, &relen) ;
+ if (((pathlen + relen + 17) != m->len) || m->s[15 + pathlen] || m->s[m->len - 1])
+ {
+ answer(EPROTO) ;
+ break ;
+ }
+ f.id = id ;
+ r = regcomp(&f.re, m->s + 16 + pathlen, REG_EXTENDED) ;
+ if (r)
+ {
+ answer(r == REG_ESPACE ? ENOMEM : EINVAL) ;
+ break ;
+ }
+ if (!ftrig1_make(&f.trig, m->s + 15))
+ {
+ regfree(&f.re) ;
+ answer(errno) ;
+ break ;
+ }
+ if (!genalloc_append(ftrigio_t, &a, &f))
+ {
+ ftrigio_deepfree(&f) ;
+ answer(errno) ;
+ break ;
+ }
+ answer(0) ;
+ break ;
+ }
+ default :
+ {
+ cleanup() ;
+ strerr_dief1x(100, "invalid client request") ;
+ }
+ }
+ (void)context ;
+ return 1 ;
+}
+
+int main (void)
+{
+ PROG = "s6-ftrigrd" ;
+
+ if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ;
+ if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ;
+ if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;
+
+ {
+ tain_t deadline ;
+ tain_now_g() ;
+ tain_addsec_g(&deadline, 2) ;
+ if (!skaclient_server_01x_init_g(FTRIGR_BANNER1, FTRIGR_BANNER1_LEN, FTRIGR_BANNER2, FTRIGR_BANNER2_LEN, &deadline))
+ strerr_diefu1sys(111, "sync with client") ;
+ }
+
+ for (;;)
+ {
+ register unsigned int n = genalloc_len(ftrigio_t, &a) ;
+ iopause_fd x[3 + n] ;
+ unsigned int i = 0 ;
+
+ x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ;
+ x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_1) ? 0 : IOPAUSE_WRITE) ;
+ x[2].fd = unixmessage_sender_fd(unixmessage_sender_x) ;
+ x[2].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_x) ? 0 : IOPAUSE_WRITE) ;
+ for (; i < n ; i++)
+ {
+ register ftrigio_t_ref p = genalloc_s(ftrigio_t, &a) + i ;
+ p->xindex = 3 + i ;
+ x[3+i].fd = p->trig.fd ;
+ x[3+i].events = IOPAUSE_READ ;
+ }
+
+ if (iopause(x, 3 + n, 0, 0) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "iopause") ;
+ }
+
+ /* client closed */
+ if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) break ;
+
+ /* client is reading */
+ if (x[1].revents & IOPAUSE_WRITE)
+ if ((unixmessage_sender_flush(unixmessage_sender_1) < 0) && !error_isagain(errno))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "flush stdout") ;
+ }
+ if (x[2].revents & IOPAUSE_WRITE)
+ if ((!unixmessage_sender_flush(unixmessage_sender_x) < 0) && !error_isagain(errno))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "flush asyncout") ;
+ }
+
+ /* scan listening ftrigs */
+ for (i = 0 ; i < genalloc_len(ftrigio_t, &a) ; i++)
+ {
+ register ftrigio_t_ref p = genalloc_s(ftrigio_t, &a) + i ;
+ if (x[p->xindex].revents & IOPAUSE_READ)
+ if (!ftrigio_read(p)) remove(i--) ;
+ }
+
+ /* client is writing */
+ if (!unixmessage_receiver_isempty(unixmessage_receiver_0) || x[0].revents & IOPAUSE_READ)
+ {
+ if (unixmessage_handle(unixmessage_receiver_0, &parse_protocol, 0) < 0)
+ {
+ if (errno == EPIPE) break ; /* normal exit */
+ cleanup() ;
+ strerr_diefu1sys(111, "handle messages from client") ;
+ }
+ }
+ }
+ cleanup() ;
+ return 0 ;
+}
diff --git a/src/libs6/s6_supervise_lock.c b/src/libs6/s6_supervise_lock.c
new file mode 100644
index 0000000..5c9ca30
--- /dev/null
+++ b/src/libs6/s6_supervise_lock.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <s6/s6-supervise.h>
+
+int s6_supervise_lock (char const *subdir)
+{
+ return s6_supervise_lock_mode(subdir, S_IRWXU, S_IRUSR | S_IWUSR) ;
+}
diff --git a/src/libs6/s6_supervise_lock_mode.c b/src/libs6/s6_supervise_lock_mode.c
new file mode 100644
index 0000000..ff3e11e
--- /dev/null
+++ b/src/libs6/s6_supervise_lock_mode.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <s6/s6-supervise.h>
+
+int s6_supervise_lock_mode (char const *subdir, unsigned int subdirmode, unsigned int controlmode)
+{
+ unsigned int subdirlen = str_len(subdir) ;
+ int fdctl, fdctlw, fdlock ;
+ char control[subdirlen + 9] ;
+ char lock[subdirlen + 6] ;
+ byte_copy(control, subdirlen, subdir) ;
+ byte_copy(control + subdirlen, 9, "/control") ;
+ byte_copy(lock, subdirlen, subdir) ;
+ byte_copy(lock + subdirlen, 6, "/lock") ;
+ if ((mkdir(subdir, (mode_t)subdirmode) == -1) && (errno != EEXIST))
+ strerr_diefu2sys(111, "mkdir ", subdir) ;
+ if (mkfifo(control, controlmode) < 0)
+ {
+ struct stat st ;
+ if (errno != EEXIST)
+ strerr_diefu2sys(111, "mkfifo ", control) ;
+ if (stat(control, &st) < 0)
+ strerr_diefu2sys(111, "stat ", control) ;
+ if (!S_ISFIFO(st.st_mode))
+ strerr_diefu2x(100, control, " is not a FIFO") ;
+ }
+ fdlock = open_create(lock) ;
+ if (fdlock < 0)
+ strerr_diefu2sys(111, "open_create ", lock) ;
+ if (lock_ex(fdlock) < 0)
+ strerr_diefu2sys(111, "lock ", lock) ;
+ fdctlw = open_write(control) ;
+ if (fdctlw >= 0) strerr_dief1x(100, "directory already locked") ;
+ if (errno != ENXIO)
+ strerr_diefu2sys(111, "open_write ", control) ;
+ fdctl = open_read(control) ;
+ if (fdctl < 0)
+ strerr_diefu2sys(111, "open_read ", control) ;
+ fdctlw = open_write(control) ;
+ if (fdctlw < 0)
+ strerr_diefu2sys(111, "open_write ", control) ;
+ fd_close(fdlock) ;
+ if ((coe(fdctlw) < 0) || (coe(fdctl) < 0))
+ strerr_diefu2sys(111, "coe ", control) ;
+
+ return fdctl ;
+ /* fdctlw is leaking. That's okay, it's coe. */
+}
diff --git a/src/libs6/s6_svc_main.c b/src/libs6/s6_svc_main.c
new file mode 100644
index 0000000..5d14904
--- /dev/null
+++ b/src/libs6/s6_svc_main.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/skamisc.h>
+#include <s6/s6-supervise.h>
+
+#define DATASIZE 256
+
+int s6_svc_main (int argc, char const *const *argv, char const *optstring, char const *usage, char const *controldir)
+{
+ char data[DATASIZE] ;
+ unsigned int datalen = 0 ;
+ register int r ;
+ for (;;)
+ {
+ register int opt = subgetopt(argc, argv, optstring) ;
+ if (opt == -1) break ;
+ if (opt == '?') strerr_dieusage(100, usage) ;
+ if (datalen >= DATASIZE) strerr_dief1x(100, "too many commands") ;
+ data[datalen++] = opt ;
+ }
+ argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ;
+ if (!argc) strerr_dieusage(100, usage) ;
+
+ {
+ unsigned int arglen = str_len(*argv) ;
+ unsigned int cdirlen = str_len(controldir) ;
+ char tmp[arglen + cdirlen + 10] ;
+ byte_copy(tmp, arglen, *argv) ;
+ tmp[arglen] = '/' ;
+ byte_copy(tmp + arglen + 1, cdirlen, controldir) ;
+ byte_copy(tmp + arglen + 1 + cdirlen, 9, "/control") ;
+ r = s6_svc_write(tmp, data, datalen) ;
+ }
+ if (r < 0) strerr_diefu2sys(111, "control ", *argv) ;
+ else if (!r) strerr_diefu3x(100, "control ", *argv, ": supervisor not listening") ;
+ return 0 ;
+}
diff --git a/src/libs6/s6_svc_write.c b/src/libs6/s6_svc_write.c
new file mode 100644
index 0000000..ea9eee5
--- /dev/null
+++ b/src/libs6/s6_svc_write.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+#include <s6/s6-supervise.h>
+
+int s6_svc_write (char const *fifo, char const *data, unsigned int datalen)
+{
+ int fd = open_write(fifo) ;
+ if (fd < 0) return (errno == ENXIO) ? 0 : -1 ;
+ else if (ndelay_off(fd) == -1) return -1 ;
+ else if (fd_write(fd, data, datalen) == -1)
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+ fd_close(fd) ;
+ return 1 ;
+}
diff --git a/src/libs6/s6_svstatus_pack.c b/src/libs6/s6_svstatus_pack.c
new file mode 100644
index 0000000..2d5baf6
--- /dev/null
+++ b/src/libs6/s6_svstatus_pack.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <s6/s6-supervise.h>
+
+void s6_svstatus_pack (char *pack, s6_svstatus_t const *sv)
+{
+ tain_pack(pack, &sv->stamp) ;
+ uint32_pack(pack + 12, (uint32)sv->pid) ;
+ pack[16] = sv->flagpaused | (sv->flagfinishing << 1) ;
+ pack[17] = sv->flagwant ? sv->flagwantup ? 'u' : 'd' : 0 ;
+}
diff --git a/src/libs6/s6_svstatus_read.c b/src/libs6/s6_svstatus_read.c
new file mode 100644
index 0000000..32ec660
--- /dev/null
+++ b/src/libs6/s6_svstatus_read.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <s6/s6-supervise.h>
+
+int s6_svstatus_read (char const *dir, s6_svstatus_t_ref status)
+{
+ unsigned int n = str_len(dir) ;
+ char pack[S6_SVSTATUS_SIZE] ;
+ char tmp[n + 2 + sizeof(S6_SVSTATUS_FILENAME)] ;
+ byte_copy(tmp, n, dir) ;
+ byte_copy(tmp + n, 2 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
+ if (openreadnclose(tmp, pack, S6_SVSTATUS_SIZE) < S6_SVSTATUS_SIZE) return 0 ;
+ s6_svstatus_unpack(pack, status) ;
+ return 1 ;
+}
diff --git a/src/libs6/s6_svstatus_unpack.c b/src/libs6/s6_svstatus_unpack.c
new file mode 100644
index 0000000..cce6989
--- /dev/null
+++ b/src/libs6/s6_svstatus_unpack.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <s6/s6-supervise.h>
+
+void s6_svstatus_unpack (char const *pack, s6_svstatus_t_ref sv)
+{
+ uint32 pid ;
+ tain_unpack(pack, &sv->stamp) ;
+ uint32_unpack(pack + 12, &pid) ;
+ sv->pid = (int)pid ;
+ sv->flagpaused = pack[16] & 1 ;
+ sv->flagfinishing = (pack[16] >> 1) & 1 ;
+ switch (pack[17])
+ {
+ case 'u' :
+ sv->flagwant = 1 ;
+ sv->flagwantup = 1 ;
+ break ;
+ case 'd' :
+ sv->flagwant = 1 ;
+ sv->flagwantup = 0 ;
+ break ;
+ default :
+ sv->flagwant = 0 ;
+ sv->flagwantup = 0 ;
+ }
+}
diff --git a/src/libs6/s6_svstatus_write.c b/src/libs6/s6_svstatus_write.c
new file mode 100644
index 0000000..2cc8a7b
--- /dev/null
+++ b/src/libs6/s6_svstatus_write.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <s6/s6-supervise.h>
+
+int s6_svstatus_write (char const *dir, s6_svstatus_t const *status)
+{
+ unsigned int n = str_len(dir) ;
+ char pack[S6_SVSTATUS_SIZE] ;
+ char tmp[n + 2 + sizeof(S6_SVSTATUS_FILENAME)] ;
+ byte_copy(tmp, n, dir) ;
+ byte_copy(tmp + n, 2 + sizeof(S6_SVSTATUS_FILENAME), "/" S6_SVSTATUS_FILENAME) ;
+ s6_svstatus_pack(pack, status) ;
+ return openwritenclose_suffix(tmp, pack, S6_SVSTATUS_SIZE, ".new") ;
+}
diff --git a/src/libs6/s6lock_acquire.c b/src/libs6/s6lock_acquire.c
new file mode 100644
index 0000000..b0fef54
--- /dev/null
+++ b/src/libs6/s6lock_acquire.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+int s6lock_acquire (s6lock_t *a, uint16 *u, char const *path, uint32 options, tain_t const *limit, tain_t const *deadline, tain_t *stamp)
+{
+ unsigned int pathlen = str_len(path) ;
+ char err ;
+ char tmp[23] = "--<" ;
+ siovec_t v[2] = { { .s = tmp, .len = 23 }, { .s = (char *)path, .len = pathlen + 1 } } ;
+ unsigned int i ;
+ if (!gensetdyn_new(&a->data, &i)) return 0 ;
+ uint16_pack_big(tmp, (uint16)i) ;
+ uint32_pack_big(tmp+3, options) ;
+ tain_pack(tmp+7, limit) ;
+ uint32_pack_big(tmp+19, (uint32)pathlen) ;
+ if (!skaclient_sendv(&a->connection, v, 2, &skaclient_default_cb, &err, deadline, stamp))
+ {
+ gensetdyn_delete(&a->data, i) ;
+ return 0 ;
+ }
+ if (err)
+ {
+ gensetdyn_delete(&a->data, i) ;
+ return (errno = err, 0) ;
+ }
+ *GENSETDYN_P(char, &a->data, i) = EAGAIN ;
+ *u = i ;
+ return 1 ;
+}
diff --git a/src/libs6/s6lock_check.c b/src/libs6/s6lock_check.c
new file mode 100644
index 0000000..e794128
--- /dev/null
+++ b/src/libs6/s6lock_check.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/gensetdyn.h>
+#include <s6/s6lock.h>
+
+int s6lock_check (s6lock_t *a, uint16 id)
+{
+ char *p = GENSETDYN_P(char, &a->data, id) ;
+ switch (*p)
+ {
+ case EBUSY : return 1 ;
+ case EINVAL : return (errno = EINVAL, -1) ;
+ default :
+ {
+ if (error_isagain(*p)) return 0 ;
+ errno = *p ;
+ *p = EINVAL ;
+ gensetdyn_delete(&a->data, id) ;
+ return -1 ;
+ }
+ }
+}
diff --git a/src/libs6/s6lock_end.c b/src/libs6/s6lock_end.c
new file mode 100644
index 0000000..c460efd
--- /dev/null
+++ b/src/libs6/s6lock_end.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+void s6lock_end (s6lock_t *a)
+{
+ gensetdyn_free(&a->data) ;
+ genalloc_free(uint16, &a->list) ;
+ skaclient_end(&a->connection) ;
+ *a = s6lock_zero ;
+}
diff --git a/src/libs6/s6lock_release.c b/src/libs6/s6lock_release.c
new file mode 100644
index 0000000..95e863f
--- /dev/null
+++ b/src/libs6/s6lock_release.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+int s6lock_release (s6lock_t *a, uint16 i, tain_t const *deadline, tain_t *stamp)
+{
+ char *p = GENSETDYN_P(char, &a->data, i) ;
+ if ((*p != EBUSY) && !error_isagain(*p))
+ {
+ s6lock_check(a, i) ;
+ return 1 ;
+ }
+ {
+ char err ;
+ char pack[3] = "-->" ;
+ uint16_pack_big(pack, i) ;
+ if (!skaclient_send(&a->connection, pack, 3, &skaclient_default_cb, &err, deadline, stamp)) return 0 ;
+ if (err) return (errno = err, 0) ;
+ }
+ *p = EINVAL ;
+ return gensetdyn_delete(&a->data, i) ;
+}
diff --git a/src/libs6/s6lock_start.c b/src/libs6/s6lock_start.c
new file mode 100644
index 0000000..e7993d9
--- /dev/null
+++ b/src/libs6/s6lock_start.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/environ.h>
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+int s6lock_start (s6lock_t *a, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+ return skaclient_start_b(&a->connection, &a->buffers, path, S6LOCK_BANNER1, S6LOCK_BANNER1_LEN, S6LOCK_BANNER2, S6LOCK_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/libs6/s6lock_startf.c b/src/libs6/s6lock_startf.c
new file mode 100644
index 0000000..c34a595
--- /dev/null
+++ b/src/libs6/s6lock_startf.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/environ.h>
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+int s6lock_startf (s6lock_t *a, char const *lockdir, tain_t const *deadline, tain_t *stamp)
+{
+ char const *cargv[3] = { S6LOCKD_PROG, lockdir, 0 } ;
+ if (!lockdir) return (errno = EINVAL, 0) ;
+ return skaclient_startf_b(&a->connection, &a->buffers, cargv[0], cargv, (char const *const *)environ, SKACLIENT_OPTION_WAITPID, S6LOCK_BANNER1, S6LOCK_BANNER1_LEN, S6LOCK_BANNER2, S6LOCK_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/libs6/s6lock_update.c b/src/libs6/s6lock_update.c
new file mode 100644
index 0000000..6e6a2a0
--- /dev/null
+++ b/src/libs6/s6lock_update.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+static int msghandler (unixmessage_t const *m, void *context)
+{
+ s6lock_t *a = (s6lock_t *)context ;
+ char *p ;
+ uint16 id ;
+ if (m->len != 3 || m->nfds) return (errno = EPROTO, 0) ;
+ uint16_unpack_big(m->s, &id) ;
+ p = GENSETDYN_P(char, &a->data, id) ;
+ if (*p == EBUSY) *p = m->s[2] ;
+ else if (error_isagain(*p)) *p = m->s[2] ? m->s[2] : EBUSY ;
+ else return (errno = EPROTO, 0) ;
+ if (!genalloc_append(uint16, &a->list, &id)) return 0 ;
+ return 1 ;
+}
+
+int s6lock_update (s6lock_t *a)
+{
+ genalloc_setlen(uint16, &a->list, 0) ;
+ return skaclient_update(&a->connection, &msghandler, a) ;
+}
diff --git a/src/libs6/s6lock_wait_and.c b/src/libs6/s6lock_wait_and.c
new file mode 100644
index 0000000..460cc07
--- /dev/null
+++ b/src/libs6/s6lock_wait_and.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <s6/s6lock.h>
+
+int s6lock_wait_and (s6lock_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { -1, IOPAUSE_READ, 0 } ;
+ x.fd = s6lock_fd(a) ;
+ for (; n ; n--, idlist++)
+ {
+ for (;;)
+ {
+ register int r = s6lock_check(a, *idlist) ;
+ if (r < 0) return r ;
+ else if (r) break ;
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return r ;
+ else if (!r) return (errno = ETIMEDOUT, -1) ;
+ else if (s6lock_update(a) < 0) return -1 ;
+ }
+ }
+ return 0 ;
+}
diff --git a/src/libs6/s6lock_wait_or.c b/src/libs6/s6lock_wait_or.c
new file mode 100644
index 0000000..0219574
--- /dev/null
+++ b/src/libs6/s6lock_wait_or.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <s6/s6lock.h>
+
+int s6lock_wait_or (s6lock_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { -1, IOPAUSE_READ | IOPAUSE_EXCEPT, 0 } ;
+ x.fd = s6lock_fd(a) ;
+ if (x.fd < 0) return -1 ;
+ for (;;)
+ {
+ register unsigned int i = 0 ;
+ register int r ;
+ for (; i < n ; i++)
+ {
+ r = s6lock_check(a, idlist[i]) ;
+ if (r < 0) return r ;
+ else if (r) return i ;
+ }
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ else if (!r) return (errno = ETIMEDOUT, -1) ;
+ else if (s6lock_update(a) < 0) return -1 ;
+ }
+ return (errno = EPROTO, -1) ; /* can't happen */
+}
diff --git a/src/libs6/s6lock_zero.c b/src/libs6/s6lock_zero.c
new file mode 100644
index 0000000..a4e0138
--- /dev/null
+++ b/src/libs6/s6lock_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <s6/s6lock.h>
+
+s6lock_t const s6lock_zero = S6LOCK_ZERO ;
diff --git a/src/libs6/s6lockd-helper.c b/src/libs6/s6lockd-helper.c
new file mode 100644
index 0000000..8979c67
--- /dev/null
+++ b/src/libs6/s6lockd-helper.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+
+#define USAGE "s6lockd-helper lockfile"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ int fd ;
+ char const *x = env_get2(envp, "S6LOCK_EX") ;
+ char c ;
+ PROG = "s6lockd-helper" ;
+ if (argc < 2) dieusage() ;
+ fd = open_create(argv[1]) ;
+ if (fd < 0) strerr_diefu2sys(111, "open ", argv[1]) ;
+ if (((x && *x) ? lock_ex(fd) : lock_sh(fd)) < 0)
+ strerr_diefu2sys(111, "lock ", argv[1]) ;
+ if (fd_write(1, "!", 1) <= 0)
+ strerr_diefu1sys(111, "write to stdout") ;
+ if (fd_read(0, &c, 1) < 0)
+ strerr_diefu1sys(111, "read from stdin") ;
+ return 0 ;
+}
diff --git a/src/libs6/s6lockd.c b/src/libs6/s6lockd.c
new file mode 100644
index 0000000..ef088f9
--- /dev/null
+++ b/src/libs6/s6lockd.c
@@ -0,0 +1,316 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/sig.h>
+#include <skalibs/selfpipe.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/iopause.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include <s6/s6lock.h>
+
+#define USAGE "s6lockd lockdir"
+#define X() strerr_dief1x(101, "internal inconsistency, please submit a bug-report.")
+
+typedef struct s6lockio_s s6lockio_t, *s6lockio_t_ref ;
+struct s6lockio_s
+{
+ unsigned int xindex ;
+ unsigned int pid ;
+ tain_t limit ;
+ int p[2] ;
+ uint16 id ; /* given by client */
+} ;
+#define S6LOCKIO_ZERO { 0, 0, TAIN_ZERO, { -1, -1 }, 0 }
+static s6lockio_t const szero = S6LOCKIO_ZERO ;
+
+static genalloc a = GENALLOC_ZERO ; /* array of s6lockio_t */
+
+static void s6lockio_free (s6lockio_t_ref p)
+{
+ register int e = errno ;
+ fd_close(p->p[1]) ;
+ fd_close(p->p[0]) ;
+ kill(p->pid, SIGTERM) ;
+ *p = szero ;
+ errno = e ;
+}
+
+static void cleanup (void)
+{
+ register unsigned int i = genalloc_len(s6lockio_t, &a) ;
+ for (; i ; i--) s6lockio_free(genalloc_s(s6lockio_t, &a) + i - 1) ;
+ genalloc_setlen(s6lockio_t, &a, 0) ;
+}
+
+static void trig (uint16 id, char e)
+{
+ char pack[3] ;
+ unixmessage_t m = { .s = pack, .len = 3, .fds = 0, .nfds = 0 } ;
+ uint16_pack_big(pack, id) ;
+ pack[2] = e ;
+ if (!unixmessage_put(unixmessage_sender_x, &m))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "build answer") ;
+ }
+}
+
+static void answer (char c)
+{
+ unixmessage_t m = { .s = &c, .len = 1, .fds = 0, .nfds = 0 } ;
+ if (!unixmessage_put(unixmessage_sender_1, &m))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "unixmessage_put") ;
+ }
+}
+
+static void remove (unsigned int i)
+{
+ register unsigned int n = genalloc_len(s6lockio_t, &a) - 1 ;
+ s6lockio_free(genalloc_s(s6lockio_t, &a) + i) ;
+ genalloc_s(s6lockio_t, &a)[i] = genalloc_s(s6lockio_t, &a)[n] ;
+ genalloc_setlen(s6lockio_t, &a, n) ;
+}
+
+static void handle_signals (void)
+{
+ for (;;)
+ {
+ switch (selfpipe_read())
+ {
+ case -1 : cleanup() ; strerr_diefu1sys(111, "selfpipe_read") ;
+ case 0 : return ;
+ case SIGTERM :
+ case SIGQUIT :
+ case SIGHUP :
+ case SIGABRT :
+ case SIGINT : cleanup() ; _exit(0) ;
+ case SIGCHLD : wait_reap() ; break ;
+ default : cleanup() ; X() ;
+ }
+ }
+}
+
+static int parse_protocol (unixmessage_t const *m, void *context)
+{
+ uint16 id ;
+ if (m->len < 3 || m->nfds)
+ {
+ cleanup() ;
+ strerr_dief1x(100, "invalid client request") ;
+ }
+ uint16_unpack_big(m->s, &id) ;
+ switch (m->s[2])
+ {
+ case '>' : /* release */
+ {
+ register unsigned int i = genalloc_len(s6lockio_t, &a) ;
+ for (; i ; i--) if (genalloc_s(s6lockio_t, &a)[i-1].id == id) break ;
+ if (i)
+ {
+ remove(i-1) ;
+ answer(0) ;
+ }
+ else answer(ENOENT) ;
+ break ;
+ }
+ case '<' : /* lock path */
+ {
+ s6lockio_t f = S6LOCKIO_ZERO ;
+ char const *cargv[3] = { S6LOCKD_HELPER_PROG, 0, 0 } ;
+ char const *cenvp[2] = { 0, 0 } ;
+ uint32 options, pathlen ;
+ if (m->len < 23)
+ {
+ answer(EPROTO) ;
+ break ;
+ }
+ uint32_unpack_big(m->s + 3, &options) ;
+ tain_unpack(m->s + 7, &f.limit) ;
+ uint32_unpack_big(m->s + 19, &pathlen) ;
+ if (pathlen + 23 != m->len || m->s[m->len - 1])
+ {
+ answer(EPROTO) ;
+ break ;
+ }
+ f.id = id ;
+ m->s[21] = '.' ;
+ m->s[22] = '/' ;
+ cargv[1] = (char const *)m->s + 21 ;
+ if (options & S6LOCK_OPTIONS_EX) cenvp[0] = "S6LOCK_EX=1" ;
+ f.pid = child_spawn(cargv[0], cargv, cenvp, f.p, 2) ;
+ if (!f.pid)
+ {
+ answer(errno) ;
+ break ;
+ }
+ if (!genalloc_append(s6lockio_t, &a, &f))
+ {
+ s6lockio_free(&f) ;
+ answer(errno) ;
+ break ;
+ }
+ answer(0) ;
+ break ;
+ }
+ default :
+ {
+ cleanup() ;
+ strerr_dief1x(100, "invalid client request") ;
+ }
+ }
+ (void)context ;
+ return 1 ;
+}
+
+int main (int argc, char const *const *argv)
+{
+ tain_t deadline ;
+ int sfd ;
+ PROG = "s6lockd" ;
+
+ if (argc < 2) strerr_dieusage(100, USAGE) ;
+ if (chdir(argv[1]) < 0) strerr_diefu2sys(111, "chdir to ", argv[1]) ;
+ if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ;
+ if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ;
+ if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;
+
+ sfd = selfpipe_init() ;
+ if (sfd < 0) strerr_diefu1sys(111, "selfpipe_init") ;
+ {
+ sigset_t set ;
+ sigemptyset(&set) ;
+ sigaddset(&set, SIGCHLD) ;
+ sigaddset(&set, SIGTERM) ;
+ sigaddset(&set, SIGQUIT) ;
+ sigaddset(&set, SIGHUP) ;
+ sigaddset(&set, SIGABRT) ;
+ sigaddset(&set, SIGINT) ;
+ if (selfpipe_trapset(&set) < 0)
+ strerr_diefu1sys(111, "trap signals") ;
+ }
+
+ tain_now_g() ;
+ tain_addsec_g(&deadline, 2) ;
+
+ if (!skaclient_server_01x_init_g(S6LOCK_BANNER1, S6LOCK_BANNER1_LEN, S6LOCK_BANNER2, S6LOCK_BANNER2_LEN, &deadline))
+ strerr_diefu1sys(111, "sync with client") ;
+
+ for (;;)
+ {
+ register unsigned int n = genalloc_len(s6lockio_t, &a) ;
+ iopause_fd x[4 + n] ;
+ unsigned int i = 0 ;
+ int r ;
+
+ tain_add_g(&deadline, &tain_infinite_relative) ;
+ x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ;
+ x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_1) ? 0 : IOPAUSE_WRITE ) ;
+ x[2].fd = unixmessage_sender_fd(unixmessage_sender_x) ;
+ x[2].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_x) ? 0 : IOPAUSE_WRITE) ;
+ x[3].fd = sfd ; x[3].events = IOPAUSE_READ ;
+ for (; i < n ; i++)
+ {
+ register s6lockio_t_ref p = genalloc_s(s6lockio_t, &a) + i ;
+ x[4+i].fd = p->p[0] ;
+ x[4+i].events = IOPAUSE_READ ;
+ if (p->limit.sec.x && tain_less(&p->limit, &deadline)) deadline = p->limit ;
+ p->xindex = 4+i ;
+ }
+
+ r = iopause_g(x, 4 + n, &deadline) ;
+ if (r < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "iopause") ;
+ }
+
+ /* timeout => seek and destroy */
+ if (!r)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ register s6lockio_t_ref p = genalloc_s(s6lockio_t, &a) + i ;
+ if (p->limit.sec.x && !tain_future(&p->limit)) break ;
+ }
+ if (i < n)
+ {
+ trig(genalloc_s(s6lockio_t, &a)[i].id, ETIMEDOUT) ;
+ remove(i) ;
+ }
+ continue ;
+ }
+
+ /* client closed */
+ if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) break ;
+
+ /* client is reading */
+ if (x[1].revents & IOPAUSE_WRITE)
+ if ((unixmessage_sender_flush(unixmessage_sender_1) < 0) && !error_isagain(errno))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "flush stdout") ;
+ }
+ if (x[2].revents & IOPAUSE_WRITE)
+ if ((unixmessage_sender_flush(unixmessage_sender_x) < 0) && !error_isagain(errno))
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "flush asyncout") ;
+ }
+
+ /* scan children for successes */
+ for (i = 0 ; i < genalloc_len(s6lockio_t, &a) ; i++)
+ {
+ register s6lockio_t_ref p = genalloc_s(s6lockio_t, &a) + i ;
+ if (p->p[0] < 0) continue ;
+ if (x[p->xindex].revents & IOPAUSE_READ)
+ {
+ char c ;
+ register int r = sanitize_read(fd_read(p->p[0], &c, 1)) ;
+ if (!r) continue ;
+ if (r < 0)
+ {
+ trig(p->id, errno) ;
+ remove(i--) ;
+ }
+ else if (c != '!')
+ {
+ trig(p->id, EPROTO) ;
+ remove(i--) ;
+ }
+ else
+ {
+ trig(p->id, 0) ;
+ p->limit = tain_zero ;
+ }
+ }
+ }
+
+ /* signals arrived */
+ if (x[3].revents & (IOPAUSE_READ | IOPAUSE_EXCEPT)) handle_signals() ;
+
+ /* client is writing */
+ if (!unixmessage_receiver_isempty(unixmessage_receiver_0) || x[0].revents & IOPAUSE_READ)
+ {
+ if (unixmessage_handle(unixmessage_receiver_0, &parse_protocol, 0) < 0)
+ {
+ if (errno == EPIPE) break ; /* normal exit */
+ cleanup() ;
+ strerr_diefu1sys(111, "handle messages from client") ;
+ }
+ }
+ }
+ cleanup() ;
+ return 0 ;
+}