summaryrefslogtreecommitdiff
path: root/src/libs6rc/s6rc_db_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs6rc/s6rc_db_init.c')
-rw-r--r--src/libs6rc/s6rc_db_init.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/libs6rc/s6rc_db_init.c b/src/libs6rc/s6rc_db_init.c
new file mode 100644
index 0000000..075d0c3
--- /dev/null
+++ b/src/libs6rc/s6rc_db_init.c
@@ -0,0 +1,140 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/alloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/cdb.h>
+#include <skalibs/sha256.h>
+
+#include <s6-rc/db.h>
+
+#include <skalibs/posixishard.h>
+
+static int gethu32 (buffer *b, SHA256Schedule *ctx, uint32_t *n)
+{
+ if (buffer_get(b, (char *)n, 4) < 4) return 0 ;
+ sha256_update(ctx, (char *)n, 4) ;
+ return 1 ;
+}
+
+int s6rc_db_init (s6rc_db_t *db, char const *dir)
+{
+ SHA256Schedule ctx = SHA256_INIT() ;
+ uint32_t ntotal, ndeps, nproducers, storagelen, nargv ;
+ size_t len = strlen(dir) ;
+ buffer b ;
+ int fd ;
+ char buf[4096] ;
+ char fn[len + 13] ;
+ memcpy(fn, dir, len) ;
+ memcpy(fn + len, "/db_nomap", 10) ;
+ fd = openc_read(fn) ;
+ if (fd == -1) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ {
+ uint32_t canary ;
+ if (!gethu32(&b, &canary)) goto err0 ;
+ if (canary != 0x11223344u) { errno = EILSEQ ; goto err0 ; }
+ }
+ if (!gethu32(&b, &ctx, &ntotal)) goto err0 ;
+ if (!gethu32(&b, &ctx, &ndeps)) goto err0 ;
+ if (!gethu32(&b, &ctx, &nproducers)) goto err0 ;
+ if (!gethu32(&b, &ctx, &storagelen)) goto err0 ;
+ if (!gethu32(&b, &ctx, &nargv)) goto err0 ;
+ if (nargv > S6RC_ARGV_MAX) goto eproto0 ;
+
+ {
+ uint32_t argvs[nargv ? nargv : 1] ;
+ if (buffer_get(&b, (char *)argvs, nargv * 4) < nargv * 4) goto err0 ;
+ {
+ char c ;
+ ssize_t r = buffer_get(&b, &c, 1) ;
+ if (r < 0) goto err0 ;
+ if (r) goto eproto0 ;
+ }
+ fd_close(fd) ;
+ sha256_update(&ctx, (char *)argvs, nargv * 4) ;
+ memcpy(fn + len, "/db", 4) ;
+
+ {
+ struct stat st ;
+ void *map ;
+ fd = openc_read(fn) ;
+ if (fd == -1) return 0 ;
+ if (fstat(fd, &st) == -1) goto err0 ;
+ if (!S_ISREG(st.st_mode)) goto eproto0 ;
+ if (st.st_size < 8 * S6RC_STYPE_N) goto eproto0 ;
+ map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
+ if (map == MAP_FAILED) goto err0 ;
+ fd_close(fd) ;
+ db->size = st.st_size ;
+ db->map = map ;
+ }
+ db->n = (uint32_t const *)db->map ;
+ if (ntotal != db->n[0] + db->n[1] + db->n[2] + db->n[3] + db->n[4] + db->n[5] + db->n[6] + db->n[7] + db->n[8] + db->n[9])
+ {
+ errno = EPROTO ;
+ goto err1 ;
+ }
+
+ memcpy(fn + len, "/resolve.cdb", 13) ;
+ if (!cdb_init(&db->resolve, fn)) goto err1 ;
+
+ {
+ ssize_t r ;
+ memcpy(fn + len, "/hash", 6) ;
+ r = openreadnclose(fn, buf+32, 33) ;
+ if (r == 33) goto eproto2 ;
+ if (r < 32) goto err2 ;
+ sha256_update(&ctx, db->map, db->size) ;
+ sha256_update(&ctx, c->map, c->size) ;
+ sha256_final(&ctx, buf) ;
+ if (memcmp(buf, buf+32, 32)) goto eproto2 ;
+ }
+
+ db->longruns = (s6rc_longrun_t const *)(db->map + 4 * 2 * S6RC_STYPE_N) ;
+ db->oneshots = (s6rc_oneshot_t const *)(db->longruns + db->n[S6RC_STYPE_LONGRUN] + db->n[S6RC_STYPE_N + S6RC_STYPE_LONGRUN]) ;
+ db->externals = (s6rc_external_t const *)(db->oneshots + db->n[S6RC_STYPE_ONESHOT] + db->n[S6RC_STYPE_N + S6RC_STYPE_ONESHOT]) ;
+ db->bundles = (s6rc_bundle_t const *)(db->externals + db->n[S6RC_STYPE_EXTERNAL] + db->n[S6RC_STYPE_N + S6RC_STYPE_EXTERNAL]) ;
+ db->virtuals = (s6rc_bundle_t const *)(db->bundles + db->n[S6RC_STYPE_BUNDLE] + db->n[S6RC_STYPE_N + S6RC_STYPE_BUNDLE]) ;
+ db->deps[0] = (uint32_t const *)(db->virtuals + db->n[S6RC_STYPE_VIRTUAL] + db->n[S6RC_STYPE_N + S6RC_STYPE_VIRTUAL]) ;
+ db->deps[1] = db->deps[0] + ndeps ;
+ db->producers = db->deps[1] + ndeps ;
+ db->deptypes[0] = (uint8_t const *)(db->producers + nproducers) ;
+ db->deptypes[1] = db->deptypes[0] + ndeps ;
+ db->storage = (char const *)(db->deptypes[1] + ndeps) ;
+ if (db->storage + storagelen != db->map + db->size) goto eproto2 ;
+
+ db->argvs = (char const **)alloc(sizeof(char const *) * nargv) ;
+ if (!db->argvs) goto err2 ;
+ for (uint32_t i = 0 ; i < nargv ; i++)
+ db->argvs[i] = argvs[i] ? db->storage + argvs[i] : 0 ;
+ }
+ return 1 ;
+
+ eproto2:
+ errno = EPROTO ;
+ err2:
+ cdb_free(&db->resolve) ;
+ err1:
+ {
+ int e = errno ;
+ munmap(db->map, db->size) ;
+ errno = e ;
+ }
+ db->map = 0 ;
+ return 0 ;
+
+ eproto0:
+ errno = EPROTO ;
+ err0:
+ fd_close(fd) ;
+ return 0 ;
+}