summaryrefslogtreecommitdiff
path: root/src/libs6rc/s6rc_db_load.c
blob: bcc5f2f1f145d320a895d4014e7c1950a920de57 (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
130
131
132
133
134
135
136
137
138
139
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_load (char const *dir, s6rc_db_t *db, cdb_t *c)
{
  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_mapfile(fn, c)) 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(c) ;
 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 ;
}