summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-12-04 14:59:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-12-04 14:59:44 +0000
commit1f72ed3900db6b43ecbde097c83c4c5ddf9c9e38 (patch)
tree628a75700f4a7d82d11d51b7963d986deb13af29
parent2c44eb5822e7ab6281123290184df4542da5cdb1 (diff)
downloads6-rc-1f72ed3900db6b43ecbde097c83c4c5ddf9c9e38.tar.xz
Refactor s6-rc-init and s6-rc-upgrade around atomic_symlink and s6rc_livedir_create
-rw-r--r--doc/s6-rc-init.html4
-rw-r--r--package/deps.mak8
-rw-r--r--src/include/s6-rc/s6rc-utils.h1
-rw-r--r--src/libs6rc/deps-lib/s6rc1
-rw-r--r--src/libs6rc/s6rc_livedir_create.c50
-rw-r--r--src/s6-rc/s6-rc-init.c190
-rw-r--r--src/s6-rc/s6-rc-update.c118
7 files changed, 151 insertions, 221 deletions
diff --git a/doc/s6-rc-init.html b/doc/s6-rc-init.html
index 2e9c88c..0fe00ba 100644
--- a/doc/s6-rc-init.html
+++ b/doc/s6-rc-init.html
@@ -32,8 +32,8 @@ invocation of the
</pre>
<ul>
- <li> <em>compiled</em> (if the <tt>-d</tt> option hasn't been given),
-<em>live</em> and <em>scandir</em> must be absolute paths. </li>
+ <li> <em>compiled</em> (if the <tt>-d</tt> option hasn't been given)
+and <em>scandir</em> must be absolute paths. </li>
<li> s6-rc-init expects to find a <em>compiled service database</em>
in <em>compiled</em>. It expects to be able to create a directory
named <em>live</em>. It also expects that an instance of
diff --git a/package/deps.mak b/package/deps.mak
index 0cece4a..e0d6a72 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -11,6 +11,7 @@ src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read.lo: src/libs6rc/s6rc_db_read
src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_sizes.lo: src/libs6rc/s6rc_db_read_sizes.c src/include/s6-rc/s6rc-db.h
src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_db_read_uint32.lo: src/libs6rc/s6rc_db_read_uint32.c src/include/s6-rc/s6rc-db.h
src/libs6rc/s6rc_graph_closure.o src/libs6rc/s6rc_graph_closure.lo: src/libs6rc/s6rc_graph_closure.c src/include/s6-rc/s6rc-db.h src/include/s6-rc/s6rc-utils.h
+src/libs6rc/s6rc_livedir_create.o src/libs6rc/s6rc_livedir_create.lo: src/libs6rc/s6rc_livedir_create.c src/include/s6-rc/s6rc-utils.h
src/libs6rc/s6rc_livedir_prefix.o src/libs6rc/s6rc_livedir_prefix.lo: src/libs6rc/s6rc_livedir_prefix.c src/include/s6-rc/s6rc-utils.h
src/libs6rc/s6rc_livedir_prefixsize.o src/libs6rc/s6rc_livedir_prefixsize.lo: src/libs6rc/s6rc_livedir_prefixsize.c src/include/s6-rc/s6rc-utils.h
src/libs6rc/s6rc_lock.o src/libs6rc/s6rc_lock.lo: src/libs6rc/s6rc_lock.c src/include/s6-rc/s6rc-utils.h
@@ -28,18 +29,19 @@ 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/config.h 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-fdholder-filler.o src/s6-rc/s6-rc-fdholder-filler.lo: src/s6-rc/s6-rc-fdholder-filler.c
+src/s6-rc/s6-rc-format-upgrade.o src/s6-rc/s6-rc-format-upgrade.lo: src/s6-rc/s6-rc-format-upgrade.c src/include/s6-rc/config.h src/include/s6-rc/s6rc.h
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/config.h src/include/s6-rc/s6rc.h
src/s6-rc/s6-rc-oneshot-run.o src/s6-rc/s6-rc-oneshot-run.lo: src/s6-rc/s6-rc-oneshot-run.c src/include/s6-rc/config.h 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/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
ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
-libs6rc.a.xyzzy: src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_check_pipelines.o src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_graph_closure.o src/libs6rc/s6rc_livedir_prefix.o src/libs6rc/s6rc_livedir_prefixsize.o src/libs6rc/s6rc_lock.o src/libs6rc/s6rc_read_uint.o src/libs6rc/s6rc_sanitize_dir.o src/libs6rc/s6rc_servicedir_internal.o src/libs6rc/s6rc_servicedir_block.o src/libs6rc/s6rc_servicedir_unblock.o src/libs6rc/s6rc_servicedir_copy_offline.o src/libs6rc/s6rc_servicedir_copy_online.o src/libs6rc/s6rc_servicedir_manage.o src/libs6rc/s6rc_servicedir_unsupervise.o
+libs6rc.a.xyzzy: src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_check_pipelines.o src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_graph_closure.o src/libs6rc/s6rc_livedir_create.o src/libs6rc/s6rc_livedir_prefix.o src/libs6rc/s6rc_livedir_prefixsize.o src/libs6rc/s6rc_lock.o src/libs6rc/s6rc_read_uint.o src/libs6rc/s6rc_sanitize_dir.o src/libs6rc/s6rc_servicedir_internal.o src/libs6rc/s6rc_servicedir_block.o src/libs6rc/s6rc_servicedir_unblock.o src/libs6rc/s6rc_servicedir_copy_offline.o src/libs6rc/s6rc_servicedir_copy_online.o src/libs6rc/s6rc_servicedir_manage.o src/libs6rc/s6rc_servicedir_unsupervise.o
else
-libs6rc.a.xyzzy: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_check_pipelines.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_graph_closure.lo src/libs6rc/s6rc_livedir_prefix.lo src/libs6rc/s6rc_livedir_prefixsize.lo src/libs6rc/s6rc_lock.lo src/libs6rc/s6rc_read_uint.lo src/libs6rc/s6rc_sanitize_dir.lo src/libs6rc/s6rc_servicedir_internal.lo src/libs6rc/s6rc_servicedir_block.lo src/libs6rc/s6rc_servicedir_unblock.lo src/libs6rc/s6rc_servicedir_copy_offline.lo src/libs6rc/s6rc_servicedir_copy_online.lo src/libs6rc/s6rc_servicedir_manage.lo src/libs6rc/s6rc_servicedir_unsupervise.lo
+libs6rc.a.xyzzy: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_check_pipelines.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_graph_closure.lo src/libs6rc/s6rc_livedir_create.lo src/libs6rc/s6rc_livedir_prefix.lo src/libs6rc/s6rc_livedir_prefixsize.lo src/libs6rc/s6rc_lock.lo src/libs6rc/s6rc_read_uint.lo src/libs6rc/s6rc_sanitize_dir.lo src/libs6rc/s6rc_servicedir_internal.lo src/libs6rc/s6rc_servicedir_block.lo src/libs6rc/s6rc_servicedir_unblock.lo src/libs6rc/s6rc_servicedir_copy_offline.lo src/libs6rc/s6rc_servicedir_copy_online.lo src/libs6rc/s6rc_servicedir_manage.lo src/libs6rc/s6rc_servicedir_unsupervise.lo
endif
libs6rc.so.xyzzy: EXTRA_LIBS := -ls6 -lskarnet
-libs6rc.so.xyzzy: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_check_pipelines.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_graph_closure.lo src/libs6rc/s6rc_livedir_prefix.lo src/libs6rc/s6rc_livedir_prefixsize.lo src/libs6rc/s6rc_lock.lo src/libs6rc/s6rc_read_uint.lo src/libs6rc/s6rc_sanitize_dir.lo src/libs6rc/s6rc_servicedir_internal.lo src/libs6rc/s6rc_servicedir_block.lo src/libs6rc/s6rc_servicedir_unblock.lo src/libs6rc/s6rc_servicedir_copy_offline.lo src/libs6rc/s6rc_servicedir_copy_online.lo src/libs6rc/s6rc_servicedir_manage.lo src/libs6rc/s6rc_servicedir_unsupervise.lo
+libs6rc.so.xyzzy: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_check_pipelines.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_graph_closure.lo src/libs6rc/s6rc_livedir_create.lo src/libs6rc/s6rc_livedir_prefix.lo src/libs6rc/s6rc_livedir_prefixsize.lo src/libs6rc/s6rc_lock.lo src/libs6rc/s6rc_read_uint.lo src/libs6rc/s6rc_sanitize_dir.lo src/libs6rc/s6rc_servicedir_internal.lo src/libs6rc/s6rc_servicedir_block.lo src/libs6rc/s6rc_servicedir_unblock.lo src/libs6rc/s6rc_servicedir_copy_offline.lo src/libs6rc/s6rc_servicedir_copy_online.lo src/libs6rc/s6rc_servicedir_manage.lo src/libs6rc/s6rc_servicedir_unsupervise.lo
s6-rc: EXTRA_LIBS := ${TAINNOW_LIB} ${SPAWN_LIB}
s6-rc: src/s6-rc/s6-rc.o ${LIBS6RC} -ls6 -lskarnet
s6-rc-bundle: EXTRA_LIBS :=
diff --git a/src/include/s6-rc/s6rc-utils.h b/src/include/s6-rc/s6rc-utils.h
index b6cab0a..8f67920 100644
--- a/src/include/s6-rc/s6rc-utils.h
+++ b/src/include/s6-rc/s6rc-utils.h
@@ -14,5 +14,6 @@ extern int s6rc_sanitize_dir (stralloc *, char const *, size_t *) ;
extern int s6rc_livedir_prefixsize (char const *, size_t *) ;
extern ssize_t s6rc_livedir_prefix (char const *, char *, size_t) ;
+extern int s6rc_livedir_create (stralloc *, char const *, char const *, char const *, char const *, char const *, unsigned char const *, unsigned int, size_t *) ;
#endif
diff --git a/src/libs6rc/deps-lib/s6rc b/src/libs6rc/deps-lib/s6rc
index f42783b..52c220f 100644
--- a/src/libs6rc/deps-lib/s6rc
+++ b/src/libs6rc/deps-lib/s6rc
@@ -5,6 +5,7 @@ s6rc_db_read.o
s6rc_db_read_sizes.o
s6rc_db_read_uint32.o
s6rc_graph_closure.o
+s6rc_livedir_create.o
s6rc_livedir_prefix.o
s6rc_livedir_prefixsize.o
s6rc_lock.o
diff --git a/src/libs6rc/s6rc_livedir_create.c b/src/libs6rc/s6rc_livedir_create.c
new file mode 100644
index 0000000..1da0ac3
--- /dev/null
+++ b/src/libs6rc/s6rc_livedir_create.c
@@ -0,0 +1,50 @@
+/* ISC license. */
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h> /* mkdtemp */
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <s6-rc/s6rc-utils.h>
+
+int s6rc_livedir_create (stralloc *sa, char const *live, char const *suffix, char const *scandir, char const *prefix, char const *compiled, unsigned char const *state, unsigned int statelen, size_t *dirlen)
+{
+ size_t newlen, ddirlen ;
+ size_t sabase = sa->len ;
+ int wasnull = !sa->s ;
+ if (!s6rc_sanitize_dir(sa, live, &ddirlen)) return 0 ;
+ if (!stralloc_cats(sa, ":")) goto err ;
+ if (!stralloc_cats(sa, suffix)) goto err ;
+ if (!stralloc_cats(sa, ":XXXXXX")) goto err ;
+ if (!mkdtemp(sa->s + sabase)) goto err ;
+ newlen = sa->len-- ;
+ if (chmod(sa->s + sabase, 0755) < 0) goto delerr ;
+ if (!stralloc_catb(sa, "/servicedirs", 13)) goto delerr ; /* allocates enough for the next strcpys */
+ if (mkdir(sa->s + sabase, 0755) < 0) goto delerr ;
+ strcpy(sa->s + newlen, "compiled") ;
+ if (symlink(compiled, sa->s + sabase) < 0) goto delerr ;
+ strcpy(sa->s + newlen, "scandir") ;
+ if (symlink(scandir, sa->s + sabase) < 0) goto delerr ;
+ strcpy(sa->s + newlen, "prefix") ;
+ if (!openwritenclose_unsafe(sa->s + sabase, prefix, strlen(prefix))) goto delerr ;
+ strcpy(sa->s + newlen, "state") ;
+ if (!openwritenclose_unsafe(sa->s + sabase, (char const *)state, statelen)) goto delerr ;
+ sa->len = newlen ;
+ sa->s[newlen] = 0 ;
+ *dirlen = ddirlen ;
+ return 1 ;
+
+ delerr:
+ {
+ int e = errno ;
+ sa->s[newlen] = 0 ;
+ rm_rf_in_tmp(sa, sabase) ;
+ errno = e ;
+ }
+ err:
+ if (wasnull) stralloc_free(sa) ;
+ else sa->len = sabase ;
+ return 0 ;
+}
diff --git a/src/s6-rc/s6-rc-init.c b/src/s6-rc/s6-rc-init.c
index c618949..dfc7b7c 100644
--- a/src/s6-rc/s6-rc-init.c
+++ b/src/s6-rc/s6-rc-init.c
@@ -1,6 +1,5 @@
/* ISC license. */
-#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -11,35 +10,29 @@
#include <skalibs/stralloc.h>
#include <skalibs/tai.h>
#include <skalibs/djbunix.h>
-#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
#include <s6-rc/config.h>
#include <s6-rc/s6rc.h>
-#define USAGE "s6-rc-init [ -c compiled ] [ -l live ] [ -p prefix ] [ -t timeout ] [ -b ] [ -d ] scandir"
+#define USAGE "s6-rc-init [ -c compiled ] [ -l live ] [ -p prefix ] [ -t timeout ] [ -d ] scandir"
#define dieusage() strerr_dieusage(100, USAGE)
-#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
-static size_t llen ;
-static stralloc stmp = STRALLOC_ZERO ;
-
-static void cleanup (void)
+static void cleanup (stralloc *sa)
{
int e = errno ;
- stmp.s[llen] = 0 ;
- unlink(stmp.s) ;
- stmp.s[llen] = ':' ;
- rm_rf_in_tmp(&stmp, 0) ;
+ rm_rf_in_tmp(sa, 0) ;
errno = e ;
}
int main (int argc, char const *const *argv)
{
- tain_t deadline, tto ;
+ tain_t deadline ;
+ stralloc sa = STRALLOC_ZERO ;
size_t dirlen ;
char const *live = S6RC_LIVE_BASE ;
char const *compiled = S6RC_COMPILED_BASE ;
char const *prefix = "" ;
- int blocking = 0, deref = 0 ;
+ int deref = 0 ;
PROG = "s6-rc-init" ;
{
unsigned int t = 0 ;
@@ -54,156 +47,79 @@ int main (int argc, char const *const *argv)
case 'l' : live = l.arg ; break ;
case 'p' : prefix = l.arg ; break ;
case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
- case 'b' : blocking = 1 ; break ;
+ case 'b' : break ;
case 'd' : deref = 1 ; break ;
default : dieusage() ;
}
}
argc -= l.ind ; argv += l.ind ;
- if (t) tain_from_millisecs(&tto, t) ;
- else tto = tain_infinite_relative ;
+ if (t) tain_from_millisecs(&deadline, t) ;
+ else deadline = tain_infinite_relative ;
}
if (!argc) dieusage() ;
if (!deref && compiled[0] != '/')
strerr_dief2x(100, compiled, " is not an absolute path") ;
- if (live[0] != '/')
- strerr_dief2x(100, live, " is not an absolute path") ;
if (argv[0][0] != '/')
strerr_dief2x(100, argv[0], " is not an absolute path") ;
if (strchr(prefix, '/') || strchr(prefix, '\n'))
strerr_dief1x(100, "prefix cannot contain a / or a newline") ;
tain_now_g() ;
- tain_add_g(&deadline, &tto) ;
-
- if (!s6rc_sanitize_dir(&stmp, live, &dirlen)) dienomem() ;
- llen = stmp.len ;
- if (!stralloc_cats(&stmp, ":initial") || !stralloc_0(&stmp))
- strerr_diefu1sys(111, "stralloc_catb") ;
+ tain_add_g(&deadline, &deadline) ;
+ if (deref)
+ {
+ char *x = realpath(compiled, 0) ;
+ if (!x) strerr_diefu2sys(111, "realpath ", compiled) ;
+ compiled = x ;
+ }
{
- int fdlock ;
- int fdcompiled ;
- int ok ;
s6rc_db_t db ;
- unsigned int n ;
- char lfn[llen + 13] ;
- char cfn[llen + 23] ;
-
-
- /* Create the real dir, lock it, symlink */
-
- unlink(live) ;
- rm_rf(stmp.s) ;
- if (mkdir(stmp.s, 0755) < 0) strerr_diefu2sys(111, "mkdir ", stmp.s) ;
- if (!s6rc_lock(stmp.s, 2, &fdlock, 0, 0, 0, blocking))
- {
- cleanup() ;
- strerr_diefu2sys(111, "take lock on ", stmp.s) ;
- }
- memcpy(lfn, stmp.s, llen) ;
- lfn[llen] = 0 ;
- if (symlink(stmp.s + dirlen, lfn) < 0)
- {
- cleanup() ;
- strerr_diefu4sys(111, "symlink ", stmp.s + dirlen, " to ", lfn) ;
- }
-
-
- /* compiled */
-
- if (deref)
- {
- char *x = realpath(compiled, 0) ;
- if (!x) strerr_diefu2sys(111, "realpath ", compiled) ;
- compiled = x ;
- }
- fdcompiled = open_readb(compiled) ;
+ int r ;
+ int fdcompiled = open_readb(compiled) ;
if (fdcompiled < 0)
- {
- cleanup() ;
strerr_diefu2sys(111, "open ", compiled) ;
- }
- memcpy(lfn + llen, "/compiled", 10) ;
- if (symlink(compiled, lfn) < 0)
- {
- cleanup() ;
- strerr_diefu4sys(111, "symlink ", compiled, " to ", lfn) ;
- }
-
-
- /* prefix */
-
- if (prefix[0])
- {
- memcpy(lfn + llen + 1, "prefix", 7) ;
- if (!openwritenclose_unsafe(lfn, prefix, strlen(prefix)))
- {
- cleanup() ;
- strerr_diefu2sys(111, "write to ", lfn) ;
- }
- }
-
-
- /* scandir */
-
- memcpy(lfn + llen + 1, "scandir", 8) ;
- if (symlink(argv[0], lfn) < 0)
+ r = s6rc_db_read_sizes(fdcompiled, &db) ;
+ if (r < 0)
+ strerr_diefu2sys(111, "read database size in ", compiled) ;
+ else if (!r)
+ strerr_dief2x(4, "invalid database size in ", compiled) ;
+ close(fdcompiled) ;
{
- cleanup() ;
- strerr_diefu4sys(111, "symlink ", argv[0], " to ", lfn) ;
+ unsigned char state[db.nshort + db.nlong] ;
+ memset(state, 0, db.nshort + db.nlong) ;
+ if (!s6rc_livedir_create(&sa, live, PROG, argv[0], prefix, compiled, state, db.nshort + db.nlong, &dirlen))
+ strerr_diefu1sys(111, "create live directory") ;
}
-
-
- /* state */
-
- memcpy(lfn + llen + 1, "state", 6) ;
- {
- int r = s6rc_db_read_sizes(fdcompiled, &db) ;
- if (r <= 0)
- {
- cleanup() ;
- if (r < 0) strerr_diefu2sys(111, "read database size in ", compiled) ;
- else strerr_dief2x(4, "invalid database size in ", compiled) ;
- }
- close(fdcompiled) ;
- n = db.nshort + db.nlong ;
- {
- char zero[n] ;
- memset(zero, 0, n) ;
- if (!openwritenclose_unsafe(lfn, zero, n))
- {
- cleanup() ;
- strerr_diefu2sys(111, "write ", lfn) ;
- }
- }
- }
-
-
- /* servicedirs */
-
- memcpy(lfn + llen + 1, "servicedirs", 12) ;
- memcpy(cfn, lfn, llen + 1) ;
- memcpy(cfn + llen + 1, "compiled/servicedirs", 21) ;
+ }
+ {
+ size_t clen = strlen(compiled) ;
+ char lfn[sa.len + 13] ;
+ char cfn[clen + 13] ;
+ memcpy(lfn, sa.s, sa.len) ;
+ memcpy(lfn + sa.len, "/servicedirs", 13) ;
+ memcpy(cfn, compiled, clen) ;
+ memcpy(cfn + clen, "/servicedirs", 13) ;
if (!hiercopy(cfn, lfn))
{
- cleanup() ;
+ cleanup(&sa) ;
strerr_diefu4sys(111, "recursively copy ", cfn, " to ", lfn) ;
}
+ }
+ if (!atomic_symlink(sa.s + dirlen, live, PROG))
+ {
+ cleanup(&sa) ;
+ strerr_diefu4sys(111, "symlink ", sa.s + dirlen, " to ", live) ;
+ }
-
- /* start the supervisors */
-
- lfn[llen] = 0 ;
- ok = s6rc_servicedir_manage_g(lfn, prefix, &deadline) ;
- if (!ok)
- {
- cleanup() ;
- strerr_diefu3sys(111, "supervise service directories in ", lfn, "/servicedirs") ;
- }
- if (ok & 2)
- strerr_warnw3x("s6-svscan not running on ", lfn, "/scandir") ;
- }
+ deref = s6rc_servicedir_manage_g(live, prefix, &deadline) ;
+ if (!deref)
+ {
+ cleanup(&sa) ;
+ strerr_diefu3sys(111, "supervise service directories in ", live, "/servicedirs") ;
+ }
+ if (deref & 2)
+ strerr_warnw2x("s6-svscan not running on ", argv[0]) ;
return 0 ;
}
diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c
index 3f77ecb..dc3806b 100644
--- a/src/s6-rc/s6-rc-update.c
+++ b/src/s6-rc/s6-rc-update.c
@@ -3,6 +3,7 @@
#include <skalibs/nonposix.h> /* Solaris doesn't know mkdtemp() is POSIX */
#include <string.h>
#include <stdint.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -32,7 +33,6 @@
#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f conversion_file ] [ -b ] newdb"
#define dieusage() strerr_dieusage(100, USAGE)
#define dienomem() strerr_diefu1sys(111, "build string") ;
-#define NEWSUFFIX ":updated:XXXXXX"
static char const *live = S6RC_LIVE_BASE ;
static size_t livelen = sizeof(S6RC_LIVE_BASE) - 1 ;
@@ -324,49 +324,32 @@ static inline void rollback_servicedirs (char const *newlive, unsigned char cons
}
}
-static inline void make_new_livedir (unsigned char const *oldstate, s6rc_db_t const *olddb, unsigned char const *newstate, s6rc_db_t const *newdb, char const *newcompiled, unsigned int *invimage, char const *prefix, size_t prefixlen, stralloc *sa)
+static inline void make_new_livedir (unsigned char const *oldstate, s6rc_db_t const *olddb, unsigned char const *newstate, s6rc_db_t const *newdb, char const *newcompiled, unsigned int *invimage, char const *prefix, stralloc *sa)
{
- size_t tmpbase = satmp.len ;
+ size_t dirlen, pos, newlen, sdlen ;
size_t newclen = strlen(newcompiled) ;
- size_t dirlen, llen, newlen, sdlen ;
- int e = 0 ;
- unsigned int i = 0 ;
- if (sareadlink(&satmp, live) < 0) strerr_diefu2sys(111, "readlink ", live) ;
- if (!s6rc_sanitize_dir(sa, live, &dirlen)) dienomem() ;
- llen = sa->len ;
- if (!stralloc_catb(sa, NEWSUFFIX, sizeof(NEWSUFFIX))) dienomem() ;
- newlen = --sa->len ;
- if (!mkdtemp(sa->s)) strerr_diefu2sys(111, "mkdtemp ", sa->s) ;
- if (chmod(sa->s, 0755) < 0) { e = errno ; goto err ; }
+ unsigned int i = newdb->nlong + newdb->nshort ;
+ if (sareadlink(sa, live) < 0 || !stralloc_0(sa)) strerr_diefu2sys(111, "readlink ", live) ;
+ pos = sa->len ;
{
- size_t tmplen = satmp.len ;
- char fn[llen + 9] ;
- if (!stralloc_cats(sa, "/scandir") || !stralloc_0(sa)) { e = errno ; goto err ; }
- memcpy(fn, sa->s, llen) ;
- memcpy(fn + llen, "/scandir", 9) ;
- if (sareadlink(&satmp, fn) < 0 || !stralloc_0(&satmp)) { e = errno ; goto err ; }
- if (symlink(satmp.s + tmplen, sa->s) < 0) { e = errno ; goto err ; }
- satmp.len = tmplen ;
- }
- sa->len = newlen ;
- if (!stralloc_catb(sa, "/prefix", 8)) { e = errno ; goto err ; }
- if (!openwritenclose_unsafe(sa->s, prefix, prefixlen)) { e = errno ; goto err ; }
- sa->len = newlen ;
- if (!stralloc_catb(sa, "/state", 7)) { e = errno ; goto err ; }
- {
- char tmpstate[newdb->nlong + newdb->nshort] ;
- unsigned int i = newdb->nlong + newdb->nshort ;
+ ssize_t r ;
+ char sdtarget[PATH_MAX] ;
+ char sdlink[livelen + 9] ;
+ unsigned char tmpstate[newdb->nlong + newdb->nshort] ;
+ memcpy(sdlink, live, livelen) ;
+ memcpy(sdlink + livelen, "/scandir", 9) ;
+ r = readlink(sdlink, sdtarget, PATH_MAX) ;
+ if (r < 0) strerr_diefu2sys(111, "readlink ", sdlink) ;
+ if (r >= PATH_MAX - 1) strerr_dief3x(100, "target for ", sdlink, " is too long") ;
+ sdtarget[r] = 0 ;
while (i--) tmpstate[i] = newstate[i] & 1 ;
- if (!openwritenclose_unsafe(sa->s, tmpstate, newdb->nlong + newdb->nshort)) { e = errno ; goto err ; }
+ if (!s6rc_livedir_create(sa, live, PROG, sdtarget, prefix, newcompiled, tmpstate, newdb->nlong + newdb->nshort, &dirlen))
+ strerr_diefu1sys(111, "create new livedir") ;
}
- sa->len = newlen ;
- if (!stralloc_catb(sa, "/compiled", 10)) { e = errno ; goto err ; }
- if (symlink(newcompiled, sa->s) < 0) goto err ;
- sa->len = newlen ;
- if (!stralloc_catb(sa, "/servicedirs", 13)) { e = errno ; goto err ; }
- if (mkdir(sa->s, 0755) < 0) { e = errno ; goto err ; }
+ newlen = sa->len ;
+ i = 0 ;
+ if (!stralloc_catb(sa, "/servicedirs/", 13)) goto rollback ;
sdlen = sa->len ;
- sa->s[sdlen - 1] = '/' ;
for (; i < newdb->nlong ; i++)
{
@@ -376,8 +359,7 @@ static inline void make_new_livedir (unsigned char const *oldstate, s6rc_db_t co
memcpy(newfn + newclen, "/servicedirs/", 13) ;
memcpy(newfn + newclen + 13, newdb->string + newdb->services[i].name, newnamelen + 1) ;
sa->len = sdlen ;
- if (!stralloc_cats(sa, newdb->string + newdb->services[i].name)
- || !stralloc_0(sa)) { e = errno ; goto rollback ; }
+ if (!stralloc_cats(sa, newdb->string + newdb->services[i].name) || !stralloc_0(sa)) goto rollback ;
if (newstate[i] & 1)
{
char const *oldname = newstate[i] & 8 ? olddb->string + olddb->services[invimage[i]].name : newdb->string + newdb->services[i].name ;
@@ -386,55 +368,35 @@ static inline void make_new_livedir (unsigned char const *oldstate, s6rc_db_t co
memcpy(oldfn, live, livelen) ;
memcpy(oldfn + livelen, "/servicedirs/", 13) ;
memcpy(oldfn + livelen + 13, oldname, oldnamelen + 1) ;
- if (rename(oldfn, sa->s) < 0) goto rollback ;
- if (!s6rc_servicedir_copy_online(newfn, sa->s)) { i++ ; e = errno ; goto rollback ; }
+ if (rename(oldfn, sa->s + pos) < 0) goto rollback ;
+ if (!s6rc_servicedir_copy_online(newfn, sa->s + pos)) { i++ ; goto rollback ; }
}
- else if (!s6rc_servicedir_copy_offline(newfn, sa->s)) { e = errno ; goto rollback ; }
+ else if (!s6rc_servicedir_copy_offline(newfn, sa->s + pos)) goto rollback ;
}
-
sa->len = newlen ;
- sa->s[sa->len++] = 0 ;
- {
- char tmpfn[llen + 5] ;
- memcpy(tmpfn, sa->s, llen) ;
- memcpy(tmpfn + llen, ".new", 5) ;
- if (unlink(tmpfn) < 0 && errno != ENOENT) { e = errno ; goto rollback ; }
- if (symlink(sa->s + dirlen, tmpfn) < 0) { e = errno ; goto rollback ; }
+ sa->s[sa->len] = 0 ;
/* The point of no return is here */
- if (rename(tmpfn, live) < 0)
- {
- e = errno ;
- unlink(tmpfn) ;
- goto rollback ;
- }
- }
-
- if (verbosity >= 2)
- strerr_warni1x("successfully switched to new database") ;
+ if (!atomic_symlink(sa->s + dirlen, live, "s6-rc-update_atomic_symlink")) goto rollback ;
+ if (verbosity >= 2) strerr_warni1x("successfully switched to new database") ;
/* scandir cleanup, then old livedir cleanup */
- sa->len = dirlen ;
- if (!stralloc_catb(sa, satmp.s + tmpbase, satmp.len - tmpbase) || !stralloc_0(sa))
- dienomem() ;
i = olddb->nlong ;
while (i--)
s6rc_servicedir_unsupervise(sa->s, prefix, olddb->string + olddb->services[i].name, (oldstate[i] & 33) == 1) ;
- rm_rf(sa->s) ;
-
+ rm_rf_in_tmp(sa, 0) ;
sa->len = 0 ;
- satmp.len = tmpbase ;
return ;
rollback:
- sa->len = newlen ;
- sa->s[sa->len++] = 0 ;
- rollback_servicedirs(sa->s, newstate, invimage, olddb, newdb, i) ;
- err:
- sa->len = newlen ;
- sa->s[sa->len++] = 0 ;
- rm_rf(sa->s) ;
- errno = e ;
+ {
+ int e = errno ;
+ sa->len = newlen ;
+ sa->s[sa->len++] = 0 ;
+ rollback_servicedirs(sa->s + pos, newstate, invimage, olddb, newdb, i) ;
+ rm_rf_in_tmp(sa, 0) ;
+ errno = e ;
+ }
strerr_diefu2sys(111, "make new live directory in ", sa->s) ;
}
@@ -642,8 +604,6 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (!argc) dieusage() ;
if (argv[0][0] != '/')
strerr_dief2x(100, argv[0], " is not an absolute path") ;
- if (live[0] != '/')
- strerr_dief2x(100, live, " is not an absolute path") ;
livelen = strlen(live) ;
{
@@ -809,12 +769,12 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (verbosity >= 2)
strerr_warni1x("updating state and service directories") ;
- make_new_livedir(oldstate, &olddb, newstate, &newdb, argv[0], invimage, prefix, prefixlen, &sa) ;
+ make_new_livedir(oldstate, &olddb, newstate, &newdb, argv[0], invimage, prefix, &sa) ;
+ stralloc_free(&sa) ;
r = s6rc_servicedir_manage_g(live, prefix, &deadline) ;
if (!r) strerr_diefu2sys(111, "manage new service directories in ", live) ;
if (r & 2) strerr_warnw3x("s6-svscan not running on ", live, "/scandir") ;
-
/* Adjust stored pipes */
if (verbosity >= 2)