diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2015-08-12 20:00:17 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2015-08-12 20:00:17 +0000 |
commit | 9473830ad612dcb674f6048a9a17e372ff9d9ec3 (patch) | |
tree | 6cf045657b34be4b6fd685c68993b13bf7e55f26 /src | |
parent | abfd58b78188c3408599b98fcce611349bfa8b9c (diff) | |
download | s6-rc-9473830ad612dcb674f6048a9a17e372ff9d9ec3.tar.xz |
Intermediary commit; working on source dir format change. Should work, but untested as for now.
Diffstat (limited to 'src')
-rw-r--r-- | src/include/s6-rc/s6rc-constants.h | 3 | ||||
-rw-r--r-- | src/include/s6-rc/s6rc-db.h | 6 | ||||
-rw-r--r-- | src/libs6rc/deps-lib/s6rc | 4 | ||||
-rw-r--r-- | src/libs6rc/s6rc_db_check_depcycles.c | 26 | ||||
-rw-r--r-- | src/libs6rc/s6rc_db_check_revdeps.c | 5 | ||||
-rw-r--r-- | src/libs6rc/s6rc_db_read.c | 5 | ||||
-rw-r--r-- | src/s6-rc/s6-rc-compile.c | 660 | ||||
-rw-r--r-- | src/s6-rc/s6-rc-db.c | 58 | ||||
-rw-r--r-- | src/s6-rc/s6-rc-update.c | 101 | ||||
-rw-r--r-- | src/s6-rc/s6-rc.c | 8 |
10 files changed, 617 insertions, 259 deletions
diff --git a/src/include/s6-rc/s6rc-constants.h b/src/include/s6-rc/s6rc-constants.h index 92af2a9..87e7053 100644 --- a/src/include/s6-rc/s6rc-constants.h +++ b/src/include/s6-rc/s6rc-constants.h @@ -11,4 +11,7 @@ #define S6RC_ONESHOT_RUNNER "s6rc-oneshot-runner" #define S6RC_ONESHOT_RUNNER_LEN (sizeof S6RC_ONESHOT_RUNNER - 1) +#define S6RC_FDHOLDER "s6rc-fdholder" +#define S6RC_FDHOLDER_LEN (sizeof S6RC_FDHOLDER - 1) + #endif diff --git a/src/include/s6-rc/s6rc-db.h b/src/include/s6-rc/s6rc-db.h index bc516b2..0053af9 100644 --- a/src/include/s6-rc/s6rc-db.h +++ b/src/include/s6-rc/s6rc-db.h @@ -4,6 +4,7 @@ #define S6RC_DB_H #include <skalibs/uint32.h> +#include <skalibs/diuint32.h> #include <skalibs/buffer.h> #define S6RC_DB_BANNER_START "s6rc-db: start\n" @@ -22,7 +23,7 @@ struct s6rc_oneshot_s typedef struct s6rc_longrun_s s6rc_longrun_t, *s6rc_longrun_t_ref ; struct s6rc_longrun_s { - uint32 servicedir ; + uint32 pipeline[2] ; } ; typedef union s6rc_longshot_u s6rc_longshot_t, *s6rc_longshot_t_ref ; @@ -62,7 +63,8 @@ extern int s6rc_db_read_uint32 (buffer *, uint32 *) ; extern int s6rc_db_read_sizes (int, s6rc_db_t *) ; extern int s6rc_db_read (int, s6rc_db_t *) ; -extern unsigned int s6rc_db_check_depcycles (s6rc_db_t const *, int, unsigned int *) ; +extern int s6rc_db_check_pipelines (s6rc_db_t const *, diuint32 *) ; +extern int s6rc_db_check_depcycles (s6rc_db_t const *, int, diuint32 *) ; extern int s6rc_db_check_revdeps (s6rc_db_t const *) ; #endif diff --git a/src/libs6rc/deps-lib/s6rc b/src/libs6rc/deps-lib/s6rc index 65b562e..194ea43 100644 --- a/src/libs6rc/deps-lib/s6rc +++ b/src/libs6rc/deps-lib/s6rc @@ -1,6 +1,8 @@ s6rc_db_check_depcycles.o +s6rc_db_check_pipelines.o +s6rc_db_check_revdeps.o s6rc_db_read.o s6rc_db_read_sizes.o s6rc_db_read_uint32.o -s6rc_db_check_revdeps.o s6rc_graph_closure.o +-lskarnet diff --git a/src/libs6rc/s6rc_db_check_depcycles.c b/src/libs6rc/s6rc_db_check_depcycles.c index 13dcf7b..db6ed6e 100644 --- a/src/libs6rc/s6rc_db_check_depcycles.c +++ b/src/libs6rc/s6rc_db_check_depcycles.c @@ -1,6 +1,7 @@ /* ISC license. */ #include <skalibs/uint32.h> +#include <skalibs/diuint32.h> #include <skalibs/bitarray.h> #include <skalibs/bytestr.h> #include <s6-rc/s6rc-db.h> @@ -9,22 +10,22 @@ typedef struct recinfo_s recinfo_t, *recinfo_t_ref ; struct recinfo_s { s6rc_db_t const *db ; - unsigned int n ; + uint32 n ; unsigned char *gray ; unsigned char *black ; unsigned char h : 1 ; } ; -static unsigned int s6rc_db_checknocycle_rec (recinfo_t *recinfo, unsigned int i) +static uint32 s6rc_db_checknocycle_rec (recinfo_t *recinfo, uint32 i) { if (!bitarray_peek(recinfo->black, i)) { - unsigned int j = recinfo->db->services[i].ndeps[recinfo->h] ; + uint32 j = recinfo->db->services[i].ndeps[recinfo->h] ; if (bitarray_peek(recinfo->gray, i)) return i ; bitarray_set(recinfo->gray, i) ; while (j--) { - register unsigned int r = s6rc_db_checknocycle_rec(recinfo, recinfo->db->deps[recinfo->h * recinfo->db->ndeps + recinfo->db->services[i].deps[recinfo->h] + j]) ; + register uint32 r = s6rc_db_checknocycle_rec(recinfo, recinfo->db->deps[recinfo->h * recinfo->db->ndeps + recinfo->db->services[i].deps[recinfo->h] + j]) ; if (r < recinfo->n) return r ; } bitarray_set(recinfo->black, i) ; @@ -32,19 +33,24 @@ static unsigned int s6rc_db_checknocycle_rec (recinfo_t *recinfo, unsigned int i return recinfo->n ; } -unsigned int s6rc_db_check_depcycles (s6rc_db_t const *db, int h, unsigned int *problem) +int s6rc_db_check_depcycles (s6rc_db_t const *db, int h, diuint32 *problem) { - unsigned int n = db->nshort + db->nlong ; + uint32 n = db->nshort + db->nlong ; + uint32 i = n ; unsigned char gray[bitarray_div8(n)] ; unsigned char black[bitarray_div8(n)] ; recinfo_t info = { .db = db, .n = n, .gray = gray, .black = black, .h = !!h } ; - unsigned int i = n ; byte_zero(gray, bitarray_div8(n)) ; byte_zero(black, bitarray_div8(n)) ; while (i--) { - register unsigned int r = s6rc_db_checknocycle_rec(&info, i) ; - if (r < n) return (*problem = r, i) ; + register uint32 r = s6rc_db_checknocycle_rec(&info, i) ; + if (r < n) + { + problem->left = i ; + problem->right = r ; + return 1 ; + } } - return n ; + return 0 ; } diff --git a/src/libs6rc/s6rc_db_check_revdeps.c b/src/libs6rc/s6rc_db_check_revdeps.c index 0cb2845..a4342b1 100644 --- a/src/libs6rc/s6rc_db_check_revdeps.c +++ b/src/libs6rc/s6rc_db_check_revdeps.c @@ -1,6 +1,5 @@ /* ISC license. */ -#include <skalibs/uint32.h> #include <skalibs/bytestr.h> #include <skalibs/bitarray.h> #include <s6-rc/s6rc-db.h> @@ -25,6 +24,6 @@ int s6rc_db_check_revdeps (s6rc_db_t const *db) while (j--) bitarray_not(matrix + m * db->deps[db->services[i].deps[0] + j], i, 1) ; } i = n * m ; - while (i--) if (*p++) return 0 ; - return 1 ; + while (i--) if (*p++) return 1 ; + return 0 ; } diff --git a/src/libs6rc/s6rc_db_read.c b/src/libs6rc/s6rc_db_read.c index 7a38797..50e1f78 100644 --- a/src/libs6rc/s6rc_db_read.c +++ b/src/libs6rc/s6rc_db_read.c @@ -90,9 +90,8 @@ static inline int s6rc_db_read_services (buffer *b, s6rc_db_t *db) #endif if (i < db->nlong) { - if (!s6rc_db_read_uint32(b, &sv->x.longrun.servicedir)) return -1 ; - DBG(" longrun - servicedir is %u: %s", sv->x.longrun.servicedir, db->string + sv->x.longrun.servicedir) ; - if (!s6rc_db_check_valid_string(db->string, db->stringlen, sv->x.longrun.servicedir)) return 0 ; + if (!s6rc_db_read_uint32(b, &sv->x.longrun.pipeline[0])) return -1 ; + if (!s6rc_db_read_uint32(b, &sv->x.longrun.pipeline[1])) return -1 ; } else { diff --git a/src/s6-rc/s6-rc-compile.c b/src/s6-rc/s6-rc-compile.c index 1126967..a1ffdee 100644 --- a/src/s6-rc/s6-rc-compile.c +++ b/src/s6-rc/s6-rc-compile.c @@ -27,10 +27,12 @@ #include <s6/config.h> #include <s6-rc/s6rc.h> -#define USAGE "s6-rc-compile [ -v verbosity ] [ -u okuid,okuid... ] [ -g okgid,okgid... ] destdir sources..." +#define USAGE "s6-rc-compile [ -v verbosity ] [ -u okuid,okuid... ] [ -g okgid,okgid... ] [ -h fdholder_user ] destdir sources..." #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_dief1x(111, "out of memory") ; +#define S6RC_INTERNALS "s6-rc-compile internals" + #define S6RC_ONESHOT_RUNNER_RUNSCRIPT \ "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n" \ EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n" \ @@ -40,8 +42,6 @@ S6_EXTBINPREFIX "s6-ipcserverd -1 --\n" \ S6_EXTBINPREFIX "s6-ipcserver-access -v0 -E -l0 -i data/rules --\n" \ S6_EXTBINPREFIX "s6-sudod -t 2000 --\n" -#define BASE_RULES "servicedirs/" S6RC_ONESHOT_RUNNER "/data/rules/gid" - static unsigned int verbosity = 1 ; static stralloc keep = STRALLOC_ZERO ; static stralloc data = STRALLOC_ZERO ; @@ -91,7 +91,6 @@ static avltree names_map = AVLTREE_INIT(8, 3, 8, &names_dtok, &names_cmp, &namei typedef struct common_s common_t, *common_t_ref ; struct common_s { - unsigned int name ; /* pos in data */ unsigned int kname ; /* pos in keep */ unsigned int ndeps ; unsigned int depindex ; /* pos in indices */ @@ -103,7 +102,7 @@ typedef struct oneshot_s oneshot_t, *oneshot_t_ref ; struct oneshot_s { common_t common ; - unsigned int argvindex[2] ; /* pos in data */ + unsigned int argvindex[2] ; /* pos in keep */ unsigned int argc[2] ; } ; @@ -112,9 +111,8 @@ struct longrun_s { common_t common ; char const *srcdir ; - unsigned int servicedirname ; - unsigned int logrelated ; - unsigned char logtype ; + unsigned int pipeline[2] ; /* pos in data */ + unsigned int pipelinename ; /* pos in data */ } ; typedef struct bundle_s bundle_t, *bundle_t_ref ; @@ -128,19 +126,19 @@ struct bundle_s typedef struct before_s before_t, *before_t_ref ; struct before_s { - genalloc indices ; /* uint32 */ + genalloc indices ; /* unsigned int */ genalloc oneshots ; /* oneshot_t */ genalloc longruns ; /* longrun_t */ genalloc bundles ; /* bundle_t */ unsigned int nargvs ; - unsigned int maxnamelen ; + uint32 specialdeps[2] ; } ; -#define BEFORE_ZERO { .indices = GENALLOC_ZERO, .oneshots = GENALLOC_ZERO, .longruns = GENALLOC_ZERO, .bundles = GENALLOC_ZERO, .nargvs = 0 } ; +#define BEFORE_ZERO { .indices = GENALLOC_ZERO, .oneshots = GENALLOC_ZERO, .longruns = GENALLOC_ZERO, .bundles = GENALLOC_ZERO, .nargvs = 0, .specialdeps = { 0, 0 } } ; - /* Read all the sources, populate the map and string data */ + /* Read all the sources, populate the name map */ static char const *typestr (servicetype_t type) @@ -151,7 +149,7 @@ static char const *typestr (servicetype_t type) "unknown" ; } -static int add_name (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos) +static int add_name_nocheck (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos) { unsigned int id ; @@ -214,20 +212,32 @@ static int add_name (before_t *be, char const *srcdir, char const *name, service } ; unsigned int namelen = str_len(name) ; unsigned int i = genalloc_len(nameinfo_t, &nameinfo) ; - if (!stralloc_catb(&data, name, namelen + 1)) dienomem() ; if (type == SVTYPE_ONESHOT || type == SVTYPE_LONGRUN) if (!stralloc_catb(&keep, name, namelen + 1)) dienomem() ; + if (!stralloc_catb(&data, name, namelen + 1)) dienomem() ; if (!genalloc_append(nameinfo_t, &nameinfo, &info)) dienomem() ; if (!avltree_insert(&names_map, i)) dienomem() ; *pos = info.pos ; *kpos = info.kpos ; - if (namelen > be->maxnamelen) be->maxnamelen = namelen ; return 0 ; } } -static inline void add_specials (before_t *be) +static void check_identifier (char const *srcdir, char const *s) +{ + if (!byte_diff(s, 5, "s6rc-") && !byte_diff(s, 6, "s6-rc-")) + strerr_dief5x(1, "in ", srcdir, ": identifier ", s, " starts with reserved prefix") ; +} + +static int add_name (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos) +{ + check_identifier(srcdir, name) ; + return add_name_nocheck(be, srcdir, name, type, pos, kpos) ; +} + +static unsigned int add_internal_longrun (before_t *be, char const *name) { + unsigned int pos ; longrun_t service = { .common = @@ -238,14 +248,86 @@ static inline void add_specials (before_t *be) .timeout = { 0, 0 } }, .srcdir = 0, - .servicedirname = keep.len, - .logrelated = 0, - .logtype = 0 + .pipeline = { 0, 0 } } ; - add_name(be, "(s6-rc-compile internals)", S6RC_ONESHOT_RUNNER, SVTYPE_LONGRUN, &service.common.name, &service.common.kname) ; - if (!stralloc_cats(&keep, data.s + service.common.name) - || !stralloc_0(&keep)) dienomem() ; + add_name_nocheck(be, S6RC_INTERNALS, name, SVTYPE_LONGRUN, &pos, &service.common.kname) ; if (!genalloc_append(longrun_t, &be->longruns, &service)) dienomem() ; + return pos ; +} + +static unsigned int add_internal_oneshot (before_t *be, char const *name, char const *ups, unsigned int upn, char const *downs, unsigned int downn) +{ + unsigned int pos ; + oneshot_t service = + { + .common = + { + .ndeps = 2, + .depindex = genalloc_len(unsigned int, &be->indices), + .annotation_flags = 0, + .timeout = { 0, 0 } + }, + .argvindex = { keep.len, keep.len + downn } + } ; + service.argc[0] = byte_count(downs, downn, '\0') ; + service.argc[1] = byte_count(ups, upn, '\0') ; + if (!genalloc_catb(unsigned int, &be->indices, be->specialdeps, 2) + || !stralloc_catb(&keep, downs, downn) + || !stralloc_catb(&keep, ups, upn)) dienomem() ; + add_name_nocheck(be, S6RC_INTERNALS, name, SVTYPE_ONESHOT, &pos, &service.common.kname) ; + if (!genalloc_append(oneshot_t, &be->oneshots, &service)) dienomem() ; + return pos ; +} + +static void add_word (char const *word) +{ + if (!stralloc_cats(&satmp, word) || !stralloc_0(&satmp)) dienomem() ; +} + +static unsigned int add_storepipe (before_t *be, char const *name) +{ + unsigned int pos, sep, base = satmp.len ; + unsigned int namelen = str_len(name) ; + char svname[16 + namelen] ; + byte_copy(svname, 15, "s6rc-storepipe-") ; + byte_copy(svname + 15, namelen + 1, name) ; + + add_word(EXECLINE_EXTBINPREFIX "piperw") ; + add_word("0") ; + add_word("1") ; + add_word(EXECLINE_EXTBINPREFIX "if") ; + add_word(" " S6_EXTBINPREFIX "s6-fdholder-store") ; + add_word(" ../s6rc-fdholder/s") ; + add_word(" pipe:s6rc-r-") ; satmp.len-- ; add_word(name) ; + add_word("") ; + add_word(EXECLINE_EXTBINPREFIX "if") ; + add_word("-nt") ; + add_word(" " S6_EXTBINPREFIX "s6-fdholder-store") ; + add_word(" -d1") ; + add_word(" ./s6rc-fdholder/s") ; + add_word(" pipe:s6rc-w-") ; satmp.len-- ; add_word(name) ; + add_word("") ; + add_word(EXECLINE_EXTBINPREFIX "exit") ; + add_word("1") ; + + sep = satmp.len ; + + add_word(EXECLINE_EXTBINPREFIX "foreground") ; + add_word(" " S6_EXTBINPREFIX "s6-fdholder-delete") ; + add_word(" ../s6rc-fdholder/s") ; + add_word(" pipe:s6rc-w-") ; satmp.len-- ; add_word(name) ; + add_word("") ; + add_word(EXECLINE_EXTBINPREFIX "foreground") ; + add_word(" " S6_EXTBINPREFIX "s6-fdholder-delete") ; + add_word(" ../s6rc-fdholder/s") ; + add_word(" pipe:s6rc-r-") ; satmp.len-- ; add_word(name) ; + add_word("") ; + add_word(EXECLINE_EXTBINPREFIX "exit") ; + add_word("0") ; + + pos = add_internal_oneshot(be, svname, satmp.s + base, sep - base, satmp.s + sep, satmp.len - sep) ; + satmp.len = base ; + return pos ; } static int uint_uniq (unsigned int const *list, unsigned int n, unsigned int pos) @@ -348,8 +430,9 @@ static uint32 read_timeout (int dirfd, char const *srcdir, char const *name, cha static void add_common (before_t *be, int dirfd, char const *srcdir, char const *name, common_t *common, servicetype_t svtype) { + unsigned int dummy ; common->annotation_flags = 0 ; - add_name(be, srcdir, name, svtype, &common->name, &common->kname) ; + add_name(be, srcdir, name, svtype, &dummy, &common->kname) ; if (!add_namelist(be, dirfd, srcdir, name, "dependencies", &common->depindex, &common->ndeps)) { if (errno != ENOENT) @@ -363,19 +446,13 @@ static void add_common (before_t *be, int dirfd, char const *srcdir, char const static inline void add_oneshot (before_t *be, int dirfd, char const *srcdir, char const *name) { - static unsigned int const special_dep = 0 ; oneshot_t service ; if (verbosity >= 3) strerr_warni3x(name, " has type ", "oneshot") ; add_common(be, dirfd, srcdir, name, &service.common, SVTYPE_ONESHOT) ; read_script(be, dirfd, srcdir, name, "up", &service.argvindex[1], &service.argc[1], 1) ; read_script(be, dirfd, srcdir, name, "down", &service.argvindex[0], &service.argc[0], 0) ; - if (uint_uniq(genalloc_s(unsigned int, &be->indices) + service.common.depindex, service.common.ndeps, 0)) - { - if (!genalloc_append(unsigned int, &be->indices, &special_dep)) dienomem() ; - service.common.ndeps++ ; - } - else if (verbosity) - strerr_warnw6x(srcdir, "/", name, "/dependencies", " explicitly lists ", S6RC_ONESHOT_RUNNER) ; + if (!genalloc_append(unsigned int, &be->indices, &be->specialdeps[0])) dienomem() ; + service.common.ndeps++ ; if (verbosity >= 4) { unsigned int i = service.common.ndeps ; @@ -387,16 +464,15 @@ static inline void add_oneshot (before_t *be, int dirfd, char const *srcdir, cha strerr_warnt7x("dependency from ", name, " to ", data.s + *p, " (", fmt, ")") ; p++ ; } - } if (!genalloc_append(oneshot_t, &be->oneshots, &service)) dienomem() ; } static inline void add_longrun (before_t *be, int dirfd, char const *srcdir, char const *name) { - longrun_t service = { .srcdir = srcdir } ; + longrun_t service = { .srcdir = srcdir, .pipeline = { 0, 0 }, .pipelinename = 0 } ; + unsigned int relatedindex, n ; int fd ; - unsigned int logindex, n ; if (verbosity >= 3) strerr_warni3x(name, " has type ", "longrun") ; add_common(be, dirfd, srcdir, name, &service.common, SVTYPE_LONGRUN) ; fd = open_readat(dirfd, "run") ; @@ -415,40 +491,48 @@ static inline void add_longrun (before_t *be, int dirfd, char const *srcdir, cha strerr_dief4x(1, srcdir, "/", name, "/run is not a regular file") ; } close(fd) ; - if (add_namelist(be, dirfd, srcdir, name, "logger", &logindex, &n)) + fd = 0 ; + if (add_namelist(be, dirfd, srcdir, name, "producer-for", &relatedindex, &n)) { - register unsigned int const *deps = genalloc_s(unsigned int, &be->indices) + service.common.depindex ; - register unsigned int i = 0 ; if (n != 1) - strerr_dief5x(1, srcdir, "/", name, "/logger", " should only contain one service name") ; - service.logtype = 1 ; - service.logrelated = genalloc_s(unsigned int, &be->indices)[logindex] ; - service.servicedirname = service.common.kname ; - for (; i < service.common.ndeps ; i++) if (service.logrelated == deps[i]) break ; - if (i < service.common.ndeps) - genalloc_setlen(unsigned int, &be->indices, logindex) ; - else service.common.ndeps++ ; + strerr_dief5x(1, srcdir, "/", name, "/producer-for", " should only contain one service name") ; + service.pipeline[1] = genalloc_s(unsigned int, &be->indices)[relatedindex] ; + { + unsigned int dummy ; + unsigned int namelen = str_len(data.s + service.pipeline[1]) ; + char svname[16 + namelen] ; + byte_copy(svname, 15, "s6rc-storepipe-") ; + byte_copy(svname + 15, namelen + 1, data.s + service.pipeline[1]) ; + add_name_nocheck(be, srcdir, svname, SVTYPE_UNDEFINED, &n, &dummy) ; + if (!genalloc_append(unsigned int, &be->indices, &n)) dienomem() ; + service.common.ndeps += 2 ; + } if (verbosity >= 3) - strerr_warni3x(name, " is a producer for ", data.s + service.logrelated) ; + strerr_warni3x(name, " is a producer for ", data.s + service.pipeline[1]) ; + fd = 1 ; } - else if (add_namelist(be, dirfd, srcdir, name, "producer", &logindex, &n)) + if (add_namelist(be, dirfd, srcdir, name, "consumer-for", &relatedindex, &n)) { + unsigned int namelen = str_len(name) ; + char svname[16 + namelen] ; if (n != 1) - strerr_dief5x(1, srcdir, "/", name, "/producer", " should only contain one service name") ; - service.logtype = 2 ; - service.logrelated = genalloc_s(unsigned int, &be->indices)[logindex] ; - genalloc_setlen(unsigned int, &be->indices, logindex) ; - service.servicedirname = keep.len ; - if (!stralloc_cats(&keep, data.s + service.logrelated) - || !stralloc_catb(&keep, "/log", 5)) dienomem() ; + strerr_dief5x(1, srcdir, "/", name, "/consumer-for", " should only contain one service name") ; + service.pipeline[0] = genalloc_s(unsigned int, &be->indices)[relatedindex] ; + byte_copy(svname, 15, "s6rc-storepipe-") ; + byte_copy(svname + 15, namelen + 1, name) ; if (verbosity >= 3) - strerr_warni3x(name, " is a logger for ", data.s + service.logrelated) ; + strerr_warni3x(name, " is a consumer for ", data.s + service.pipeline[0]) ; + n = add_storepipe(be, svname) ; + genalloc_s(unsigned int, &be->indices)[relatedindex] = n ; + service.common.ndeps++ ; + fd = 0 ; } - else + if (fd && add_namelist(be, dirfd, srcdir, name, "pipeline-name", &relatedindex, &n)) { - service.logtype = 0 ; - service.servicedirname = service.common.kname ; - if (verbosity >= 3) strerr_warni2x(name, " has no logger or producer") ; + if (n != 1) + strerr_dief5x(1, srcdir, "/", name, "/pipeline-name", " should only contain one name") ; + service.pipelinename = genalloc_s(unsigned int, &be->indices)[relatedindex] ; + genalloc_setlen(unsigned int, &be->indices, relatedindex) ; } if (!genalloc_append(longrun_t, &be->longruns, &service)) dienomem() ; } @@ -501,7 +585,8 @@ static inline void add_sources (before_t *be, char const *srcdir) if (!d) break ; if (d->d_name[0] == '.') continue ; if (d->d_name[str_chr(d->d_name, '\n')]) - strerr_dief3x(2, "subdirectory of ", srcdir, " contains a newline character") ; + strerr_dief3x(1, "subdirectory of ", srcdir, " contains a newline character") ; + check_identifier(srcdir, d->d_name) ; satmp.len = cur ; if (!stralloc_catb(&satmp, d->d_name, str_len(d->d_name) + 1)) dienomem() ; if (stat(satmp.s + start, &st) < 0) @@ -517,6 +602,48 @@ static inline void add_sources (before_t *be, char const *srcdir) satmp.len = start ; } +static inline void add_pipeline_bundles (before_t *be) +{ + longrun_t const *longruns = genalloc_s(longrun_t, &be->longruns) ; + unsigned int n = genalloc_len(longrun_t, &be->longruns) ; + unsigned int i = n ; + while (i--) if (longruns[i].pipelinename) + { + bundle_t bundle = { .listindex = genalloc_len(unsigned int, &be->indices), .n = 1 } ; + unsigned int id ; + nameinfo_t const *info ; + unsigned int j = i ; + if (verbosity >= 3) strerr_warni2x("creating bundle for pipeline ", data.s + longruns[i].pipelinename) ; + add_name(be, S6RC_INTERNALS, data.s + longruns[i].pipelinename, SVTYPE_BUNDLE, &bundle.name, &id) ; + avltree_search(&names_map, keep.s + longruns[i].common.kname, &id) ; + info = genalloc_s(nameinfo_t, &nameinfo) + id ; + if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ; + + while (longruns[j].pipeline[1]) + { + if (bundle.n >= n) + strerr_dief4x(1, "pipeline ", data.s + longruns[i].pipelinename, " is too long: possible loop involving ", keep.s + longruns[j].common.kname) ; + avltree_search(&names_map, data.s + longruns[j].pipeline[1], &id) ; + info = genalloc_s(nameinfo_t, &nameinfo) + id ; + if (info->type != SVTYPE_LONGRUN) + strerr_dief5x(1, "longrun service ", keep.s + longruns[j].common.kname, " declares a consumer ", data.s + longruns[j].pipeline[1], " that is not a longrun service") ; + if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ; + j = info->i ; + { + unsigned int namelen = str_len(data.s + info->pos) ; + char svname[16 + namelen] ; + byte_copy(svname, 15, "s6rc-storepipe-") ; + byte_copy(svname + 15, namelen + 1, data.s + info->pos) ; + avltree_search(&names_map, svname, &id) ; + info = genalloc_s(nameinfo_t, &nameinfo) + id ; + if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ; + } + bundle.n += 2 ; + } + if (!genalloc_append(bundle_t, &be->bundles, &bundle)) dienomem() ; + } +} + /* Resolve all names and dependencies */ @@ -530,7 +657,7 @@ struct bundle_recinfo_s unsigned int n ; unsigned int nlong ; unsigned int nbits ; - uint32 const *indices ; + unsigned int const *indices ; unsigned char *barray ; unsigned char *mark ; unsigned int source ; @@ -541,7 +668,7 @@ static void resolve_bundle_rec (bundle_recinfo_t *recinfo, unsigned int i) if (!(recinfo->mark[i] & 2)) { bundle_t const *me = recinfo->oldb + i ; - uint32 const *listindex = recinfo->indices + me->listindex ; + unsigned int const *listindex = recinfo->indices + me->listindex ; unsigned int j = 0 ; if (recinfo->mark[i] & 1) strerr_dief4x(1, "cyclic bundle definition: resolution of ", data.s + recinfo->oldb[recinfo->source].name, " encountered a cycle involving ", data.s + me->name) ; @@ -572,7 +699,7 @@ static void resolve_bundle_rec (bundle_recinfo_t *recinfo, unsigned int i) } } -static inline unsigned int resolve_bundles (bundle_t const *oldb, bundle_t *newb, unsigned int nshort, unsigned int nlong, unsigned int nbundles, uint32 const *indices, unsigned char *barray) +static inline unsigned int resolve_bundles (bundle_t const *oldb, bundle_t *newb, unsigned int nshort, unsigned int nlong, unsigned int nbundles, unsigned int const *indices, unsigned char *barray) { unsigned int total = 0, i = 0 ; unsigned char mark[nbundles] ; @@ -609,7 +736,7 @@ static inline void flatlist_bundles (bundle_t *bundles, unsigned int nbundles, u } } -static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n, unsigned int nbits, uint32 const *indices, unsigned char *sarray, unsigned char const *barray) +static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n, unsigned int nbits, unsigned int const *indices, unsigned char *sarray, unsigned char const *barray) { unsigned int j = 0 ; for (; j < me->ndeps ; j++) @@ -626,7 +753,7 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, nlong + p->i)] = 0 ; - strerr_warnt7x("atomic ", data.s + me->name, " depends on oneshot ", data.s + p->pos, " (", fmt, ")") ; + strerr_warnt7x("atomic ", keep.s + me->kname, " depends on oneshot ", data.s + p->pos, " (", fmt, ")") ; } break ; case SVTYPE_LONGRUN : @@ -635,7 +762,7 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, p->i)] = 0 ; - strerr_warnt7x("atomic ", data.s + me->name, " depends on longrun ", data.s + p->pos, " (", fmt, ")") ; + strerr_warnt7x("atomic ", keep.s + me->kname, " depends on longrun ", data.s + p->pos, " (", fmt, ")") ; } break ; case SVTYPE_BUNDLE : @@ -644,21 +771,21 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, nlong + p->i)] = 0 ; - strerr_warnt4x("atomic ", data.s + me->name, " depends on bundle ", data.s + p->pos) ; + strerr_warnt4x("atomic ", keep.s + me->kname, " depends on bundle ", data.s + p->pos) ; } break ; default : - strerr_dief4x(1, "during dependency resolution for service ", data.s + me->name, ": undefined service name ", data.s + p->pos) ; + strerr_dief4x(1, "during dependency resolution for service ", keep.s + me->kname, ": undefined service name ", data.s + p->pos) ; } } } -static inline void check_logger (longrun_t const *longruns, unsigned int i) +static uint32 resolve_prodcons (longrun_t const *longruns, unsigned int i, int h, uint32 nlong) { unsigned int j ; register nameinfo_t const *p ; - if (!longruns[i].logtype) return ; - avltree_search(&names_map, data.s + longruns[i].logrelated, &j) ; + if (!longruns[i].pipeline[h]) return nlong ; + avltree_search(&names_map, data.s + longruns[i].pipeline[h], &j) ; p = genalloc_s(nameinfo_t, &nameinfo) + j ; switch (p->type) { @@ -666,21 +793,21 @@ static inline void check_logger (longrun_t const *longruns, unsigned int i) { unsigned int k ; register nameinfo_t const *q ; - if (longruns[p->i].logtype != 3 - longruns[i].logtype) goto err ; - avltree_search(&names_map, data.s + longruns[p->i].logrelated, &k) ; + avltree_search(&names_map, data.s + longruns[p->i].pipeline[!h], &k) ; q = genalloc_s(nameinfo_t, &nameinfo) + k ; if (q->type != SVTYPE_LONGRUN) goto err ; if (q->i != i) goto err ; break ; - err: - strerr_dief7x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " that does not declare it back ") ; + err: + strerr_dief7x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for a service named ", data.s + p->pos, " that does not declare it back ") ; } case SVTYPE_ONESHOT : case SVTYPE_BUNDLE : - strerr_dief8x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " of type ", p->type == SVTYPE_BUNDLE ? "bundle" : "oneshot") ; + strerr_dief8x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for a service named ", data.s + p->pos, " of type ", p->type == SVTYPE_BUNDLE ? "bundle" : "oneshot") ; default : - strerr_dief7x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " that is not defined") ; + strerr_dief6x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for an undefined service: ", data.s + p->pos) ; } + return p->i ; } static inline unsigned int ugly_bitarray_vertical_countones (unsigned char const *sarray, unsigned int n, unsigned int i) @@ -695,7 +822,7 @@ static inline unsigned int resolve_services (s6rc_db_t *db, before_t const *be, { oneshot_t const *oneshots = genalloc_s(oneshot_t const, &be->oneshots) ; longrun_t const *longruns = genalloc_s(longrun_t const, &be->longruns) ; - uint32 const *indices = genalloc_s(uint32 const, &be->indices) ; + unsigned int const *indices = genalloc_s(unsigned int const, &be->indices) ; unsigned int n = db->nshort + db->nlong ; unsigned int nbits = bitarray_div8(n) ; unsigned int total[2] = { 0, 0 } ; @@ -704,14 +831,14 @@ static inline unsigned int resolve_services (s6rc_db_t *db, before_t const *be, byte_zero(sarray, nbits * n) ; for (; i < db->nlong ; i++) { + srcdirs[i] = longruns[i].srcdir ; db->services[i].name = longruns[i].common.kname ; db->services[i].flags = longruns[i].common.annotation_flags ; db->services[i].timeout[0] = longruns[i].common.timeout[0] ; db->services[i].timeout[1] = longruns[i].common.timeout[1] ; - db->services[i].x.longrun.servicedir = longruns[i].servicedirname ; - srcdirs[i] = longruns[i].srcdir ; + db->services[i].x.longrun.pipeline[0] = resolve_prodcons(longruns, i, 0, db->nlong) ; + db->services[i].x.longrun.pipeline[1] = resolve_prodcons(longruns, i, 1, db->nlong) ; resolve_deps(&longruns[i].common, db->nlong, n, nbits, indices, sarray + i * nbits, barray) ; - check_logger(longruns, i) ; } for (i = 0 ; i < db->nshort ; i++) { @@ -742,7 +869,9 @@ static inline void flatlist_services (s6rc_db_t *db, unsigned char const *sarray { unsigned int n = db->nshort + db->nlong ; unsigned int nbits = bitarray_div8(n) ; + diuint32 problem ; unsigned int i = 0 ; + register int r ; if (verbosity >= 3) strerr_warni1x("converting service dependency array") ; for (; i < n ; i++) { @@ -755,10 +884,18 @@ static inline void flatlist_services (s6rc_db_t *db, unsigned char const *sarray for (; k < db->services[i].ndeps[1] ; j++) if (bitarray_peek(sarray + i * nbits, j)) mydeps[k++] = j ; } - if (verbosity >= 3) strerr_warni1x("checking for dependency cycles") ; - nbits = s6rc_db_check_depcycles(db, 1, &i) ; - if (nbits < n) - strerr_dief4x(1, "cyclic service definition: resolution of ", db->string + db->services[nbits].name, " encountered a cycle involving ", db->string + db->services[i].name) ; + + if (verbosity >= 3) strerr_warni1x("checking database correctness") ; + if (s6rc_db_check_depcycles(db, 1, &problem)) + strerr_dief4x(1, "cyclic service dependency involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ; + r = s6rc_db_check_pipelines(db, &problem) ; + if (r) + { + if (r == 1) + strerr_dief4x(1, "cyclic longrun pipeline involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ; + else + strerr_dief4x(1, "longrun pipeline collision involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ; + } } @@ -803,6 +940,21 @@ static void auto_file (char const *compiled, char const *file, char const *s, un } } +static void auto_symlink (char const *compiled, char const *name, char const *target) +{ + unsigned int clen = str_len(compiled) ; + unsigned int flen = str_len(name) ; + char fn[clen + flen + 2] ; + byte_copy(fn, clen, compiled) ; + fn[clen] = '/' ; + byte_copy(fn + clen + 1, flen + 1, name) ; + if (symlink(target, fn) < 0) + { + cleanup(compiled) ; + strerr_diefu4sys(111, "symlink ", target, " to ", fn) ; + } +} + static void auto_rights (char const *compiled, char const *file, mode_t mode) { unsigned int clen = str_len(compiled) ; @@ -837,40 +989,120 @@ static inline void write_sizes (char const *compiled, s6rc_db_t const *db) auto_file(compiled, "n", pack, 20) ; } -static inline void write_specials (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn) +static void make_skel (char const *compiled, char const *name, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn) { + unsigned int namelen = str_len(name) ; unsigned int i = uidn ; - char fn[sizeof(BASE_RULES) + UINT64_FMT + 6] = BASE_RULES ; - auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER) ; - auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/notification-fd", "3\n", 2) ; - auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", S6RC_ONESHOT_RUNNER_RUNSCRIPT, sizeof(S6RC_ONESHOT_RUNNER_RUNSCRIPT) - 1) ; - auto_rights(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", 0755) ; - auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/data") ; - auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/data/rules") ; - if (gidn) auto_dir(compiled, fn) ; - fn[sizeof(BASE_RULES) - 4] = 'u' ; + char fn[UINT64_FMT + namelen + 35] ; + byte_copy(fn, 12, "servicedirs/") ; + byte_copy(fn + 12, namelen + 1, name) ; + auto_dir(compiled, fn) ; + byte_copy(fn + 12 + namelen, 17, "/notification-fd") ; + auto_file(compiled, fn, "3\n", 2) ; + byte_copy(fn + 13 + namelen, 5, "data") ; + auto_dir(compiled, fn) ; + byte_copy(fn + 17 + namelen, 7, "/rules") ; + auto_dir(compiled, fn) ; + if (gidn) + { + byte_copy(fn + 23 + namelen, 5, "/gid") ; + auto_dir(compiled, fn) ; + } + byte_copy(fn + 23 + namelen, 5, "/uid") ; auto_dir(compiled, fn) ; - fn[sizeof(BASE_RULES) - 1] = '/' ; + fn[27 + namelen] = '/' ; while (i--) { - unsigned int len = uint64_fmt(fn + sizeof(BASE_RULES), uids[i]) ; - fn[sizeof(BASE_RULES) + len] = 0 ; + unsigned int len = uint64_fmt(fn + 28 + namelen, uids[i]) ; + fn[28 + namelen + len] = 0 ; auto_dir(compiled, fn) ; - byte_copy(fn + sizeof(BASE_RULES) + len, 7, "/allow") ; + byte_copy(fn + 28 + namelen + len, 7, "/allow") ; auto_file(compiled, fn, "", 0) ; } - fn[sizeof(BASE_RULES) - 4] = 'g' ; i = gidn ; while (i--) { - unsigned int len = gid_fmt(fn + sizeof(BASE_RULES), gids[i]) ; - fn[sizeof(BASE_RULES) + len] = 0 ; + unsigned int len = gid_fmt(fn + 28 + namelen, gids[i]) ; + fn[28 + namelen + len] = 0 ; auto_dir(compiled, fn) ; - byte_copy(fn + sizeof(BASE_RULES) + len, 7, "/allow") ; + byte_copy(fn + 28 + namelen + len, 7, "/allow") ; auto_file(compiled, fn, "", 0) ; } } +static inline void write_oneshot_runner (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn) +{ + make_skel(compiled, S6RC_ONESHOT_RUNNER, uids, uidn, gids, gidn) ; + auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", S6RC_ONESHOT_RUNNER_RUNSCRIPT, sizeof(S6RC_ONESHOT_RUNNER_RUNSCRIPT) - 1) ; + auto_rights(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", 0755) ; +} + +static inline void write_fdholder (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser) +{ + unsigned int base = satmp.len ; + make_skel(compiled, S6RC_FDHOLDER, uids, uidn, gids, gidn) ; + { + char fn[62 + S6RC_FDHOLDER_LEN + UINT64_FMT] = "servicedirs/" S6RC_FDHOLDER "/data/rules/uid/" ; + char fmt[7 + UINT64_FMT] = "../uid/" ; + unsigned int i = uint64_fmt(fmt + 7, uids[0]) ; + fmt[7 + i] = 0 ; + byte_copy(fn + 28 + S6RC_FDHOLDER_LEN, i, fmt + 7) ; + byte_copy(fn + 28 + S6RC_FDHOLDER_LEN + i, 5, "/env") ; + auto_dir(compiled, fn) ; + byte_copy(fn + 32 + S6RC_FDHOLDER_LEN + i, 18, "/S6_FDHOLDER_LIST") ; + auto_file(compiled, fn, "\n", 1) ; + byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 12, "STORE_REGEX") ; + auto_file(compiled, fn, "^pipe:s6rc-\n", 12) ; + byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 15, "RETRIEVE_REGEX") ; + auto_symlink(compiled, fn, "S6_FDHOLDER_STORE_REGEX") ; + byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 8, "SETDUMP") ; + auto_file(compiled, fn, "\n", 1) ; + fn[45 + S6RC_FDHOLDER_LEN + i] = 'G' ; + auto_file(compiled, fn, "\n", 1) ; + + for (i = 1 ; i < uidn ; i++) + { + unsigned int len = uint64_fmt(fn + 28 + S6RC_FDHOLDER_LEN, uids[i]) ; + fn[28 + S6RC_FDHOLDER_LEN + len] = 0 ; + auto_symlink(compiled, fn, fmt + 7) ; + } + fn[24 + S6RC_FDHOLDER_LEN] = 'g' ; + i = gidn ; + while (i--) + { + unsigned int len = gid_fmt(fn + 28 + S6RC_FDHOLDER_LEN, gids[i]) ; + fn[28 + S6RC_FDHOLDER_LEN + len] = 0 ; + auto_symlink(compiled, fn, fmt) ; + } + } + + if (!stralloc_cats(&satmp, + "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n" \ + EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n" \ + EXECLINE_EXTBINPREFIX "fdmove 1 3\n")) dienomem() ; + if (fdhuser) + { + if (!stralloc_cats(&satmp, S6_EXTBINPREFIX "s6-envuidgid -i -- ") + || !string_quote(&satmp, fdhuser, str_len(fdhuser)) + || !stralloc_catb(&satmp, "\n", 1)) dienomem() ; + } + if (!stralloc_cats(&satmp, S6_EXTBINPREFIX "s6-fdholder-daemon -1 ")) dienomem() ; + if (fdhuser) + { + if (!stralloc_cats(&satmp, "-U ")) dienomem() ; + } + if (!stralloc_cats(&satmp, "-i data/rules -- s\n")) dienomem() ; + auto_file(compiled, "servicedirs/" S6RC_FDHOLDER "/run", satmp.s + base, satmp.len - base) ; + satmp.len = base ; + auto_rights(compiled, "servicedirs/" S6RC_FDHOLDER "/run", 0755) ; +} + +static inline void write_specials (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser) +{ + write_oneshot_runner(compiled, uids, uidn, gids, gidn) ; + write_fdholder(compiled, uids, uidn, gids, gidn, fdhuser) ; +} + static inline void write_resolve (char const *compiled, s6rc_db_t const *db, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps) { unsigned int clen = str_len(compiled) ; @@ -975,95 +1207,138 @@ static void dircopy (char const *compiled, char const *srcfn, char const *dstfn) } } -static void write_servicedir (char const *compiled, char const *srcdir, char const *src, char const *dst) +static int read_uint (char const *file, unsigned int *fd) { - unsigned int clen = str_len(compiled) ; - unsigned int srcdirlen = str_len(srcdir) ; - unsigned int srclen = str_len(src) ; - unsigned int dstlen = str_len(dst) ; - struct stat st ; - char dstfn[clen + 30 + dstlen] ; - char srcfn[srcdirlen + srclen + 18] ; - byte_copy(dstfn, clen, compiled) ; - byte_copy(dstfn + clen, 13, "/servicedirs/") ; - byte_copy(dstfn + clen + 13, dstlen + 1, dst) ; - if (mkdir(dstfn, 0755) < 0) + 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, fd)) return (errno = EINVAL, -1) ; + return 1 ; +} + +static inline void write_run_wrapper (char const *compiled, char const *fn, s6rc_db_t const *db, unsigned int i, unsigned int fd) +{ + unsigned int base = satmp.len ; + if (!stralloc_cats(&satmp, "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n")) dienomem() ; + if (db->services[i].x.longrun.pipeline[0] < db->nlong) { - cleanup(compiled) ; - strerr_diefu2sys(111, "mkdir ", dstfn) ; + if (!stralloc_cats(&satmp, EXECLINE_EXTBINPREFIX "s6-fdholder-retrieve ../s6rc-fdholder/s \"pipe:s6rc-r-") + || !string_quote_nodelim(&satmp, db->string + db->services[i].name, str_len(db->string + db->services[i].name)) + || !stralloc_cats(&satmp, "\"\n")) dienomem() ; } - byte_copy(dstfn + clen + 13 + dstlen, 5, "/run") ; - byte_copy(srcfn, srcdirlen, srcdir) ; - srcfn[srcdirlen] = '/' ; - byte_copy(srcfn + srcdirlen + 1, srclen, src) ; - byte_copy(srcfn + srcdirlen + srclen + 1, 5, "/run") ; - if (!filecopy(srcfn, dstfn, 0755)) + if (db->services[i].x.longrun.pipeline[1] < db->nlong) { - cleanup(compiled) ; - strerr_diefu4sys(111, "copy ", srcfn, " to ", dstfn) ; + char const *consumername = db->string + db->services[db->services[i].x.longrun.pipeline[1]].name ; + if (!stralloc_cats(&satmp, EXECLINE_EXTBINPREFIX "fdmove ") + || !stralloc_cats(&satmp, fd == 3 ? "4" : "3") + || !stralloc_cats(&satmp, " 0\n" + EXECLINE_EXTBINPREFIX "s6-fdholder-retrieve ../s6rc-fdholder/s \"pipe:s6rc-w-") + || !string_quote_nodelim(&satmp, consumername, str_len(consumername)) + || !stralloc_cats(&satmp, "\"\n" + EXECLINE_EXTBINPREFIX "fdmove 1 0\n" + EXECLINE_EXTBINPREFIX "fdmove 0 ") + || !stralloc_cats(&satmp, fd == 3 ? "4" : "3") + || !stralloc_cats(&satmp, "\n")) dienomem() ; } - byte_copy(dstfn + clen + 14 + dstlen, 7, "finish") ; - byte_copy(srcfn + srcdirlen + srclen + 2, 7, "finish") ; - filecopy(srcfn, dstfn, 0755) ; - byte_copy(dstfn + clen + 14 + dstlen, 15, "timeout-finish") ; - byte_copy(srcfn + srcdirlen + srclen + 2, 15, "timeout-finish") ; - filecopy(srcfn, dstfn, 0644) ; - byte_copy(dstfn + clen + 14 + dstlen, 16, "notification-fd") ; - byte_copy(srcfn + srcdirlen + srclen + 2, 16, "notification-fd") ; - filecopy(srcfn, dstfn, 0644) ; - - byte_copy(srcfn + srcdirlen + srclen + 4, 7, "setsid") ; - if (stat(srcfn, &st) < 0) + if (!stralloc_cats(&satmp, "./run.user\n")) dienomem() ; + auto_file(compiled, fn, satmp.s + base, satmp.len - base) ; + satmp.len = base ; + auto_rights(compiled, fn, 0755) ; +} + +static inline void write_servicedirs (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs) +{ + unsigned int clen = str_len(compiled) ; + unsigned int i = 2 ; + if (verbosity >= 3) strerr_warni3x("writing ", compiled, "/servicedirs") ; + for (; i < db->nlong ; i++) { - if (errno != ENOENT) + struct stat st ; + unsigned int srcdirlen = str_len(srcdirs[i]) ; + unsigned int len = str_len(db->string + db->services[i].name) ; + unsigned int fd = 0 ; + register int r ; + char srcfn[srcdirlen + len + 18] ; + char dstfn[clen + len + 30] ; + byte_copy(dstfn, clen, compiled) ; + byte_copy(dstfn + clen, 13, "/servicedirs/") ; + byte_copy(dstfn + clen + 13, len + 1, db->string + db->services[i].name) ; + if (mkdir(dstfn, 0755) < 0) { cleanup(compiled) ; - strerr_diefu2sys(111, "stat ", srcfn) ; + strerr_diefu2sys(111, "mkdir ", dstfn) ; } - } - else - { - int fd ; - byte_copy(dstfn + clen + 16 + dstlen, 7, "setsid") ; - fd = open_trunc(dstfn) ; - if (fd < 0) + byte_copy(srcfn, srcdirlen, srcdirs[i]) ; + srcfn[srcdirlen] = '/' ; + byte_copy(srcfn + srcdirlen + 1, len, db->string + db->services[i].name) ; + byte_copy(srcfn + srcdirlen + 1 + len, 17, "/notification-fd") ; + r = read_uint(srcfn, &fd) ; + if (r < 0) { cleanup(compiled) ; - strerr_diefu2sys(111, "touch ", dstfn) ; + strerr_diefu2sys(111, "read ", srcfn) ; + } + if (r) + { + char fmt[UINT_FMT] ; + unsigned int fmtlen = uint_fmt(fmt, fd) ; + fmt[fmtlen++] = '\n' ; + byte_copy(dstfn + clen + 13 + len, 17, "/notification-fd") ; + if (!openwritenclose_unsafe(dstfn, fmt, fmtlen)) + { + cleanup(compiled) ; + strerr_diefu2sys(111, "write to ", dstfn) ; + } } - close(fd) ; - } - - byte_copy(dstfn + clen + 14 + dstlen, 5, "data") ; - byte_copy(srcfn + srcdirlen + srclen + 2, 5, "data") ; - dircopy(compiled, srcfn, dstfn) ; - byte_copy(dstfn + clen + 14 + dstlen, 4, "env") ; - byte_copy(srcfn + srcdirlen + srclen + 2, 4, "env") ; - dircopy(compiled, srcfn, dstfn) ; -} -static inline void write_servicedirs (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, unsigned int maxnamelen) -{ - unsigned int clen = str_len(compiled) ; - unsigned int i = 1 ; - char fn[clen + 23 + maxnamelen] ; - char islogger[db->nlong] ; - if (verbosity >= 3) strerr_warni3x("writing ", compiled, "/servicedirs") ; - byte_copy(fn, clen, compiled) ; - byte_copy(fn + clen, 12, "/servicedirs") ; - fn[clen+12] = '/' ; - byte_zero(islogger, db->nlong) ; - for (; i < db->nlong ; i++) - { - char const *servicedirname = db->string + db->services[i].x.longrun.servicedir ; - islogger[i] = servicedirname[str_chr(servicedirname, '/')] ; - if (!islogger[i]) - write_servicedir(compiled, srcdirs[i], db->string + db->services[i].name, servicedirname) ; - } - for (i = 1 ; i < db->nlong ; i++) - { - if (islogger[i]) - write_servicedir(compiled, srcdirs[i], db->string + db->services[i].name, db->string + db->services[i].x.longrun.servicedir) ; + byte_copy(dstfn + clen + 13 + len, 5, "/run") ; + if (db->services[i].x.longrun.pipeline[0] < db->nlong || db->services[i].x.longrun.pipeline[1] < db->nlong) + { + write_run_wrapper(compiled, dstfn + clen + 1, db, i, fd) ; + byte_copy(dstfn + clen + 17 + len, 6, ".user") ; + } + byte_copy(srcfn + srcdirlen + 1 + len, 5, "/run") ; + if (!filecopy(srcfn, dstfn, 0755)) + { + cleanup(compiled) ; + strerr_diefu4sys(111, "copy ", srcfn, " to ", dstfn) ; + } + byte_copy(dstfn + clen + 14 + len, 7, "finish") ; + byte_copy(srcfn + srcdirlen + len + 2, 7, "finish") ; + filecopy(srcfn, dstfn, 0755) ; + byte_copy(dstfn + clen + 14 + len, 15, "timeout-finish") ; + byte_copy(srcfn + srcdirlen + len + 2, 15, "timeout-finish") ; + filecopy(srcfn, dstfn, 0644) ; + + byte_copy(srcfn + srcdirlen + len + 4, 7, "setsid") ; + if (stat(srcfn, &st) < 0) + { + if (errno != ENOENT) + { + cleanup(compiled) ; + strerr_diefu2sys(111, "stat ", srcfn) ; + } + } + else + { + int fd ; + byte_copy(dstfn + clen + 16 + len, 7, "setsid") ; + fd = open_trunc(dstfn) ; + if (fd < 0) + { + cleanup(compiled) ; + strerr_diefu2sys(111, "touch ", dstfn) ; + } + close(fd) ; + } + + byte_copy(dstfn + clen + 14 + len, 5, "data") ; + byte_copy(srcfn + srcdirlen + len + 2, 5, "data") ; + dircopy(compiled, srcfn, dstfn) ; + byte_copy(dstfn + clen + 14 + len, 4, "env") ; + byte_copy(srcfn + srcdirlen + len + 2, 4, "env") ; + dircopy(compiled, srcfn, dstfn) ; } } @@ -1081,8 +1356,9 @@ static inline int write_service (buffer *b, s6rc_service_t const *sv, int type) uint32_pack_big(pack + 28, sv->deps[1]) ; if (type) { - uint32_pack_big(pack + 32, sv->x.longrun.servicedir) ; - m = 36 ; + uint32_pack_big(pack + 32, sv->x.longrun.pipeline[0]) ; + uint32_pack_big(pack + 36, sv->x.longrun.pipeline[1]) ; + m = 40 ; } else { @@ -1154,21 +1430,23 @@ static inline void write_db (char const *compiled, s6rc_db_t const *db) strerr_diefu2sys(111, "write to ", dbfn) ; } -static inline void write_compiled (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps, unsigned int maxnamelen, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn) +static inline void write_compiled (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser) { if (verbosity >= 2) strerr_warni2x("writing compiled information to ", compiled) ; init_compiled(compiled) ; write_sizes(compiled, db) ; write_resolve(compiled, db, bundles, nbundles, bdeps) ; + stralloc_free(&data) ; write_db(compiled, db) ; - write_specials(compiled, uids, uidn, gids, gidn) ; - write_servicedirs(compiled, db, srcdirs, maxnamelen) ; + write_specials(compiled, uids, uidn, gids, gidn, fdhuser) ; + write_servicedirs(compiled, db, srcdirs) ; } int main (int argc, char const *const *argv) { before_t before = BEFORE_ZERO ; char const *compiled ; + char const *fdhuser = 0 ; unsigned int uidn = 0, gidn = 0 ; uint64 uids[256] ; gid_t gids[256] ; @@ -1177,13 +1455,14 @@ int main (int argc, char const *const *argv) subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { - register int opt = subgetopt_r(argc, argv, "v:u:g:", &l) ; + register int opt = subgetopt_r(argc, argv, "v:u:g:h:", &l) ; if (opt == -1) break ; switch (opt) { case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; case 'u' : if (!uint64_scanlist(uids, 255, l.arg, &uidn)) dieusage() ; break ; case 'g' : if (!gid_scanlist(gids, 255, l.arg, &gidn)) dieusage() ; break ; + case 'h' : fdhuser = l.arg ; break ; default : dieusage() ; } } @@ -1192,14 +1471,15 @@ int main (int argc, char const *const *argv) if (argc < 2) dieusage() ; if (!uidn && !gidn) uids[uidn++] = 0 ; compiled = *argv++ ; - add_specials(&before) ; + before.specialdeps[0] = add_internal_longrun(&before, S6RC_ONESHOT_RUNNER) ; + before.specialdeps[1] = add_internal_longrun(&before, S6RC_FDHOLDER) ; for (; *argv ; argv++) add_sources(&before, *argv) ; + add_pipeline_bundles(&before) ; { unsigned int n = genalloc_len(oneshot_t, &before.oneshots) + genalloc_len(longrun_t, &before.longruns) ; unsigned int nbits = bitarray_div8(n) ; unsigned int nbundles = genalloc_len(bundle_t, &before.bundles) ; - unsigned int maxnamelen = before.maxnamelen ; s6rc_service_t servicesblob[n] ; s6rc_db_t db = { @@ -1214,13 +1494,13 @@ int main (int argc, char const *const *argv) unsigned char sarray[nbits * n] ; bundle_t bundles[nbundles] ; unsigned char barray[nbits * nbundles] ; - unsigned int nbdeps = resolve_bundles(genalloc_s(bundle_t, &before.bundles), bundles, db.nshort, db.nlong, nbundles, genalloc_s(uint32, &before.indices), barray) ; + unsigned int nbdeps = resolve_bundles(genalloc_s(bundle_t, &before.bundles), bundles, db.nshort, db.nlong, nbundles, genalloc_s(unsigned int, &before.indices), barray) ; uint32 bdeps[nbdeps] ; genalloc_free(bundle_t, &before.bundles) ; flatlist_bundles(bundles, nbundles, nbits, barray, bdeps) ; db.ndeps = resolve_services(&db, &before, srcdirs, sarray, barray) ; - genalloc_free(uint32, &before.indices) ; + genalloc_free(unsigned int, &before.indices) ; genalloc_free(oneshot_t, &before.oneshots) ; genalloc_free(longrun_t, &before.longruns) ; genalloc_free(nameinfo_t, &nameinfo) ; @@ -1229,7 +1509,7 @@ int main (int argc, char const *const *argv) uint32 deps[db.ndeps << 1] ; db.deps = deps ; flatlist_services(&db, sarray) ; - write_compiled(compiled, &db, srcdirs, bundles, nbundles, bdeps, maxnamelen, uids, uidn, gids, gidn) ; + write_compiled(compiled, &db, srcdirs, bundles, nbundles, bdeps, uids, uidn, gids, gidn, fdhuser) ; } } diff --git a/src/s6-rc/s6-rc-db.c b/src/s6-rc/s6-rc-db.c index aeaff76..8621b6c 100644 --- a/src/s6-rc/s6-rc-db.c +++ b/src/s6-rc/s6-rc-db.c @@ -180,16 +180,6 @@ static void print_timeout (char const *name, int h) strerr_diefu1sys(111, "write to stdout") ; } -static void print_servicedir (char const *name) -{ - unsigned int n = resolve_service(name) ; - if (n >= db->nlong) - strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " does not represent a longrun service") ; - if (buffer_puts(buffer_1, db->string + db->services[n].x.longrun.servicedir) < 0 - || buffer_putflush(buffer_1, "\n", 1) < 0) - strerr_diefu1sys(111, "write to stdout") ; -} - static void print_script (char const *name, int h) { unsigned int argc ; @@ -209,6 +199,30 @@ static void print_script (char const *name, int h) strerr_diefu1sys(111, "write to stdout") ; } +static inline void print_pipeline (char const *name) +{ + unsigned int n = resolve_service(name) ; + if (n >= db->nlong) + strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " does not represent a longrun") ; + for (;;) + { + register unsigned int j = db->services[n].x.longrun.pipeline[0] ; + if (j >= db->nlong) break ; + n = j ; + } + for (;;) + { + register unsigned int j = db->services[n].x.longrun.pipeline[1] ; + if (buffer_puts(buffer_1, db->string + db->services[n].name) < 0 + || buffer_put(buffer_1, "\n", 1) < 0) + strerr_diefu1sys(111, "write to stdout") ; + if (j >= db->nlong) break ; + n = j ; + } + if (buffer_flush(buffer_1)) + strerr_diefu1sys(111, "write to stdout") ; +} + static inline void print_flags (char const *name) { unsigned int n = resolve_service(name) ; @@ -278,7 +292,7 @@ static inline void print_help (void) "s6-rc-db [ -u | -d ] timeout atomicname\n" "s6-rc-db contents bundlename\n" "s6-rc-db [ -u | -d ] dependencies servicename...\n" -"s6-rc-db servicedir longrunname\n" +"s6-rc-db pipeline longrunname\n" "s6-rc-db [ -u | -d ] script oneshotname\n" "s6-rc-db flags atomicname\n" "s6-rc-db atomics servicename...\n" @@ -305,7 +319,7 @@ static inline unsigned int parse_command (char const *command) "timeout", "contents", "dependencies", - "servicedir", + "pipeline", "script", "flags", "atomics", @@ -421,11 +435,19 @@ int main (int argc, char const *const *argv) { case 1 : /* check */ { - unsigned int problem, w ; - if (!s6rc_db_check_revdeps(&dbblob)) + diuint32 problem ; + if (s6rc_db_check_revdeps(&dbblob)) strerr_dief3x(4, "invalid service database in ", compiled, ": direct and reverse dependencies are mismatched") ; - w = s6rc_db_check_depcycles(&dbblob, 1, &problem) ; - if (w < n) strerr_dief6x(4, "invalid service database in ", compiled, ": service ", stringblob + serviceblob[w].name, " has a dependency cycle involving ", stringblob + serviceblob[problem].name) ; + if (s6rc_db_check_depcycles(&dbblob, 1, &problem)) + strerr_dief8x(4, "invalid service database in ", compiled, ": dependency ", "cycle", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ; + r = s6rc_db_check_pipelines(&dbblob, &problem) ; + if (r) + { + if (r == 1) + strerr_dief8x(4, "invalid service database in ", compiled, ": pipeline ", "cycle", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ; + else + strerr_dief8x(4, "invalid service database in ", compiled, ": pipeline ", "collision", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ; + } break ; } case 2 : /* list */ @@ -450,8 +472,8 @@ int main (int argc, char const *const *argv) case 6 : /* dependencies */ print_union(argv + 1, up, 1, 0) ; break ; - case 7 : /* servicedir */ - print_servicedir(argv[1]) ; + case 7 : /* pipeline */ + print_pipeline(argv[1]) ; break ; case 8 : /* script */ print_script(argv[1], up) ; diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c index 42a84e8..08f719f 100644 --- a/src/s6-rc/s6-rc-update.c +++ b/src/s6-rc/s6-rc-update.c @@ -8,8 +8,10 @@ #include <skalibs/uint32.h> #include <skalibs/uint.h> #include <skalibs/bytestr.h> -#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> #include <skalibs/strerr2.h> +#include <skalibs/sgetopt.h> #include <skalibs/bitarray.h> #include <skalibs/cdb.h> #include <skalibs/stralloc.h> @@ -21,7 +23,7 @@ #include <s6-rc/config.h> #include <s6-rc/s6rc.h> -#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] newdb" +#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f conversion_file ] newdb" #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "build string") ; @@ -29,6 +31,11 @@ static char const *live = S6RC_LIVE_BASE ; static unsigned int livelen = sizeof(S6RC_LIVE_BASE) - 1 ; static unsigned int verbosity = 1 ; + + + /* Conversions and transitions */ + + static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, unsigned int *newnames, unsigned char *oldstate, cdb_t *oldc, s6rc_db_t const *olddb) { unsigned int base = sa->len ; @@ -60,6 +67,9 @@ static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, u strerr_diefu3sys(111, "read ", live, "/compiled/resolve.cdb") ; uint32_unpack_big(pack, &x) ; if (x >= oldn) strerr_dief3x(4, "invalid database in ", live, "/compiled") ; + if (oldstate[x] & 64) + strerr_dief3x(6, "service ", olddb->string + olddb->services[x].name, " appears more than once in conversion file") ; + oldstate[x] |= 64 ; cur = base + slen + str_len(sa->s + base + slen) + 1 ; if (n >= 2 && !str_diff(sa->s + cur, "->")) { @@ -80,18 +90,17 @@ static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, u } } -static inline void parse_conversion_file (stralloc *sa, unsigned int *newnames, unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb) +static inline void parse_conversion_file (char const *convfile, stralloc *sa, unsigned int *newnames, unsigned char *oldstate, cdb_t *oldc, s6rc_db_t const *olddb) { + int fd = open_readb(convfile) ; + char buf[4096] ; + buffer b = BUFFER_INIT(&fd_readsv, fd, buf, 4096) ; unsigned int base = satmp.len ; - cdb_t oldc = CDB_ZERO ; - int oldfdres = open_readatb(fdoldc, "resolve.cdb") ; - if (oldfdres < 0) strerr_diefu3sys(111, "open ", live, "/compiled/resolve.cdb") ; - if (!cdb_init_map(&oldc, oldfdres, 1)) - strerr_diefu3sys(111, "cdb_init ", live, "/compiled/resolve.cdb") ; + if (fd < 0) strerr_diefu2sys(111, "open ", convfile) ; for (;;) { - register int r = skagetln(buffer_0, &satmp, '\n') ; + register int r = skagetln(&b, &satmp, '\n') ; if (!r) break ; if (r < 0) { @@ -99,45 +108,53 @@ static inline void parse_conversion_file (stralloc *sa, unsigned int *newnames, if (!stralloc_0(&satmp)) dienomem() ; } else satmp.s[satmp.len - 1] = 0 ; - parse_line(sa, satmp.s + base, satmp.len - base, newnames, oldstate, &oldc, olddb) ; + parse_line(sa, satmp.s + base, satmp.len - base, newnames, oldstate, oldc, olddb) ; satmp.len = base ; } satmp.len = base ; + close(fd) ; +} + +static inline void stuff_with_oldc (unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, char const *convfile, unsigned int *nameindex, stralloc *namedata) +{ + cdb_t oldc = CDB_ZERO ; + int oldfdres = open_readatb(fdoldc, "resolve.cdb") ; + if (oldfdres < 0) strerr_diefu3sys(111, "open ", live, "/compiled/resolve.cdb") ; + if (!cdb_init_map(&oldc, oldfdres, 1)) + strerr_diefu3sys(111, "cdb_init ", live, "/compiled/resolve.cdb") ; + + parse_conversion_file(convfile, namedata, nameindex, oldstate, &oldc, olddb) ; + cdb_free(&oldc) ; close(oldfdres) ; } -static inline void fill_convtable_and_flags (unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, int fdnewc, char const *newfn, s6rc_db_t const *olddb, s6rc_db_t const *newdb) +static inline void fill_convtable_and_flags (unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, cdb_t *newc, char const *newfn, s6rc_db_t const *olddb, s6rc_db_t const *newdb) { unsigned int newn = newdb->nshort + newdb->nlong ; - cdb_t newc = CDB_ZERO ; - int newfdres = open_readatb(fdnewc, "resolve.cdb") ; unsigned int i = olddb->nshort + olddb->nlong ; - if (newfdres < 0) strerr_diefu3sys(111, "open ", newfn, "/resolve.cdb") ; - if (!cdb_init_map(&newc, newfdres, 1)) - strerr_diefu3sys(111, "cdb_init ", newfn, "/resolve.cdb") ; while (i--) { char const *newname = oldstate[i] & 16 ? namedata + nameindex[i] : olddb->string + olddb->services[i].name ; unsigned int len ; - int r = cdb_find(&newc, newname, str_len(newname)) ; + int r = cdb_find(newc, newname, str_len(newname)) ; if (r < 0) strerr_diefu3sys(111, "read ", newfn, "/resolve.cdb") ; if (!r) { oldstate[i] |= 2 ; /* disappeared -> want down */ continue ; } - if (cdb_datalen(&newc) & 3) + if (cdb_datalen(newc) & 3) strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ; - len = cdb_datalen(&newc) >> 2 ; + len = cdb_datalen(newc) >> 2 ; if (len > newn) strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ; { - char pack[cdb_datalen(&newc) + 1] ; + char pack[cdb_datalen(newc) + 1] ; char const *p = pack ; - if (cdb_read(&newc, pack, cdb_datalen(&newc), cdb_datapos(&newc)) < 0) + if (cdb_read(newc, pack, cdb_datalen(newc), cdb_datapos(newc)) < 0) strerr_diefu3sys(111, "read ", newfn, "/resolve.cdb") ; if (len == 1) oldstate[i] |= 8 ; /* atomic or singleton bundle */ while (len--) @@ -154,6 +171,18 @@ static inline void fill_convtable_and_flags (unsigned char *conversion_table, un } } +} + +static inline void stuff_with_newc (int fdnewc, char const *newfn, unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, s6rc_db_t const *olddb, s6rc_db_t const *newdb) +{ + cdb_t newc = CDB_ZERO ; + int newfdres = open_readatb(fdnewc, "resolve.cdb") ; + if (newfdres < 0) strerr_diefu3sys(111, "open ", newfn, "/compiled/resolve.cdb") ; + if (!cdb_init_map(&newc, newfdres, 1)) + strerr_diefu3sys(111, "cdb_init ", newfn, "/compiled/resolve.cdb") ; + + fill_convtable_and_flags(conversion_table, oldstate, newstate, namedata, nameindex, &newc, newfn, olddb, newdb) ; + cdb_free(&newc) ; close(newfdres) ; } @@ -183,17 +212,20 @@ static inline void adjust_newalreadyup (unsigned char const *oldstate, unsigned } } -static void compute_transitions (unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, unsigned char *newstate, int fdnewc, char const *newfn, s6rc_db_t const *newdb) +static void compute_transitions (char const *convfile, unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, unsigned char *newstate, int fdnewc, char const *newfn, s6rc_db_t const *newdb) { unsigned int oldn = olddb->nshort + olddb->nlong ; unsigned int newn = newdb->nshort + newdb->nlong ; unsigned char conversion_table[oldn * bitarray_div8(newn)] ; + unsigned int oldpairings[olddb->nlong] ; + unsigned int newpairings[newdb->nlong] ; byte_zero(conversion_table, oldn * bitarray_div8(newn)) ; { stralloc namedata = STRALLOC_ZERO ; unsigned int nameindex[oldn] ; - parse_conversion_file(&namedata, nameindex, oldstate, fdoldc, olddb) ; - fill_convtable_and_flags(conversion_table, oldstate, newstate, namedata.s, nameindex, fdnewc, newfn, olddb, newdb) ; + + stuff_with_oldc(oldstate, fdoldc, olddb, convfile, nameindex, &namedata) ; + stuff_with_newc(fdnewc, newfn, conversion_table, oldstate, newstate, namedata.s, nameindex, olddb, newdb) ; stralloc_free(&namedata) ; } adjust_newwantup(oldstate, oldn, newstate, newn, conversion_table) ; @@ -201,6 +233,11 @@ static void compute_transitions (unsigned char *oldstate, int fdoldc, s6rc_db_t adjust_newalreadyup(oldstate, oldn, newstate, newn, conversion_table) ; } + + + /* Service directory replacement */ + + static int safe_servicedir_update (char const *dst, char const *src, int h) { unsigned int dstlen = str_len(dst) ; @@ -252,8 +289,9 @@ static int safe_servicedir_update (char const *dst, char const *src, int h) byte_copy(dstfn + dstlen + 1, 4, "run") ; if (!hiercopy(srcfn, dstfn)) goto err ; byte_copy(srcfn + srclen + 1, 4, "run") ; - byte_copy(dstfn + dstlen + 1, 4, "finish") ; - hiercopy(srcfn, dstfn) ; + byte_copy(dstfn + dstlen + 1, 7, "finish") ; + byte_copy(tmpfn + dstlen + 1, 11, "finish.new") ; + if (hiercopy(srcfn, tmpfn) && rename(tmpfn, dstfn) < 0) goto err ; if (h) { byte_copy(dstfn + dstlen + 1, 5, "down") ; @@ -302,6 +340,11 @@ static inline void update_servicedirs (unsigned char const *oldstate, unsigned i { } + + + /* The update itself. */ + + static inline void update_state_and_compiled (unsigned char const *newstate, unsigned int newn, char const *newcompiled) { char fn[livelen + 14] ; @@ -346,6 +389,7 @@ static void fill_tfmt (char *tfmt, tain_t const *deadline) int main (int argc, char const *const *argv, char const *const *envp) { + char const *convfile = "/dev/null" ; tain_t deadline ; int dryrun = 0 ; PROG = "s6-rc-update" ; @@ -355,7 +399,7 @@ int main (int argc, char const *const *argv, char const *const *envp) subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { - register int opt = subgetopt_r(argc, argv, "v:t:nl:", &l) ; + register int opt = subgetopt_r(argc, argv, "v:t:nl:f:", &l) ; if (opt == -1) break ; switch (opt) { @@ -363,6 +407,7 @@ int main (int argc, char const *const *argv, char const *const *envp) case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; case 'n' : dryrun = 1 ; break ; case 'l' : live = l.arg ; livelen = str_len(live) ; break ; + case 'f' : convfile = l.arg ; break ; default : dieusage() ; } } @@ -464,7 +509,7 @@ int main (int argc, char const *const *argv, char const *const *envp) /* Read the conversion file and compute what to do */ if (verbosity >= 2) strerr_warni1x("computing state adjustments") ; - compute_transitions(oldstate, fdoldc, &olddb, newstate, fdnewc, argv[0], &newdb) ; + compute_transitions(convfile, oldstate, fdoldc, &olddb, newstate, fdnewc, argv[0], &newdb) ; tain_now_g() ; if (!tain_future(&deadline)) strerr_dief1x(1, "timed out") ; diff --git a/src/s6-rc/s6-rc.c b/src/s6-rc/s6-rc.c index 2cb4caa..db30690 100644 --- a/src/s6-rc/s6-rc.c +++ b/src/s6-rc/s6-rc.c @@ -121,7 +121,7 @@ static pid_t start_oneshot (unsigned int i, int h) static pid_t start_longrun (unsigned int i, int h) { - unsigned int svdlen = str_len(db->string + db->services[i].x.longrun.servicedir) ; + unsigned int svdlen = str_len(db->string + db->services[i].name) ; unsigned int m = 0 ; char fmt[UINT32_FMT] ; char vfmt[UINT_FMT] ; @@ -129,7 +129,7 @@ static pid_t start_longrun (unsigned int i, int h) char const *newargv[7 + !!dryrun[0] * 6] ; byte_copy(servicefn, livelen, live) ; byte_copy(servicefn + livelen, 9, "/scandir/") ; - byte_copy(servicefn + livelen + 9, svdlen, db->string + db->services[i].x.longrun.servicedir) ; + byte_copy(servicefn + livelen + 9, svdlen, db->string + db->services[i].name) ; if (h) { byte_copy(servicefn + livelen + 9 + svdlen, 17, "/notification-fd") ; @@ -166,11 +166,11 @@ static void success_longrun (unsigned int i, int h) { if (!dryrun[0]) { - unsigned int svdlen = str_len(db->string + db->services[i].x.longrun.servicedir) ; + unsigned int svdlen = str_len(db->string + db->services[i].name) ; char fn[livelen + svdlen + 15] ; byte_copy(fn, livelen, live) ; byte_copy(fn + livelen, 9, "/scandir/") ; - byte_copy(fn + livelen + 9, svdlen, db->string + db->services[i].x.longrun.servicedir) ; + byte_copy(fn + livelen + 9, svdlen, db->string + db->services[i].name) ; byte_copy(fn + livelen + 9 + svdlen, 6, "/down") ; if (h) { |