diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | doc/index.html | 6 | ||||
-rw-r--r-- | doc/s6-rc-format-upgrade.html | 125 | ||||
-rw-r--r-- | package/deps.mak | 2 | ||||
-rw-r--r-- | package/targets.mak | 3 | ||||
-rw-r--r-- | src/s6-rc/deps-exe/s6-rc-format-upgrade | 2 | ||||
-rw-r--r-- | src/s6-rc/s6-rc-format-upgrade.c | 70 | ||||
-rw-r--r-- | src/s6-rc/s6-rc-update.c | 19 |
8 files changed, 211 insertions, 17 deletions
@@ -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 <em>verbosity</em></tt> : be more or less +verbose. Default is 1. </li> + <li> <tt>-t <em>timeout</em></tt> : if all +operations have not completed after <em>timeout</em> +milliseconds, complain and exit 1. </li> + <li> <tt>-l <em>live</em></tt> : 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> : 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") ; { |