enable restart on config change
[project/procd.git] / instance.c
1 #include "procd.h"
2 #include "service.h"
3 #include "instance.h"
4
5 enum {
6         INSTANCE_ATTR_COMMAND,
7         INSTANCE_ATTR_ENV,
8         INSTANCE_ATTR_DATA,
9         __INSTANCE_ATTR_MAX
10 };
11
12 static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = {
13         [INSTANCE_ATTR_COMMAND] = { "command", BLOBMSG_TYPE_ARRAY },
14         [INSTANCE_ATTR_ENV] = { "env", BLOBMSG_TYPE_TABLE },
15         [INSTANCE_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
16 };
17
18 void
19 instance_start(struct service_instance *in)
20 {
21         in->restart = false;
22 }
23
24 static void
25 instance_timeout(struct uloop_timeout *t)
26 {
27         struct service_instance *in;
28
29         in = container_of(t, struct service_instance, timeout);
30         kill(in->proc.pid, SIGKILL);
31         uloop_process_delete(&in->proc);
32         in->proc.cb(&in->proc, -1);
33 }
34
35 static void
36 instance_exit(struct uloop_process *p, int ret)
37 {
38         struct service_instance *in;
39
40         in = container_of(p, struct service_instance, proc);
41         uloop_timeout_cancel(&in->timeout);
42         if (in->restart)
43                 instance_start(in);
44 }
45
46 void
47 instance_stop(struct service_instance *in, bool restart)
48 {
49         if (!in->proc.pending)
50                 return;
51
52         kill(in->proc.pid, SIGTERM);
53 }
54
55 static bool
56 instance_config_changed(struct service_instance *in, struct service_instance *in_new)
57 {
58         if (!in->valid)
59                 return true;
60
61         if (!blob_attr_equal(in->command, in_new->command))
62                 return true;
63
64         if (!blobmsg_list_equal(&in->env, &in_new->env))
65                 return true;
66
67         if (!blobmsg_list_equal(&in->data, &in_new->data))
68                 return true;
69
70         return false;
71 }
72
73 static bool
74 instance_config_parse(struct service_instance *in)
75 {
76         struct blob_attr *tb[__INSTANCE_ATTR_MAX];
77         struct blob_attr *cur;
78
79         blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb,
80                 blobmsg_data(in->config), blobmsg_data_len(in->config));
81         if (!tb[INSTANCE_ATTR_COMMAND])
82                 return false;
83
84         if ((cur = tb[INSTANCE_ATTR_ENV]))
85                 blobmsg_list_fill(&in->env, blobmsg_data(cur), blobmsg_data_len(cur));
86
87         if ((cur = tb[INSTANCE_ATTR_DATA]))
88                 blobmsg_list_fill(&in->data, blobmsg_data(cur), blobmsg_data_len(cur));
89
90         return true;
91 }
92
93 static void
94 instance_config_cleanup(struct service_instance *in)
95 {
96         blobmsg_list_free(&in->env);
97         blobmsg_list_free(&in->data);
98 }
99
100 static void
101 instance_config_move(struct service_instance *in, struct service_instance *in_src)
102 {
103         instance_config_cleanup(in);
104         blobmsg_list_move(&in->env, &in_src->env);
105         blobmsg_list_move(&in->data, &in_src->data);
106         in->command = in_src->command;
107 }
108
109 bool
110 instance_update(struct service_instance *in, struct service_instance *in_new)
111 {
112         bool changed = instance_config_changed(in, in_new);
113
114         in->config = in_new->config;
115         if (!changed)
116                 return false;
117
118         in->restart = true;
119         instance_stop(in, true);
120         instance_config_move(in, in_new);
121         return true;
122 }
123
124 void
125 instance_free(struct service_instance *in)
126 {
127         uloop_process_delete(&in->proc);
128         uloop_timeout_cancel(&in->timeout);
129         instance_config_cleanup(in);
130         free(in);
131 }
132
133 void
134 instance_init(struct service_instance *in, struct blob_attr *config)
135 {
136         in->config = config;
137         in->timeout.cb = instance_timeout;
138         in->proc.cb = instance_exit;
139
140         blobmsg_list_simple_init(&in->env);
141         blobmsg_list_simple_init(&in->data);
142         in->valid = instance_config_parse(in);
143 }
144
145