summaryrefslogtreecommitdiff
path: root/src/s6-rc/s6-rc-update.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/s6-rc/s6-rc-update.c')
-rw-r--r--src/s6-rc/s6-rc-update.c101
1 files changed, 73 insertions, 28 deletions
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") ;