add more parsing code
[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 instance_stop(in, true);
119 instance_config_move(in, in_new);
120 return true;
121 }
122
123 void
124 instance_free(struct service_instance *in)
125 {
126 uloop_process_delete(&in->proc);
127 uloop_timeout_cancel(&in->timeout);
128 instance_config_cleanup(in);
129 free(in);
130 }
131
132 void
133 instance_init(struct service_instance *in, struct blob_attr *config)
134 {
135 in->config = config;
136 in->timeout.cb = instance_timeout;
137 in->proc.cb = instance_exit;
138
139 blobmsg_list_simple_init(&in->env);
140 blobmsg_list_simple_init(&in->data);
141 in->valid = instance_config_parse(in);
142 }
143
144