diff options
Diffstat (limited to 'src/libs6rc')
-rw-r--r-- | src/libs6rc/deps-lib/s6rc | 6 | ||||
-rw-r--r-- | src/libs6rc/s6rc-servicedir-internal.h | 32 | ||||
-rw-r--r-- | src/libs6rc/s6rc_read_uint.c | 16 | ||||
-rw-r--r-- | src/libs6rc/s6rc_servicedir_block.c | 27 | ||||
-rw-r--r-- | src/libs6rc/s6rc_servicedir_copy_offline.c | 18 | ||||
-rw-r--r-- | src/libs6rc/s6rc_servicedir_copy_online.c | 74 | ||||
-rw-r--r-- | src/libs6rc/s6rc_servicedir_internal.c | 83 | ||||
-rw-r--r-- | src/libs6rc/s6rc_servicedir_unblock.c | 21 |
8 files changed, 277 insertions, 0 deletions
diff --git a/src/libs6rc/deps-lib/s6rc b/src/libs6rc/deps-lib/s6rc index 194ea43..e415f45 100644 --- a/src/libs6rc/deps-lib/s6rc +++ b/src/libs6rc/deps-lib/s6rc @@ -5,4 +5,10 @@ s6rc_db_read.o s6rc_db_read_sizes.o s6rc_db_read_uint32.o s6rc_graph_closure.o +s6rc_read_uint.o +s6rc_servicedir_internal.o +s6rc_servicedir_block.o +s6rc_servicedir_unblock.o +s6rc_servicedir_copy_offline.o +s6rc_servicedir_copy_online.o -lskarnet diff --git a/src/libs6rc/s6rc-servicedir-internal.h b/src/libs6rc/s6rc-servicedir-internal.h new file mode 100644 index 0000000..fe05a40 --- /dev/null +++ b/src/libs6rc/s6rc-servicedir-internal.h @@ -0,0 +1,32 @@ +/* ISC license. */ + +#ifndef S6RC_SERVICEDIR_INTERNAL_H +#define S6RC_SERVICEDIR_INTERNAL_H + +typedef enum s6rc_filetype_e s6rc_filetype_t, *s6rc_filetype_t_ref ; +enum s6rc_filetype_e +{ + FILETYPE_NORMAL, + FILETYPE_EMPTY, + FILETYPE_UINT, + FILETYPE_DIR +} ; + +#define SVFILE_EXECUTABLE 0x01 +#define SVFILE_MANDATORY 0x02 +#define SVFILE_ATOMIC 0x04 + +typedef struct s6rc_servicedir_desc_s s6rc_servicedir_desc_t, *s6rc_servicedir_desc_t_ref ; +struct s6rc_servicedir_desc_s +{ + char const *name ; + s6rc_filetype_t type ; + unsigned char options ; +} ; + +extern s6rc_servicedir_desc_t const *s6rc_servicedir_file_list ; +extern unsigned int const s6rc_servicedir_file_maxlen ; + +extern int s6rc_servicedir_copy_one (char const *, char const *, s6rc_servicedir_desc_t const *) ; + +#endif diff --git a/src/libs6rc/s6rc_read_uint.c b/src/libs6rc/s6rc_read_uint.c new file mode 100644 index 0000000..6953190 --- /dev/null +++ b/src/libs6rc/s6rc_read_uint.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/djbunix.h> + +int s6rc_read_uint (char const *file, unsigned int *u) +{ + char buf[UINT_FMT + 1] ; + register int r = openreadnclose(file, buf, UINT_FMT) ; + if (r < 0) return (errno == ENOENT) ? 0 : -1 ; + buf[byte_chr(buf, r, '\n')] = 0 ; + if (!uint0_scan(buf, u)) return (errno = EINVAL, -1) ; + return 1 ; +} diff --git a/src/libs6rc/s6rc_servicedir_block.c b/src/libs6rc/s6rc_servicedir_block.c new file mode 100644 index 0000000..d01481b --- /dev/null +++ b/src/libs6rc/s6rc_servicedir_block.c @@ -0,0 +1,27 @@ +/* ISC license. */ + +#include <errno.h> +#include <unistd.h> +#include <skalibs/bytestr.h> +#include <skalibs/djbunix.h> +#include <s6/s6-supervise.h> +#include <s6-rc/s6rc-servicedir.h> + +int s6rc_servicedir_block (char const *dir) +{ + unsigned int dirlen = str_len(dir) ; + s6_svstatus_t status ; + char fn[dirlen + 6] ; + if (!s6_svstatus_read(dir, &status)) return -1 ; + byte_copy(fn, dirlen, dir) ; + byte_copy(fn + dirlen, 6, "/down") ; + if (!touch(fn)) return -1 ; + if (s6_svc_writectl(dir, S6_SUPERVISE_CTLDIR, "O", 1) < 0) + { + register int e = errno ; + unlink(fn) ; + errno = e ; + return -1 ; + } + return status.flagwantup ; +} diff --git a/src/libs6rc/s6rc_servicedir_copy_offline.c b/src/libs6rc/s6rc_servicedir_copy_offline.c new file mode 100644 index 0000000..6581a4f --- /dev/null +++ b/src/libs6rc/s6rc_servicedir_copy_offline.c @@ -0,0 +1,18 @@ +/* ISC license. */ + +#include <sys/stat.h> +#include <errno.h> +#include "s6rc-servicedir-internal.h" +#include <s6-rc/s6rc-servicedir.h> + +int s6rc_servicedir_copy_offline (char const *src, char const *dst) +{ + s6rc_servicedir_desc_t const *p = s6rc_servicedir_file_list ; + if (mkdir(dst, 0755) < 0) + { + if (errno != EEXIST) return 0 ; + } + for (; p->name ; p++) + if (!s6rc_servicedir_copy_one(src, dst, p)) return 0 ; + return 1 ; +} diff --git a/src/libs6rc/s6rc_servicedir_copy_online.c b/src/libs6rc/s6rc_servicedir_copy_online.c new file mode 100644 index 0000000..6e14844 --- /dev/null +++ b/src/libs6rc/s6rc_servicedir_copy_online.c @@ -0,0 +1,74 @@ +/* ISC license. */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <skalibs/bytestr.h> +#include <skalibs/djbunix.h> +#include <s6-rc/s6rc-utils.h> +#include "s6rc-servicedir-internal.h" +#include <s6-rc/s6rc-servicedir.h> + +int s6rc_servicedir_copy_online (char const *src, char const *dst) +{ + unsigned int srclen = str_len(src) ; + unsigned int dstlen = str_len(dst) ; + unsigned int n ; + unsigned int i = 0 ; + int wantup = 0 ; + int e ; + char srcfn[srclen + s6rc_servicedir_file_maxlen + 6] ; + char dstfn[dstlen + s6rc_servicedir_file_maxlen + 6] ; + char oldfn[dstlen + s6rc_servicedir_file_maxlen + 6] ; + byte_copy(srcfn, srclen, src) ; + srcfn[srclen] = '/' ; + byte_copy(dstfn, dstlen + 1, dst) ; + byte_copy(oldfn, dstlen, dst) ; + byte_copy(oldfn + dstlen, 5, "/old") ; + if (rm_rf(oldfn) < 0 && errno != ENOENT) return 0 ; + if (mkdir(oldfn, 0755) < 0) return 0 ; + dstfn[dstlen] = '/' ; + oldfn[dstlen + 4] = '/' ; + wantup = s6rc_servicedir_block(dst) ; + if (wantup < 0) { e = errno ; goto errdir ; } + + for (; s6rc_servicedir_file_list[i].name ; i++) + { + str_copy(dstfn + dstlen + 1, s6rc_servicedir_file_list[i].name) ; + str_copy(oldfn + dstlen + 5, s6rc_servicedir_file_list[i].name) ; + if (rename(dstfn, oldfn) < 0) { e = errno ; goto errrename ; } + } + n = i ; + while (i--) + { + if (!s6rc_servicedir_copy_one(src, dst, s6rc_servicedir_file_list + i)) + { + e = errno ; + goto errremove ; + } + } + oldfn[dstlen + 4] = 0 ; + rm_rf(oldfn) ; + s6rc_servicedir_unblock(dst, wantup) ; + return 1 ; + + errremove: + for (; i < n ; i++) + { + str_copy(dstfn + dstlen + 1, s6rc_servicedir_file_list[i].name) ; + rm_rf(dstfn) ; + } + i = n ; + errrename: + while (i--) + { + str_copy(dstfn + dstlen + 1, s6rc_servicedir_file_list[i].name) ; + str_copy(oldfn + dstlen + 5, s6rc_servicedir_file_list[i].name) ; + rename(oldfn, dstfn) ; + } + errdir: + oldfn[dstlen + 4] = 0 ; + rmdir(oldfn) ; + errno = e ; + return 0 ; +} diff --git a/src/libs6rc/s6rc_servicedir_internal.c b/src/libs6rc/s6rc_servicedir_internal.c new file mode 100644 index 0000000..7522313 --- /dev/null +++ b/src/libs6rc/s6rc_servicedir_internal.c @@ -0,0 +1,83 @@ +/* ISC license. */ + +#include <errno.h> +#include <unistd.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/djbunix.h> +#include <s6-rc/s6rc-utils.h> +#include "s6rc-servicedir-internal.h" + +static s6rc_servicedir_desc_t const svdir_file_list[] = +{ + { .name = "finish", .type = FILETYPE_NORMAL, .options = SVFILE_EXECUTABLE | SVFILE_ATOMIC }, + { .name = "finish.user", .type = FILETYPE_NORMAL, .options = SVFILE_EXECUTABLE }, + { .name = "run", .type = FILETYPE_NORMAL, .options = SVFILE_EXECUTABLE | SVFILE_MANDATORY | SVFILE_ATOMIC }, + { .name = "run.user", .type = FILETYPE_NORMAL, .options = SVFILE_EXECUTABLE }, + { .name = "nosetsid", .type = FILETYPE_EMPTY, .options = 0 }, + { .name = "notification-fd", .type = FILETYPE_UINT, .options = 0 }, + { .name = "timeout-finish", .type = FILETYPE_UINT, .options = 0 }, + { .name = "data", .type = FILETYPE_DIR, .options = 0 }, + { .name = "env", .type = FILETYPE_DIR, .options = 0 }, + { .name = 0, .options = 0 } +} ; + +s6rc_servicedir_desc_t const *s6rc_servicedir_file_list = svdir_file_list ; +unsigned int const s6rc_servicedir_file_maxlen = 15 ; + +int s6rc_servicedir_copy_one (char const *src, char const *dst, s6rc_servicedir_desc_t const *p) +{ + unsigned int srclen = str_len(src) ; + unsigned int dstlen = str_len(dst) ; + unsigned int plen = str_len(p->name) ; + char srcfn[srclen + plen + 2] ; + char dstfn[dstlen + plen + 2] ; + byte_copy(srcfn, srclen, src) ; + srcfn[srclen] = '/' ; + byte_copy(srcfn + srclen + 1, plen + 1, p->name) ; + byte_copy(dstfn, dstlen, dst) ; + dstfn[dstlen] = '/' ; + byte_copy(dstfn + dstlen + 1, plen + 1, p->name) ; + + switch (p->type) + { + case FILETYPE_NORMAL : + { + unsigned int mode = p->options & SVFILE_EXECUTABLE ? 0755 : 0644 ; + if (!(p->options & SVFILE_ATOMIC ? filecopy_suffix(srcfn, dstfn, mode, ".new") : filecopy_unsafe(srcfn, dstfn, mode))) + { + if (errno != ENOENT || p->options & SVFILE_MANDATORY) return 0 ; + } + break ; + } + case FILETYPE_EMPTY : + if (access(srcfn, F_OK) < 0) + { + if (errno != ENOENT || p->options & SVFILE_MANDATORY) return 0 ; + } + else if (!touch(dstfn)) return 0 ; + break ; + case FILETYPE_UINT : + { + unsigned int u ; + register int r = s6rc_read_uint(srcfn, &u) ; + if (r < 0 || (!r && p->options & SVFILE_MANDATORY)) return 0 ; + if (r) + { + char fmt[UINT_FMT] ; + r = uint_fmt(fmt, u) ; + fmt[r++] = '\n' ; + if (!openwritenclose_unsafe(dstfn, fmt, r)) return 0 ; + } + break ; + } + case FILETYPE_DIR : + if (!hiercopy(srcfn, dstfn)) + { + if (errno != ENOENT || p->options & SVFILE_MANDATORY) return 0 ; + } + break ; + default : return (errno = EDOM, 0) ; + } + return 1 ; +} diff --git a/src/libs6rc/s6rc_servicedir_unblock.c b/src/libs6rc/s6rc_servicedir_unblock.c new file mode 100644 index 0000000..6fd846c --- /dev/null +++ b/src/libs6rc/s6rc_servicedir_unblock.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <unistd.h> +#include <skalibs/bytestr.h> +#include <s6/s6-supervise.h> +#include <s6-rc/s6rc-servicedir.h> + +int s6rc_servicedir_unblock (char const *dir, int h) +{ + if (h) + { + unsigned int dirlen = str_len(dir) ; + char fn[dirlen + 6] ; + byte_copy(fn, dirlen, dir) ; + byte_copy(fn + dirlen, 6, "/down") ; + if (unlink(fn) < 0 && errno != ENOENT) return -1 ; + if (s6_svc_writectl(dir, S6_SUPERVISE_CTLDIR, "u", 1) < 0) return -1 ; + } + return 0 ; +} |