1 /*
2    CTDB event daemon - daemon state
3 
4    Copyright (C) Amitay Isaacs  2018
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "replace.h"
21 #include "system/dir.h"
22 
23 #include <talloc.h>
24 #include <tevent.h>
25 
26 #include "lib/util/debug.h"
27 #include "lib/util/dlinklist.h"
28 
29 #include "common/logging.h"
30 #include "common/run_event.h"
31 #include "common/path.h"
32 
33 #include "event/event_private.h"
34 
35 struct event_event {
36 	struct event_event *prev, *next;
37 
38 	const char *name;
39 	struct run_event_script_list *script_list;
40 };
41 
42 struct event_component {
43 	struct event_component *prev, *next;
44 
45 	/* component state */
46 	const char *name;
47 	const char *path;
48 	struct run_event_context *run_ctx;
49 
50 	/* events list */
51 	struct event_event *event;
52 };
53 
54 struct event_client {
55 	struct event_client *prev, *next;
56 
57 	struct sock_client_context *client;
58 };
59 
60 struct event_context {
61 	struct tevent_context *ev;
62 	struct event_config *config;
63 	struct run_proc_context *run_proc_ctx;
64 
65 	const char *script_dir;
66 	const char *debug_script;
67 
68 	/* component list */
69 	struct event_component *component;
70 
71 	/* client list */
72 	struct event_client *client;
73 };
74 
75 /*
76  * event_event functions
77  */
78 
eventd_event_find(struct event_component * comp,const char * event_name)79 static struct event_event *eventd_event_find(struct event_component *comp,
80 					     const char *event_name)
81 {
82 	struct event_event *event;
83 
84 	if (event_name == NULL) {
85 		return NULL;
86 	}
87 
88 	for (event = comp->event; event != NULL; event = event->next) {
89 		if (strcmp(event->name, event_name) == 0) {
90 			return event;
91 		}
92 	}
93 
94 	return NULL;
95 }
96 
eventd_event_add(struct event_component * comp,const char * event_name,struct event_event ** result)97 static int eventd_event_add(struct event_component *comp,
98 			    const char *event_name,
99 			    struct event_event **result)
100 {
101 	struct event_event *event;
102 
103 	if (event_name == NULL) {
104 		return EINVAL;
105 	}
106 
107 	event = eventd_event_find(comp, event_name);
108 	if (event != NULL) {
109 		goto done;
110 	}
111 
112 	event = talloc_zero(comp, struct event_event);
113 	if (event == NULL) {
114 		return ENOMEM;
115 	}
116 
117 	event->name = talloc_strdup(event, event_name);
118 	if (event->name == NULL) {
119 		talloc_free(event);
120 		return ENOMEM;
121 	}
122 
123 	DLIST_ADD_END(comp->event, event);
124 
125 done:
126 	if (result != NULL) {
127 		*result = event;
128 	}
129 	return 0;
130 }
131 
eventd_event_set(struct event_component * comp,const char * event_name,struct run_event_script_list * script_list)132 static int eventd_event_set(struct event_component *comp,
133 			    const char *event_name,
134 			    struct run_event_script_list *script_list)
135 {
136 	struct event_event *event = NULL;
137 	int ret;
138 
139 	ret = eventd_event_add(comp, event_name, &event);
140 	if (ret != 0) {
141 		return ret;
142 	}
143 
144 	TALLOC_FREE(event->script_list);
145 	if (script_list != NULL) {
146 		event->script_list = talloc_steal(event, script_list);
147 	}
148 
149 	return 0;
150 }
151 
eventd_event_get(struct event_component * comp,const char * event_name,struct run_event_script_list ** result)152 static int eventd_event_get(struct event_component *comp,
153 			    const char *event_name,
154 			    struct run_event_script_list **result)
155 {
156 	struct event_event *event;
157 
158 	event = eventd_event_find(comp, event_name);
159 	if (event == NULL) {
160 		return EINVAL;
161 	}
162 
163 	*result = event->script_list;
164 	return 0;
165 }
166 
167 /*
168  * event_component functions
169  */
170 
eventd_component_find(struct event_context * eventd,const char * comp_name)171 static struct event_component *eventd_component_find(
172 					struct event_context *eventd,
173 					const char *comp_name)
174 {
175 	struct event_component *comp;
176 
177 	if (comp_name == NULL) {
178 		return NULL;
179 	}
180 
181 	for (comp = eventd->component; comp != NULL; comp = comp->next) {
182 		if (strcmp(comp->name, comp_name) == 0) {
183 			return comp;
184 		}
185 	}
186 
187 	return NULL;
188 }
189 
eventd_component_add(struct event_context * eventd,const char * comp_name,struct event_component ** result)190 static int eventd_component_add(struct event_context *eventd,
191 				const char *comp_name,
192 				struct event_component **result)
193 {
194 	struct event_component *comp;
195 	int ret;
196 
197 	if (comp_name == NULL) {
198 		return EINVAL;
199 	}
200 
201 	comp = eventd_component_find(eventd, comp_name);
202 	if (comp != NULL) {
203 		goto done;
204 	}
205 
206 	comp = talloc_zero(eventd, struct event_component);
207 	if (comp == NULL) {
208 		return ENOMEM;
209 	}
210 
211 	comp->name = talloc_strdup(comp, comp_name);
212 	if (comp->name == NULL) {
213 		talloc_free(comp);
214 		return ENOMEM;
215 	}
216 
217 	comp->path = talloc_asprintf(comp,
218 				     "%s/%s",
219 				     eventd->script_dir,
220 				     comp_name);
221 	if (comp->path == NULL) {
222 		talloc_free(comp);
223 		return ENOMEM;
224 	}
225 
226 	ret = run_event_init(eventd,
227 			     eventd->run_proc_ctx,
228 			     comp->path,
229 			     eventd->debug_script,
230 			     &comp->run_ctx);
231 	if (ret != 0) {
232 		talloc_free(comp);
233 		return ret;
234 	}
235 
236 	DLIST_ADD_END(eventd->component, comp);
237 
238 done:
239 	if (result != NULL) {
240 		*result = comp;
241 	}
242 	return 0;
243 }
244 
245 /*
246  * event_client functions
247  */
248 
eventd_client_find(struct event_context * eventd,struct sock_client_context * client)249 static struct event_client *eventd_client_find(
250 					struct event_context *eventd,
251 					struct sock_client_context *client)
252 {
253 	struct event_client *e;
254 
255 	for (e = eventd->client; e != NULL; e = e->next) {
256 		if (e->client == client) {
257 			return e;
258 		}
259 	}
260 
261 	return NULL;
262 }
263 
eventd_client_add(struct event_context * eventd,struct sock_client_context * client)264 int eventd_client_add(struct event_context *eventd,
265 		      struct sock_client_context *client)
266 {
267 	struct event_client *e;
268 
269 	e = talloc_zero(eventd, struct event_client);
270 	if (e == NULL) {
271 		return ENOMEM;
272 	}
273 
274 	e->client = client;
275 
276 	DLIST_ADD_END(eventd->client, e);
277 
278 	return 0;
279 }
280 
eventd_client_del(struct event_context * eventd,struct sock_client_context * client)281 void eventd_client_del(struct event_context *eventd,
282 		       struct sock_client_context *client)
283 {
284 	struct event_client *e;
285 
286 	e = eventd_client_find(eventd, client);
287 	if (e == NULL) {
288 		return;
289 	}
290 
291 	DLIST_REMOVE(eventd->client, e);
292 
293 	talloc_free(e);
294 }
295 
eventd_client_exists(struct event_context * eventd,struct sock_client_context * client)296 bool eventd_client_exists(struct event_context *eventd,
297 			  struct sock_client_context *client)
298 {
299 	struct event_client *e;
300 
301 	e = eventd_client_find(eventd, client);
302 	if (e == NULL) {
303 		return false;
304 	}
305 
306 	return true;
307 }
308 
309 /* public functions */
310 
event_context_init(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct event_config * config,struct event_context ** result)311 int event_context_init(TALLOC_CTX *mem_ctx,
312 		       struct tevent_context *ev,
313 		       struct event_config *config,
314 		       struct event_context **result)
315 {
316 	struct event_context *eventd;
317 	const char *debug_script;
318 	int ret;
319 
320 	eventd = talloc_zero(mem_ctx, struct event_context);
321 	if (eventd == NULL) {
322 		return ENOMEM;
323 	}
324 
325 	eventd->ev = ev;
326 	eventd->config = config;
327 
328 	ret = run_proc_init(eventd, ev, &eventd->run_proc_ctx);
329 	if (ret != 0) {
330 		talloc_free(eventd);
331 		return ret;
332 	}
333 
334 	eventd->script_dir = path_etcdir_append(eventd, "events");
335 	if (eventd->script_dir == NULL) {
336 		talloc_free(eventd);
337 		return ENOMEM;
338 	}
339 
340 	/* FIXME
341 	status = directory_exist(eventd->script_dir);
342 	if (! status) {
343 		talloc_free(eventd);
344 		return EINVAL;
345 	}
346 	*/
347 
348 	debug_script = event_config_debug_script(config);
349 	if (debug_script != NULL) {
350 		eventd->debug_script = path_etcdir_append(eventd,
351 							  debug_script);
352 		if (eventd->debug_script == NULL) {
353 			D_WARNING("Failed to set debug script to %s\n",
354 				  debug_script);
355 		}
356 	}
357 
358 	*result = eventd;
359 	return 0;
360 }
361 
eventd_config(struct event_context * eventd)362 struct event_config *eventd_config(struct event_context *eventd)
363 {
364 	return eventd->config;
365 }
366 
eventd_run_ctx(struct event_context * eventd,const char * comp_name,struct run_event_context ** result)367 int eventd_run_ctx(struct event_context *eventd,
368 		   const char *comp_name,
369 		   struct run_event_context **result)
370 {
371 	struct event_component *comp;
372 	int ret;
373 
374 	ret = eventd_component_add(eventd, comp_name, &comp);
375 	if (ret != 0) {
376 		return ret;
377 	}
378 
379 	*result = comp->run_ctx;
380 	return 0;
381 }
382 
eventd_set_event_result(struct event_context * eventd,const char * comp_name,const char * event_name,struct run_event_script_list * script_list)383 int eventd_set_event_result(struct event_context *eventd,
384 			    const char *comp_name,
385 			    const char *event_name,
386 			    struct run_event_script_list *script_list)
387 {
388 	struct event_component *comp;
389 
390 	comp = eventd_component_find(eventd, comp_name);
391 	if (comp == NULL) {
392 		return ENOENT;
393 	}
394 
395 	return eventd_event_set(comp, event_name, script_list);
396 }
397 
eventd_get_event_result(struct event_context * eventd,const char * comp_name,const char * event_name,struct run_event_script_list ** result)398 int eventd_get_event_result(struct event_context *eventd,
399 			    const char *comp_name,
400 			    const char *event_name,
401 			    struct run_event_script_list **result)
402 {
403 	struct event_component *comp;
404 	int ret;
405 
406 	ret = eventd_component_add(eventd, comp_name, &comp);
407 	if (ret != 0) {
408 		return ret;
409 	}
410 
411 	return eventd_event_get(comp, event_name, result);
412 }
413 
eventd_script_list(TALLOC_CTX * mem_ctx,struct run_event_script_list * script_list)414 struct ctdb_event_script_list *eventd_script_list(
415 				TALLOC_CTX *mem_ctx,
416 				struct run_event_script_list *script_list)
417 {
418 	struct ctdb_event_script_list *value;
419 	int num_scripts = 0;
420 	int i;
421 
422 	value = talloc_zero(mem_ctx, struct ctdb_event_script_list);
423 	if (value == NULL) {
424 		return NULL;
425 	}
426 
427 	if (script_list != NULL) {
428 		num_scripts = script_list->num_scripts;
429 	}
430 
431 	if (num_scripts <= 0) {
432 		return value;
433 	}
434 
435 	value->script = talloc_array(value,
436 				     struct ctdb_event_script,
437 				     num_scripts);
438 	if (value->script == NULL) {
439 		goto fail;
440 	}
441 
442 	for (i=0; i<num_scripts; i++) {
443 		struct run_event_script *rscript = &script_list->script[i];
444 		struct ctdb_event_script *escript = &value->script[i];
445 
446 		escript->name = talloc_strdup(value, rscript->name);
447 		if (escript->name == NULL) {
448 			goto fail;
449 		}
450 
451 		escript->begin = rscript->begin;
452 		escript->end = rscript->end;
453 		escript->result = rscript->summary;
454 
455 		if (rscript->output == NULL) {
456 			escript->output = NULL;
457 			continue;
458 		}
459 
460 		escript->output = talloc_strdup(value, rscript->output);
461 		if (escript->output == NULL) {
462 			goto fail;
463 		}
464 	}
465 	value->num_scripts = num_scripts;
466 
467 	return value;
468 
469 fail:
470 	talloc_free(value);
471 	return NULL;
472 }
473