summaryrefslogtreecommitdiff
path: root/src/libs6rcd/s6rc_db_load.c
blob: e42afc907dc1991a7f731658c30407c6080a2d0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* 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/sha256.h>

#include "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_load (char const *dir, s6rc_db_t *db)
{
  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 + 10] ;
  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]) goto eproto1 ;

    {
      ssize_t r ;
      memcpy(fn + len, "/hash", 6) ;
      r = openreadnclose(fn, buf+32, 33) ;
      if (r == 33) goto eproto1 ;
      if (r < 32) goto err1 ;
      sha256_update(&ctx, db->map, db->size) ;
      sha256_final(&ctx, buf) ;
      if (memcmp(buf, buf+32, 32)) goto eproto1 ;
    }

    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] = (s6rc_id_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 eproto1 ;

    db->argvs = (char const **)alloc(sizeof(char const *) * nargv) ;
    if (!db->argvs) goto err1 ;
    for (uint32_t i = 0 ; i < nargv ; i++)
      db->argvs[i] = argvs[i] ? db->storage + argvs[i] : 0 ;
  }
  return 1 ;

 eproto1:
  errno = EPROTO ;
 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 ;
}