summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-07-31 23:10:55 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-07-31 23:10:55 +0000
commit3cae993e993524e7b1aa7fe4f3a4446c76d8e2ee (patch)
treedb1d982111c004b6cac0f27c8a306a7962013234
parent37868cbc2525294d0ec7cd77be02e144080eeffa (diff)
downloads6-rc-3cae993e993524e7b1aa7fe4f3a4446c76d8e2ee.tar.xz
working on s6-rc-update, minor fixes all around
-rw-r--r--package/deps.mak4
-rw-r--r--src/s6-rc/deps-exe/s6-rc-update1
-rw-r--r--src/s6-rc/s6-rc-db.c18
-rw-r--r--src/s6-rc/s6-rc-update.c402
-rw-r--r--src/s6-rc/s6-rc.c55
5 files changed, 440 insertions, 40 deletions
diff --git a/package/deps.mak b/package/deps.mak
index 520f9a3..a5d7b1d 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -14,7 +14,7 @@ src/s6-rc/s6-rc-compile.o src/s6-rc/s6-rc-compile.lo: src/s6-rc/s6-rc-compile.c
src/s6-rc/s6-rc-db.o src/s6-rc/s6-rc-db.lo: src/s6-rc/s6-rc-db.c src/include/s6-rc/s6rc.h
src/s6-rc/s6-rc-dryrun.o src/s6-rc/s6-rc-dryrun.lo: src/s6-rc/s6-rc-dryrun.c
src/s6-rc/s6-rc-init.o src/s6-rc/s6-rc-init.lo: src/s6-rc/s6-rc-init.c src/include/s6-rc/s6rc.h
-src/s6-rc/s6-rc-update.o src/s6-rc/s6-rc-update.lo: src/s6-rc/s6-rc-update.c src/include/s6-rc/s6rc-constants.h
+src/s6-rc/s6-rc-update.o src/s6-rc/s6-rc-update.lo: src/s6-rc/s6-rc-update.c src/include/s6-rc/config.h src/include/s6-rc/s6rc.h
src/s6-rc/s6-rc.o src/s6-rc/s6-rc.lo: src/s6-rc/s6-rc.c src/include/s6-rc/config.h src/include/s6-rc/s6rc.h
libs6rc.a: src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_graph_closure.o
@@ -30,4 +30,4 @@ s6-rc-dryrun: src/s6-rc/s6-rc-dryrun.o -lskarnet
s6-rc-init: private EXTRA_LIBS := ${TAINNOW_LIB} ${SOCKET_LIB}
s6-rc-init: src/s6-rc/s6-rc-init.o ${LIBS6RC} -ls6 -lskarnet
s6-rc-update: private EXTRA_LIBS := ${TAINNOW_LIB}
-s6-rc-update: src/s6-rc/s6-rc-update.o ${LIBS6RC} -ls6 -lskarnet
+s6-rc-update: src/s6-rc/s6-rc-update.o ${LIBS6RC} -ls6 -lexecline -lskarnet
diff --git a/src/s6-rc/deps-exe/s6-rc-update b/src/s6-rc/deps-exe/s6-rc-update
index b76070e..ba32165 100644
--- a/src/s6-rc/deps-exe/s6-rc-update
+++ b/src/s6-rc/deps-exe/s6-rc-update
@@ -1,4 +1,5 @@
${LIBS6RC}
-ls6
+-lexecline
-lskarnet
${TAINNOW_LIB}
diff --git a/src/s6-rc/s6-rc-db.c b/src/s6-rc/s6-rc-db.c
index 5d0493c..aeaff76 100644
--- a/src/s6-rc/s6-rc-db.c
+++ b/src/s6-rc/s6-rc-db.c
@@ -38,7 +38,7 @@ static void print_bundle_contents (char const *name)
strerr_diefu3sys(111, "cdb_init ", compiled, "/resolve.cdb") ;
r = cdb_find(&c, name, str_len(name)) ;
if (r < 0) strerr_diefu3sys(111, "read ", compiled, "/resolve.cdb") ;
- if (!r) strerr_dief3x(1, name, " is not a valid identifier in ", compiled) ;
+ if (!r) strerr_dief3x(3, name, " is not a valid identifier in ", compiled) ;
if (cdb_datalen(&c) == 4)
{
uint32 x ;
@@ -49,7 +49,7 @@ static void print_bundle_contents (char const *name)
if (x >= db->nshort + db->nlong)
strerr_dief2x(4, "invalid database in ", compiled) ;
if (!str_diff(name, db->string + db->services[x].name))
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " represents an atomic service") ;
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " represents an atomic service") ;
if (buffer_puts(buffer_1, db->string + db->services[x].name) < 0
|| buffer_put(buffer_1, "\n", 1) < 0)
strerr_diefu1sys(111, "write to stdout") ;
@@ -144,7 +144,7 @@ static unsigned int resolve_service (char const *name)
strerr_diefu3sys(111, "cdb_init ", compiled, "/resolve.cdb") ;
r = cdb_find(&c, name, str_len(name)) ;
if (r < 0) strerr_diefu3sys(111, "read ", compiled, "/resolve.cdb") ;
- if (!r) strerr_dief3x(1, name, " is not a valid identifier in ", compiled) ;
+ if (!r) strerr_dief3x(3, name, " is not a valid identifier in ", compiled) ;
if (cdb_datalen(&c) != 4) return db->nshort + db->nlong ;
if (cdb_read(&c, pack, 4, cdb_datapos(&c)) < 0)
strerr_diefu3sys(111, "cdb_read ", compiled, "/resolve.cdb") ;
@@ -173,7 +173,7 @@ static void print_timeout (char const *name, int h)
unsigned int len ;
char fmt[UINT32_FMT] ;
if (n >= db->nshort + db->nlong)
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
len = uint32_fmt(fmt, db->services[n].timeout[h]) ;
fmt[len++] = '\n' ;
if (buffer_putflush(buffer_1, fmt, len) < 0)
@@ -184,7 +184,7 @@ static void print_servicedir (char const *name)
{
unsigned int n = resolve_service(name) ;
if (n >= db->nlong)
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " does not represent a longrun service") ;
+ 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") ;
@@ -196,9 +196,9 @@ static void print_script (char const *name, int h)
char const *const *argv ;
unsigned int n = resolve_service(name) ;
if (n >= db->nshort + db->nlong)
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
if (n < db->nlong)
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " represents a longrun service") ;
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " represents a longrun service") ;
argv = db->argvs + db->services[n].x.oneshot.argv[h] ;
argc = db->services[n].x.oneshot.argc[h] ;
while (argc--)
@@ -214,7 +214,7 @@ static inline void print_flags (char const *name)
unsigned int n = resolve_service(name) ;
char fmt[9] = "00000000\n" ;
if (n >= db->nshort + db->nlong)
- strerr_dief5x(1, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " represents a bundle") ;
uint320_xfmt(fmt, db->services[n].flags, 8) ;
if (buffer_putflush(buffer_1, fmt, 9) < 0)
strerr_diefu1sys(111, "write to stdout") ;
@@ -234,7 +234,7 @@ static void print_union (char const *const *argv, int h, int isdeps, int doclosu
{
register int r = cdb_find(&c, *argv, str_len(*argv)) ;
if (r < 0) strerr_diefu3sys(111, "read ", compiled, "/resolve.cdb") ;
- if (!r) strerr_dief3x(1, *argv, " is not a valid identifier in ", compiled) ;
+ if (!r) strerr_dief3x(3, *argv, " is not a valid identifier in ", compiled) ;
{
unsigned int len = cdb_datalen(&c) >> 2 ;
char pack[cdb_datalen(&c) + 1] ;
diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c
index 7e9af38..059bc84 100644
--- a/src/s6-rc/s6-rc-update.c
+++ b/src/s6-rc/s6-rc-update.c
@@ -1,22 +1,32 @@
/* ISC license. */
+#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint.h>
#include <skalibs/bytestr.h>
#include <skalibs/sgetopt.h>
#include <skalibs/strerr2.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/cdb.h>
#include <skalibs/stralloc.h>
#include <skalibs/djbunix.h>
#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
+#include <execline/execline.h>
#include <s6/s6-supervise.h>
-#include <s6-rc/s6rc-constants.h>
+#include <s6-rc/config.h>
+#include <s6-rc/s6rc.h>
-#define USAGE "s6-rc-update [ -l live ]"
+#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] newdb"
#define dieusage() strerr_dieusage(100, USAGE)
#define dienomem() strerr_diefu1sys(111, "build string") ;
static char const *live = S6RC_LIVE_BASE ;
+static unsigned int verbosity = 1 ;
static int safe_servicedir_update (char const *dst, char const *src, int h)
{
@@ -115,8 +125,394 @@ static int servicedir_name_change (char const *live, char const *oldname, char c
return 1 ;
}
-int main (int argc, char const *const *argv)
+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 ;
+ unsigned int oldn = olddb->nshort + olddb->nlong ;
+ unsigned int max ;
+ register int r ;
+ if (!stralloc_readyplus(sa, slen)) dienomem() ;
+ sa->len += slen ;
+ r = el_parse_from_string(sa, s) ;
+ switch (r)
+ {
+ case -1 : dienomem() ;
+ case -2 : strerr_dief2x(100, "syntax error in conversion file: ", s) ;
+ case -3 : strerr_dief2x(100, "mismatched braces in conversion file: ", s) ;
+ default : break ;
+ }
+ max = sa->len ;
+ sa->len = base ;
+ if (r >= 2)
+ {
+ char pack[4] ;
+ uint32 x ;
+ unsigned int cur ;
+ int r = cdb_find(oldc, sa->s + base + slen, str_len(sa->s + base + slen)) ;
+ if (r < 0) strerr_diefu3sys(111, "read ", live, "/compiled/resolve.cdb") ;
+ if (!r) strerr_dief5x(3, "unknown identifier in ", live, "/compiled/resolve.cdb", ": ", sa->s + base + slen) ;
+ if (cdb_datalen(oldc) != 4) strerr_dief5x(5, "identifier ", sa->s + base + slen, " does not represent an atomic service in ", live, "/compiled") ;
+ if (cdb_read(oldc, pack, 4, cdb_datapos(oldc)) < 0)
+ strerr_diefu3sys(111, "read ", live, "/compiled/resolve.cdb") ;
+ uint32_unpack_big(pack, &x) ;
+ if (x >= oldn) strerr_dief3x(4, "invalid database in ", live, "/compiled") ;
+ cur = base + slen + str_len(sa->s + base + slen) ;
+
+ }
+}
+
+static inline void parse_conversion_file (stralloc *sa, unsigned int *newnames, unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb)
+{
+ 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") ;
+
+ for (;;)
+ {
+ register int r = skagetln(buffer_0, &satmp, '\n') ;
+ if (!r) break ;
+ if (r < 0)
+ {
+ if (errno != EPIPE) strerr_diefu1sys(111, "read from stdin") ;
+ 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) ;
+ satmp.len = base ;
+ }
+
+ satmp.len = base ;
+ 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)
+{
+ 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)) ;
+ if (r < 0) strerr_diefu3sys(111, "read ", newfn, "/resolve.cdb") ;
+ if (!r)
+ {
+ oldstate[i] |= 2 ; /* disappeared -> want down */
+ continue ;
+ }
+ if (cdb_datalen(&newc) & 3)
+ strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ;
+ 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 const *p = pack ;
+ 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--)
+ {
+ uint32 x ;
+ uint32_unpack_big(p, &x) ; p += 4 ;
+ if (x >= newn)
+ strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ;
+ if (newstate[x] & 4)
+ strerr_dief4x(1, "bad conversion file: new service ", newdb->string + newdb->services[x].name, " is a target for more than one conversion, including old service ", olddb->string + olddb->services[i].name) ;
+ newstate[x] |= 4 ;
+ bitarray_set(conversion_table + i * bitarray_div8(newn), x) ;
+ }
+ }
+ }
+
+ cdb_free(&newc) ;
+ close(newfdres) ;
+}
+
+static inline void adjust_newwantup (unsigned char *oldstate, unsigned int oldn, unsigned char *newstate, unsigned int newn, unsigned char const *conversion_table)
+{
+ unsigned int i = oldn ;
+ while (i--) if (oldstate[i] & 1)
+ {
+ register unsigned int j = newn ;
+ if (!(oldstate[i] & 8) || (oldstate[i] & 4)) oldstate[i] |= 34 ;
+ while (j--) if (bitarray_peek(conversion_table + i * bitarray_div8(newn), j)) newstate[j] |= 3 ;
+ }
+}
+
+static inline void adjust_newalreadyup (unsigned char const *oldstate, unsigned int oldn, unsigned char *newstate, unsigned int newn, unsigned char const *conversion_table)
+{
+ unsigned int i = oldn ;
+ while (i--) if (oldstate[i] & 32)
+ {
+ register unsigned int j = newn ;
+ while (j--) if (bitarray_peek(conversion_table + i * bitarray_div8(newn), j))
+ {
+ newstate[j] &= 254 ;
+ newstate[j] |= 2 ;
+ }
+ }
+}
+
+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)
+{
+ unsigned int oldn = olddb->nshort + olddb->nlong ;
+ unsigned int newn = newdb->nshort + newdb->nlong ;
+ unsigned char conversion_table[oldn * bitarray_div8(newn)] ;
+ 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) ;
+ stralloc_free(&namedata) ;
+ }
+ adjust_newwantup(oldstate, oldn, newstate, newn, conversion_table) ;
+ s6rc_graph_closure(olddb, oldstate, 5, 0) ;
+ adjust_newalreadyup(oldstate, oldn, newstate, newn, conversion_table) ;
+}
+
+static unsigned int want_count (unsigned char const *state, unsigned int n)
+{
+ unsigned int count = 0, i = n ;
+ while (i--) if (state[i] & 2) count++ ;
+ return count ;
+}
+
+static void fill_tfmt (char *tfmt, tain_t const *deadline)
+{
+ int t ;
+ tain_t tto ;
+ tain_sub(&tto, deadline, &STAMP) ;
+ t = tain_to_millisecs(&tto) ;
+ if (!t) t = 1 ;
+ else if (t < 0) t = 0 ;
+ tfmt[uint_fmt(tfmt, t)] = 0 ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ tain_t deadline ;
+ char const *live = S6RC_LIVE_BASE ;
+ unsigned int livelen ;
+ int dryrun = 0 ;
PROG = "s6-rc-update" ;
strerr_dief1x(100, "this utility has not been written yet.") ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "v:t:nl:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+ case 'n' : dryrun = 1 ; break ;
+ case 'l' : live = l.arg ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+ if (argc < 2) dieusage() ;
+
+ livelen = str_len(live) ;
+
+ {
+ int livelock ;
+ int fdoldc, fdnewc ;
+ s6rc_db_t olddb, newdb ;
+ unsigned int oldn, oldm, newn, newm ;
+ char dbfn[livelen + 10] ;
+
+ if (!tain_now_g())
+ strerr_warnwu1x("get correct TAI time. (Do you have a valid leap seconds file?)") ;
+ tain_add_g(&deadline, &deadline) ;
+
+
+ /* Take the live lock */
+
+ byte_copy(dbfn, livelen, live) ;
+ byte_copy(dbfn + livelen, 6, "/lock") ;
+ livelock = open_write(dbfn) ;
+ if (livelock < 0) strerr_diefu2sys(111, "open ", dbfn) ;
+ if (coe(livelock) < 0) strerr_diefu2sys(111, "coe ", dbfn) ;
+ if (lock_ex(livelock) < 0) strerr_diefu2sys(111, "lock ", dbfn) ;
+
+
+ /* Read the sizes of the compiled dbs */
+
+ byte_copy(dbfn + livelen + 1, 9, "compiled") ;
+ fdoldc = open_readb(dbfn) ;
+ if (!s6rc_db_read_sizes(fdoldc, &olddb))
+ strerr_diefu3sys(111, "read ", dbfn, "/n") ;
+ oldn = olddb.nshort + olddb.nlong ;
+ oldm = bitarray_div8(oldn) ;
+ fdnewc = open_readb(argv[0]) ;
+ if (!s6rc_db_read_sizes(fdnewc, &newdb))
+ strerr_diefu3sys(111, "read ", argv[0], "/n") ;
+ newn = newdb.nshort + newdb.nlong ;
+ newm = bitarray_div8(newn) ;
+
+
+ /* Allocate enough stack for the dbs */
+
+ {
+ pid_t pid ;
+ s6rc_service_t oldserviceblob[oldn] ;
+ char const *oldargvblob[olddb.nargvs] ;
+ uint32 olddepsblob[olddb.ndeps << 1] ;
+ char oldstringblob[olddb.stringlen] ;
+ s6rc_service_t newserviceblob[newn] ;
+ char const *newargvblob[newdb.nargvs] ;
+ uint32 newdepsblob[newdb.ndeps << 1] ;
+ char newstringblob[newdb.stringlen] ;
+ unsigned char oldstate[oldn] ;
+ unsigned char newstate[newn] ;
+ register int r ;
+
+ olddb.services = oldserviceblob ;
+ olddb.argvs = oldargvblob ;
+ olddb.deps = olddepsblob ;
+ olddb.string = oldstringblob ;
+ newdb.services = newserviceblob ;
+ newdb.argvs = newargvblob ;
+ newdb.deps = newdepsblob ;
+ newdb.string = newstringblob ;
+
+
+ /* Read the dbs */
+
+ r = s6rc_db_read(fdoldc, &olddb) ;
+ if (r < 0) strerr_diefu3sys(111, "read ", dbfn, "/db") ;
+ if (!r) strerr_dief3x(4, "invalid service database in ", dbfn, "/db") ;
+ r = s6rc_db_read(fdnewc, &newdb) ;
+ if (r < 0) strerr_diefu3sys(111, "read ", argv[0], "/db") ;
+ if (!r) strerr_dief3x(4, "invalid service database in ", argv[0], "/db") ;
+
+
+ /* Initial state */
+
+ byte_zero(newstate, newn) ;
+ byte_copy(dbfn + livelen + 1, 6, "state") ;
+ {
+ r = openreadnclose(dbfn, (char *)oldstate, oldn) ;
+ if (r != oldn) strerr_diefu2sys(111, "read ", dbfn) ;
+ {
+ register unsigned int i = oldn ;
+ while (i--) oldstate[i] &= 1 ;
+ }
+ }
+
+
+ /* 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) ;
+ tain_now_g() ;
+ if (!tain_future(&deadline)) strerr_dief1x(1, "timed out") ;
+
+
+ /* Down transition */
+
+ {
+ char const *newargv[12 + (dryrun * 5) + want_count(oldstate, oldn)] ;
+ unsigned int m = 0, i = oldn ;
+ int wstat ;
+ char vfmt[UINT_FMT] ;
+ char tfmt[UINT_FMT] ;
+ vfmt[uint_fmt(vfmt, verbosity)] = 0 ;
+ fill_tfmt(tfmt, &deadline) ;
+ if (dryrun)
+ {
+ newargv[m++] = S6RC_BINPREFIX "s6-rc-dryrun" ;
+ newargv[m++] = "-v" ;
+ newargv[m++] = vfmt ;
+ newargv[m++] = "-t0" ;
+ newargv[m++] = "--" ;
+ }
+ newargv[m++] = S6RC_BINPREFIX "s6-rc" ;
+ newargv[m++] = "-v" ;
+ newargv[m++] = vfmt ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = tfmt ;
+ newargv[m++] = "-l" ;
+ newargv[m++] = live ;
+ newargv[m++] = "-X" ;
+ newargv[m++] = "-d" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = "change" ;
+ while (i--) if (oldstate[i] & 2)
+ newargv[m++] = olddb.string + olddb.services[i].name ;
+ newargv[m++] = 0 ;
+ if (verbosity >= 2)
+ strerr_warni1x("stopping services in the old database") ;
+ pid = child_spawn0(newargv[0], newargv, envp) ;
+ if (!pid) strerr_diefu2sys(111, "spawn ", newargv[0]) ;
+ if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "waitpid") ;
+ if (WIFSIGNALED(wstat) || WEXITSTATUS(wstat))
+ strerr_diefu1sys(wait_estatus(wstat), "first s6-rc invocation failed") ;
+ }
+
+
+ /* Service directory and state switch */
+
+ if (verbosity >= 2)
+ strerr_warni1x("updating state and service directories") ;
+
+
+ /* Up transition */
+
+ if (!tain_future(&deadline)) strerr_dief1x(1, "timed out") ;
+
+ {
+ char const *newargv[12 + (dryrun * 5) + want_count(newstate, newn)] ;
+ unsigned int m = 0, i = newn ;
+ char vfmt[UINT_FMT] ;
+ char tfmt[UINT_FMT] ;
+ vfmt[uint_fmt(vfmt, verbosity)] = 0 ;
+ fill_tfmt(tfmt, &deadline) ;
+ if (dryrun)
+ {
+ newargv[m++] = S6RC_BINPREFIX "s6-rc-dryrun" ;
+ newargv[m++] = "-v" ;
+ newargv[m++] = vfmt ;
+ newargv[m++] = "-t0" ;
+ newargv[m++] = "--" ;
+ }
+ newargv[m++] = S6RC_BINPREFIX "s6-rc" ;
+ newargv[m++] = "-v" ;
+ newargv[m++] = vfmt ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = tfmt ;
+ newargv[m++] = "-l" ;
+ newargv[m++] = live ;
+ newargv[m++] = "-aX" ;
+ newargv[m++] = "-u" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = "change" ;
+ while (i--) if (newstate[i] & 2)
+ newargv[m++] = newdb.string + newdb.services[i].name ;
+ newargv[m++] = 0 ;
+ if (verbosity >= 2)
+ strerr_warni1x("starting services in the new database") ;
+ pathexec_run(newargv[0], newargv, envp) ;
+ strerr_dieexec(111, newargv[0]) ;
+ }
+ }
+ }
}
diff --git a/src/s6-rc/s6-rc.c b/src/s6-rc/s6-rc.c
index 1f1ab3f..2cb4caa 100644
--- a/src/s6-rc/s6-rc.c
+++ b/src/s6-rc/s6-rc.c
@@ -372,7 +372,7 @@ static inline void print_help (void)
int main (int argc, char const *const *argv)
{
- int up = 1, prune = 0, selectlive = 0 ;
+ int up = 1, prune = 0, selectlive = 0, takelock = 1 ;
unsigned int what ;
PROG = "s6-rc" ;
{
@@ -380,7 +380,7 @@ int main (int argc, char const *const *argv)
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "v:n:t:l:udpa", &l) ;
+ register int opt = subgetopt_r(argc, argv, "v:n:t:l:udpaX", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -398,6 +398,7 @@ int main (int argc, char const *const *argv)
case 'd' : up = 0 ; break ;
case 'p' : prune = 1 ; break ;
case 'a' : selectlive = 1 ; break ;
+ case 'X' : takelock = 0 ; break ;
default : dieusage() ;
}
}
@@ -416,7 +417,6 @@ int main (int argc, char const *const *argv)
livelen = str_len(live) ;
{
- int livelock ;
int fdcompiled ;
s6rc_db_t dbblob ;
char dbfn[livelen + 10] ;
@@ -425,18 +425,23 @@ int main (int argc, char const *const *argv)
/* Take the live lock */
- byte_copy(dbfn, livelen, live) ;
- byte_copy(dbfn + livelen, 6, "/lock") ;
- livelock = open_write(dbfn) ;
- if (livelock < 0) strerr_diefu2sys(111, "open ", dbfn) ;
- if (coe(livelock) < 0) strerr_diefu2sys(111, "coe ", dbfn) ;
- if ((what < 3 ? lock_sh(livelock) : lock_ex(livelock)) < 0)
- strerr_diefu2sys(111, "lock ", dbfn) ;
+ if (takelock)
+ {
+ int livelock ;
+ byte_copy(dbfn, livelen, live) ;
+ byte_copy(dbfn + livelen, 6, "/lock") ;
+ livelock = open_write(dbfn) ;
+ if (livelock < 0) strerr_diefu2sys(111, "open ", dbfn) ;
+ if (coe(livelock) < 0) strerr_diefu2sys(111, "coe ", dbfn) ;
+ if ((what < 3 ? lock_sh(livelock) : lock_ex(livelock)) < 0)
+ strerr_diefu2sys(111, "lock ", dbfn) ;
+ /* livelock leaks, but we don't care */
+ }
/* Read the sizes of the compiled db */
- byte_copy(dbfn + livelen + 1, 9, "compiled") ;
+ byte_copy(dbfn + livelen, 10, "/compiled") ;
fdcompiled = open_readb(dbfn) ;
if (!s6rc_db_read_sizes(fdcompiled, &dbblob))
strerr_diefu3sys(111, "read ", dbfn, "/n") ;
@@ -459,7 +464,19 @@ int main (int argc, char const *const *argv)
dbblob.deps = depsblob ;
dbblob.string = stringblob ;
state = stateblob ;
- byte_zero(state, n) ;
+
+
+ /* Read live state in bit 0 of state */
+
+ byte_copy(dbfn + livelen + 1, 6, "state") ;
+ {
+ r = openreadnclose(dbfn, (char *)state, n) ;
+ if (r != n) strerr_diefu2sys(111, "read ", dbfn) ;
+ {
+ register unsigned int i = n ;
+ while (i--) state[i] &= 1 ;
+ }
+ }
/* Read the db from the file */
@@ -511,20 +528,6 @@ int main (int argc, char const *const *argv)
close(fdcompiled) ;
- /* Read live state in bit 0 of state */
-
- byte_copy(dbfn + livelen + 1, 6, "state") ;
- {
- char tmpstate[n] ;
- r = openreadnclose(dbfn, tmpstate, n) ;
- if (r != n) strerr_diefu2sys(111, "read ", dbfn) ;
- {
- register unsigned int i = n ;
- while (i--) if (tmpstate[i]) state[i] |= 1 ;
- }
- }
-
-
/* Add live state to selection */
if (selectlive)