summaryrefslogtreecommitdiff
path: root/src/server/deps.c
blob: b1a1fd4e06e6b3a2e5811772681f37b294ed02ee (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
/* ISC license. */

#include <stdint.h>
#include <sys/uio.h>
#include <errno.h>

#include <s6-rc/db.h>
#include "state.h"

static int state_allownext (sstate_t const *st, uint8_t deptype, uint8_t subtype, int h)
{
  return !(st->bits & SSTATE_WANTED) == h && subtype != S6RC_STYPE_EXTERNAL && subtype != S6RC_STYPE_N + S6RC_STYPE_EXTERNAL ? 0 :
  (!(st->bits & SSTATE_CURRENT) != h && !(st->bits & SSTATE_TRANSITIONING))
   || (s6rc_deptype_soft(deptype) && st->bits & SSTATE_FAILED)
   || (s6rc_deptype_loose(deptype) && !(st->bits & SSTATE_TRANSITIONING))
}

static int instances_testalldown (mstate_t const *m, uint8_t deptype, uint8_t type, uint32_t num)
{
  instance_t const *ins = genalloc_s(instance_t, m->dyn[type] + num) ;
  size_t n = genalloc_len(instance_t, m->dyn[type] + num) ;
  for (size_t i = 0 ; i < n ; i++)
    if (!state_allownext(&ins[i].sstate, deptype, subtype, 0)) return 0 ;
  return 1 ;
}

int deps_fulfilled (s6rc_db_t const *db, mstate_t const *m, uint32_t id, char const *param, int h)
{
  s6rc_common_t const *common ;
  uint32_t num ;
  uint8_t type ;
  s6rc_service_typenum(db->n, id, &type, &num) ;
  common = s6rc_service_common_tn(db, type, num) ;
  for (uint32_t i = 0 ; i < common->ndeps[h] ; i++)
  {
    uint32_t subnum ;
    uint8_t subtype ;
    uint8_t deptype = db->deptypes[h][common->deps[h] + i] ;
    s6rc_service_typenum(db->n, db->deps[h][common->deps[h] + i], &subtype, &subnum) ;
    if (!h && type < S6RC_STYPE_N && subtype >= S6RC_STYPE_N)
      return instances_testalldown(m, deptype, subtype, subnum) ;
    if (h && type >= S6RC_STYPE_N && subtype < S6RC_STYPE_N)
      param = 0 ;
    if (!state_allownext(sstate_tn(m, subtype, subnum, param), deptype, subtype, h))
      return 0 ;
  }
  return 1 ;
}

typedef struct recinfo_s recinfo_t, *recinfo_t_ref ;
struct recinfo_s
{
  s6rc_db_t const *db ;
  mstate_t *m ;
  char const *param ;
  uint8_t h : 1 ;
  uint8_t force : 1 ;
}

static int mstate_dep_closure_rec (recinfo_t *recinfo, uint32_t id, char const *param)
{
  sstate_t *st ;
  st = sstate(recinfo->db, recinfo->m, id, param) ;
  if (!st)
  {
    if (!recinfo->h) return 1 ;
    st = instance_create(recinfo->m, id, param) ;
    if (!st) return 0 ;
  }
  if (!(st->tmp & SSTATE_TRANSITIONING))
  {
    s6rc_common_t const *common ;
    uint32_t num ;
    uint8_t type ;
    st->tmp |= SSTATE_TRANSITIONING ;
    s6rc_service_typenum(recinfo->db->n, id, &type, &num) ;
    common = s6rc_service_common_tn(recinfo->db, type, num) ;
    if (!recinfo->h && !recinfo->force && common->flags & S6RC_DB_FLAG_ESSENTIAL) return (errno = EPERM, 0) ;
    for (uint32_t i = 0 ; i < common->ndeps[recinfo->h] ; i++)
    {
      uint32_t subid = recinfo->db->deps[recinfo->h][common->deps[recinfo->h] + i] ;
      uint32_t subnum ;
      uint8_t subtype ;
      if (s6rc_service_recheck_instance(recinfo->db, &subid, &param) < 0) return (errno = EPROTO, 0) ;
      if (deptype_passive(recinfo->db->deptypes[recinfo->h][common->deps[recinfo->h] + i])) continue ;
      s6rc_service_typenum(recinfo->db->n, subid, &subtype, &subnum) ;
      if (!recinfo->h && type < S6RC_STYPE_N && subtype >= S6RC_STYPE_N)
      {
        instance_t const *ins = genalloc_s(instance_t, recinfo->m->dyn[subtype] + subnum) ;
        size_t n = genalloc_len(instance_t, recinfo->m->dyn[subtype] + subnum) ;
        for (size_t j = 0 ; j < n ; j++)
          if (!mstate_dep_closure_rec(recinfo, subid, ins[j].param)) return 0 ;
      }
      else
      {
        if (recinfo->h && type >= S6RC_STYPE_N && subtype < S6RC_STYPE_N)
          param = 0 ;
        if (!mstate_dep_closure_rec(recinfo, subid, param))
          return 0 ;
      }
    }
    st->tmp |= SSTATE_WANTED ;
  }
}

static void mstate_dep_closure (s6rc_db_t const *db, mstate_t *m, sstate_t *st, char const *param, int h, int force)
{
  recinfo_t recinfo = { .db = db, .m = m, .param = param, .h = !!h, .force = !!force } ;
  mstate_dep_closure_rec(&recinfo, st) ;
}

int mstate_change_wanted (s6rc_db_t const *db, mstate_t *m, char const *const *args, size_t n, int h, int force)
{
  mstate_zerotmp(m, db->n) ;
  for (size_t i = 0 ; i < n ; n++)
  {
    sstate_t *st ;
    uint32_t id ;
    char const *param ;
    int r = s6rc_service_resolve(&db->resolve, args[i], &id, &param) ;
    if (r < 0) return -1 ;
    if (!r) return 1 + i ;
    st = sstate(db, m, id, param) ;
    if (!st)  /* instance not found */
    {
      st = instance_create(m, id, param) ;
      if (!st) return -1 ;
    }
    st->tmp |= SSTATE_WANTED | SSTATE_EXPLICIT ;
    mstate_dep_closure(db, m, st, param, h) ;
  }
}