summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-12-04 18:11:24 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-12-04 18:11:24 +0000
commit85e2821400dafd4afc4b75da331d2fd2129c5238 (patch)
treec662d7e1b69cf25b2a25122cfe440f03b73e3687
parent9492b12a6ca520bbcb191879a5df77e36fede8f3 (diff)
downloads6-rc-85e2821400dafd4afc4b75da331d2fd2129c5238.tar.xz
Add s6-rc-format-upgrade
-rw-r--r--.gitignore1
-rw-r--r--doc/index.html6
-rw-r--r--doc/s6-rc-format-upgrade.html125
-rw-r--r--package/deps.mak2
-rw-r--r--package/targets.mak3
-rw-r--r--src/s6-rc/deps-exe/s6-rc-format-upgrade2
-rw-r--r--src/s6-rc/s6-rc-format-upgrade.c70
-rw-r--r--src/s6-rc/s6-rc-update.c19
8 files changed, 211 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 9713499..d06e759 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@
/s6-rc-update
/s6-rc-fdholder-filler
/s6-rc-oneshot-run
+/s6-rc-format-upgrade
diff --git a/doc/index.html b/doc/index.html
index ee06542..9ce7128 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -111,6 +111,12 @@ the previous versions of s6-rc and the current one. </li>
<li> <a href="s6-rc-update.html">The <tt>s6-rc-update</tt> program</a> </li>
</ul>
+<h4> Upgrading from earlier s6-rc database formats </h4>
+
+<ul>
+ <li> <a href="s6-rc-format-upgrade.html">The <tt>s6-rc-format-upgrade</tt> program</a> </li>
+</ul>
+
<h4> Programs used internally </h4>
<ul>
diff --git a/doc/s6-rc-format-upgrade.html b/doc/s6-rc-format-upgrade.html
new file mode 100644
index 0000000..1b11e39
--- /dev/null
+++ b/doc/s6-rc-format-upgrade.html
@@ -0,0 +1,125 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-rc: the s6-rc-format-upgrade program</title>
+ <meta name="Description" content="s6-rc: the s6-rc-format-upgrade program" />
+ <meta name="Keywords" content="s6-rc command s6-rc-format-upgrade database format upgrade rc dependency state management services" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-rc</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-rc-format-upgrade program </h1>
+
+<p>
+ s6-rc-format-upgrade is a program that is normally used
+very rarely: when the s6-rc package is upgraded, some
+services are currently managed with s6-rc, and the database
+format has changed. This program transitions a live directory
+using a database with the old s6-rc format (the one being
+replaced) so that it uses a database with the new s6-rc format.
+</p>
+
+<p>
+ The point is to ensure a smooth transition between different
+versions of s6-rc without needing a reboot.
+</p>
+
+<p>
+ s6-rc-format-upgrade is very different from
+<a href="s6-rc-update.html">s6-rc-update</a> and does not
+duplicate its functionality:
+</p>
+
+<ul>
+ <li> <a href="s6-rc-update.html">s6-rc-update</a> updates a
+live directory to use a <em>different compiled database</em>,
+compiled from a different source, where services may have
+changed, be renamed, etc. But it can only handle databases
+with the format that it knows - the format created by the
+<a href="s6-rc-compile.html">s6-rc-compile</a> binary that
+comes in the same package as s6-rc-update. </li>
+ <li> s6-rc-format-upgrade is the opposite: it cannot handle
+service changes, it can only update a live directory to use
+a compiled database corresponding to the <em>same source</em>
+as the compiled database the live directory is currently
+using. But it will replace an obsolete compiled database with
+a compiled database that uses the new format (provided both
+compiled databases come from the same source, and have just been
+produced by invocation of different versions of
+<a href="s6-rc-compile.html">s6-rc-compile</a>), ensuring the
+s6-rc installation can live through database format changes. </li>
+</ul>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-rc-format-upgrade [ -v verbosity ] [ -l <em>live</em> ] [ -t <em>timeout</em> ] [ -b ] <em>newcompiled</em>
+</pre>
+
+<ul>
+ <li> <em>newcompiled</em> must be an absolute path. </li>
+ <li> s6-rc-format-upgrade expects to find a compiled service database
+with the <strong>new format</strong> in <em>compiled</em> </li>
+ <li> <em>newcompiled</em> <strong>must</strong> be compiled from
+the same source database as the current compiled database currently
+being used by <em>live</em>.
+ <li> s6-rc-format-upgrade then updates the live directory in <em>live</em>
+so it uses <em>newcompiled</em> as its compiled database. </li>
+ <li> On success, it exits 0. </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp;: be more or less
+verbose. Default is 1. </li>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if all
+operations have not completed after <em>timeout</em>
+milliseconds, complain and exit 1. </li>
+ <li> <tt>-l&nbsp;<em>live</em></tt>&nbsp;: Work with the live state in
+the <em>live</em> directory. Default is
+<tt>/run/s6-rc</tt>. The default can be changed at compile time by
+giving the <tt>--livedir=<em>live</em></tt> option to
+<tt>./configure</tt>. </li>
+ <li> <tt>-b</tt>&nbsp;: blocking lock. If <em>live</em> is currently
+being used by another program, s6-rc-format-upgrade will wait until that
+other program has released its lock on the directory, then proceed.
+By default, s6-rc-format-upgrade fails with an error message if the live
+directory is currently in use. </li>
+</ul>
+
+<h2> Typical usage </h2>
+
+<p>
+ s6-rc-format-upgrade is only necessary when the database format
+changes, which only happens when s6-rc's major version number
+(the third number from the right) changes. The correct order of
+operations is then the following:
+</p>
+
+<ul>
+ <li> Make sure your current compiled database is up-to-date
+with your source database. If it's not, update it, by invoking
+the <a href="s6-rc-compile.html">s6-rc-compile</a> and
+<a href="s6-rc-update.html">s6-rc-update</a> binaries from your
+<strong>old</strong> s6-rc installation, the ones that
+understand the old format. </li>
+ <li> From the same source, compile a new database with the new format,
+using the <a href="s6-rc-compile.html">s6-rc-compile</a> binary
+from the <strong>new</strong> s6-rc package. </li>
+ <li> Update your live directories with this new database, using
+s6-rc-format-upgrade. </li>
+ <li> You can now remove the old databases, and delete the old
+s6-rc package. </li>
+</ul>
+
+</body>
+</html>
diff --git a/package/deps.mak b/package/deps.mak
index e0d6a72..96e604c 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -54,6 +54,8 @@ s6-rc-dryrun: EXTRA_LIBS := ${TAINNOW_LIB}
s6-rc-dryrun: src/s6-rc/s6-rc-dryrun.o -lskarnet
s6-rc-fdholder-filler: EXTRA_LIBS := ${TAINNOW_LIB} ${SOCKET_LIB}
s6-rc-fdholder-filler: src/s6-rc/s6-rc-fdholder-filler.o -ls6 -lskarnet
+s6-rc-format-upgrade: EXTRA_LIBS :=
+s6-rc-format-upgrade: src/s6-rc/s6-rc-format-upgrade.o ${LIBS6RC} -lskarnet
s6-rc-init: EXTRA_LIBS := ${TAINNOW_LIB} ${SOCKET_LIB} ${SPAWN_LIB}
s6-rc-init: src/s6-rc/s6-rc-init.o ${LIBS6RC} -ls6 -lskarnet
s6-rc-oneshot-run: EXTRA_LIBS :=
diff --git a/package/targets.mak b/package/targets.mak
index 9573a5f..522b1e3 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -5,7 +5,8 @@ s6-rc-db \
s6-rc-bundle \
s6-rc-init \
s6-rc \
-s6-rc-update
+s6-rc-update \
+s6-rc-format-upgrade
LIBEXEC_TARGETS := \
s6-rc-fdholder-filler \
diff --git a/src/s6-rc/deps-exe/s6-rc-format-upgrade b/src/s6-rc/deps-exe/s6-rc-format-upgrade
new file mode 100644
index 0000000..152b051
--- /dev/null
+++ b/src/s6-rc/deps-exe/s6-rc-format-upgrade
@@ -0,0 +1,2 @@
+${LIBS6RC}
+-lskarnet
diff --git a/src/s6-rc/s6-rc-format-upgrade.c b/src/s6-rc/s6-rc-format-upgrade.c
new file mode 100644
index 0000000..3b399e3
--- /dev/null
+++ b/src/s6-rc/s6-rc-format-upgrade.c
@@ -0,0 +1,70 @@
+/* ISC license. */
+
+#include <string.h>
+#include <skalibs/types.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-transactional.h>
+#include <s6-rc/config.h>
+#include <s6-rc/s6rc.h>
+
+#define USAGE "s6-rc-format-upgrade [ -v verbosity ] [ -t timeout ] [ -l live ] [ -b ] newdb"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static unsigned int verbosity = 1 ;
+
+
+ /* This function will change if format changes become heavier */
+
+static inline void update_livedir (char const *live, char const *newcompiled, tain_t const *deadline)
+{
+ size_t livelen = strlen(live) ;
+ char cfn[livelen + 10] ;
+ memcpy(cfn, live, livelen) ;
+ memcpy(cfn + livelen, "/compiled", 10) ;
+ if (!atomic_symlink(newcompiled, cfn, PROG))
+ strerr_diefu4sys(111, "atomic_symlink ", cfn, " to ", newcompiled) ;
+}
+
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ tain_t deadline ;
+ char const *live = S6RC_LIVE_BASE ;
+ int blocking = 0 ;
+ int livelock ;
+ PROG = "s6-rc-format-upgrade" ;
+ {
+ unsigned int t = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "v:t:l:b", &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 'l' : live = l.arg ; break ;
+ case 'b' : blocking = 1 ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
+ }
+ if (!argc) dieusage() ;
+ if (argv[0][0] != '/')
+ strerr_dief2x(100, argv[0], " is not an absolute path") ;
+
+ tain_now_g() ;
+ tain_add_g(&deadline, &deadline) ;
+
+ if (!s6rc_lock(live, 2, &livelock, 0, 0, 0, blocking))
+ strerr_diefu2sys(111, "take lock on ", live) ;
+
+ update_livedir(live, argv[0], &deadline) ;
+ return 0 ;
+}
diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c
index dc3806b..0313f1e 100644
--- a/src/s6-rc/s6-rc-update.c
+++ b/src/s6-rc/s6-rc-update.c
@@ -1,6 +1,5 @@
/* ISC license. */
-#include <skalibs/nonposix.h> /* Solaris doesn't know mkdtemp() is POSIX */
#include <string.h>
#include <stdint.h>
#include <limits.h>
@@ -21,7 +20,6 @@
#include <skalibs/tai.h>
#include <skalibs/djbunix.h>
#include <skalibs/skamisc.h>
-#include <skalibs/webipc.h>
#include <skalibs/unix-transactional.h>
#include <execline/execline.h>
#include <s6/config.h>
@@ -516,31 +514,20 @@ static void fill_tfmt (char *tfmt, tain_t const *deadline)
static inline void update_fdholder (s6rc_db_t const *olddb, unsigned char const *oldstate, s6rc_db_t const *newdb, unsigned char const *newstate, unsigned int const *invimage, char const *const *envp, tain_t const *deadline)
{
- int fdsocket ;
s6_fdholder_t a = S6_FDHOLDER_ZERO ;
char fnsocket[livelen + sizeof("/servicedirs/" S6RC_FDHOLDER "/s")] ;
if (!(newstate[1] & 1)) return ;
memcpy(fnsocket, live, livelen) ;
memcpy(fnsocket + livelen, "/servicedirs/" S6RC_FDHOLDER "/s", sizeof("/servicedirs/" S6RC_FDHOLDER "/s")) ;
- fdsocket = ipc_stream_nb() ;
- if (fdsocket < 0) goto hammer ;
- if (!ipc_timed_connect_g(fdsocket, fnsocket, deadline))
- {
- if (errno == ETIMEDOUT) strerr_dief1x(2, "timed out during s6rc-fdholder update") ;
- else goto closehammer ;
- }
- s6_fdholder_init(&a, fdsocket) ;
+ if (!s6_fdholder_start_g(&a, fnsocket, deadline)) goto hammer ;
if (!delete_unused_pipes(&a, olddb, oldstate, deadline)) goto freehammer ;
if (!rename_pipes(&a, olddb, newdb, newstate, invimage, deadline)) goto freehammer ;
if (!create_new_pipes(&a, newdb, newstate, deadline)) goto freehammer ;
- s6_fdholder_free(&a) ;
- close(fdsocket) ;
+ s6_fdholder_end(&a) ;
return ;
freehammer:
- s6_fdholder_free(&a) ;
- closehammer:
- close(fdsocket) ;
+ s6_fdholder_end(&a) ;
hammer:
if (verbosity) strerr_warnwu1x("live update s6rc-fdholder - restarting it") ;
{