diff options
Diffstat (limited to 'src/libs6')
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 ; +} |