diff options
Diffstat (limited to 'src/libs6/s6lockd.c')
-rw-r--r-- | src/libs6/s6lockd.c | 318 |
1 files changed, 0 insertions, 318 deletions
diff --git a/src/libs6/s6lockd.c b/src/libs6/s6lockd.c deleted file mode 100644 index 8cc767a..0000000 --- a/src/libs6/s6lockd.c +++ /dev/null @@ -1,318 +0,0 @@ -/* ISC license. */ - -#include <sys/uio.h> -#include <stdint.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> - -#include <skalibs/posixishard.h> -#include <skalibs/types.h> -#include <skalibs/allreadwrite.h> -#include <skalibs/error.h> -#include <skalibs/strerr.h> -#include <skalibs/genalloc.h> -#include <skalibs/sig.h> -#include <skalibs/selfpipe.h> -#include <skalibs/tai.h> -#include <skalibs/cspawn.h> -#include <skalibs/djbunix.h> -#include <skalibs/iopause.h> -#include <skalibs/textmessage.h> -#include <skalibs/textclient.h> - -#include <s6/lock.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 limit ; - int p[2] ; - uint16_t 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 *p) -{ - 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) -{ - size_t 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_t id, unsigned char e) -{ - char pack[3] ; - uint16_pack_big(pack, id) ; - pack[2] = e ; - if (!textmessage_put(textmessage_sender_x, pack, 3)) - { - cleanup() ; - strerr_diefu1sys(111, "build answer") ; - } -} - -static void answer (unsigned char c) -{ - if (!textmessage_put(textmessage_sender_1, (char *)&c, 1)) - { - cleanup() ; - strerr_diefu1sys(111, "textmessage_put") ; - } -} - -static void remove (unsigned int i) -{ - size_t 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 (struct iovec const *v, void *context) -{ - char *s = v->iov_base ; - uint16_t id ; - if (v->iov_len < 3) - { - cleanup() ; - strerr_dief1x(100, "invalid client request") ; - } - uint16_unpack_big(s, &id) ; - switch (s[2]) - { - case '>' : /* release */ - { - size_t 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[4] = { S6LOCKD_HELPER_PROG, "r", 0, 0 } ; - char const *nullenv = 0 ; - uint32_t options, pathlen ; - if (v->iov_len < 23) - { - answer(EPROTO) ; - break ; - } - uint32_unpack_big(s + 3, &options) ; - tain_unpack(s + 7, &f.limit) ; - uint32_unpack_big(s + 19, &pathlen) ; - if (pathlen + 23 != v->iov_len || s[v->iov_len - 1]) - { - answer(EPROTO) ; - break ; - } - f.id = id ; - s[21] = '.' ; - s[22] = '/' ; - if (options & S6LOCK_OPTIONS_EX) cargv[1] = "w" ; - cargv[2] = (char const *)s + 21 ; - f.pid = child_spawn2(cargv[0], cargv, &nullenv, f.p) ; - 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 deadline ; - 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_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ; - - if (selfpipe_init() == -1) 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)) - strerr_diefu1sys(111, "trap signals") ; - } - - tain_now_set_stopwatch_g() ; - tain_addsec_g(&deadline, 2) ; - - if (!textclient_server_01x_init_g(S6LOCK_BANNER1, S6LOCK_BANNER1_LEN, S6LOCK_BANNER2, S6LOCK_BANNER2_LEN, &deadline)) - strerr_diefu1sys(111, "sync with client") ; - - for (;;) - { - size_t 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 | (textmessage_sender_isempty(textmessage_sender_1) ? 0 : IOPAUSE_WRITE ) ; - x[2].fd = textmessage_sender_fd(textmessage_sender_x) ; - x[2].events = IOPAUSE_EXCEPT | (textmessage_sender_isempty(textmessage_sender_x) ? 0 : IOPAUSE_WRITE) ; - x[3].fd = selfpipe_fd() ; x[3].events = IOPAUSE_READ ; - for (; i < n ; i++) - { - s6lockio_t *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++) - { - s6lockio_t *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 (!textmessage_sender_flush(textmessage_sender_1) && !error_isagain(errno)) - { - cleanup() ; - strerr_diefu1sys(111, "flush stdout") ; - } - if (x[2].revents & IOPAUSE_WRITE) - if (!textmessage_sender_flush(textmessage_sender_x) && !error_isagain(errno)) - { - cleanup() ; - strerr_diefu1sys(111, "flush asyncout") ; - } - - /* scan children for successes */ - for (i = 0 ; i < genalloc_len(s6lockio_t, &a) ; i++) - { - s6lockio_t *p = genalloc_s(s6lockio_t, &a) + i ; - if (p->p[0] < 0) continue ; - if (x[p->xindex].revents & IOPAUSE_READ) - { - char c ; - ssize_t 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 (!textmessage_receiver_isempty(textmessage_receiver_0) || x[0].revents & IOPAUSE_READ) - { - if (textmessage_handle(textmessage_receiver_0, &parse_protocol, 0) < 0) - { - if (errno == EPIPE) break ; /* normal exit */ - cleanup() ; - strerr_diefu1sys(111, "handle messages from client") ; - } - } - } - cleanup() ; - return 0 ; -} |