2d0ac40861246e51098841424e1cc480c9908387
[sahlberg/ctdb.git] / server / eventscript.c
1 /* 
2    event script handling
3
4    Copyright (C) Andrew Tridgell  2007
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 "includes.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
23 #include "system/dir.h"
24 #include "system/locale.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include "../common/rb_tree.h"
28
29 static struct {
30         struct timeval start;
31         const char *script_running;
32 } child_state;
33
34 /*
35   ctdbd sends us a SIGTERM when we should time out the current script
36  */
37 static void sigterm(int sig)
38 {
39         DEBUG(DEBUG_ERR,("Timed out running script '%s' after %.1f seconds\n", 
40                  child_state.script_running, timeval_elapsed(&child_state.start)));
41         /* all the child processes will be running in the same process group */
42         kill(-getpgrp(), SIGKILL);
43         exit(1);
44 }
45
46 struct ctdb_event_script_state {
47         struct ctdb_context *ctdb;
48         pid_t child;
49         void (*callback)(struct ctdb_context *, int, void *);
50         int fd[2];
51         void *private_data;
52         const char *options;
53 };
54
55
56 struct ctdb_monitor_script_status {
57         struct ctdb_monitor_script_status *next;
58         const char *name;
59         struct timeval start;
60         struct timeval finished;
61         int32_t status;
62         int32_t timedout;
63         char *output;
64 };
65
66 struct ctdb_monitoring_status {
67         struct timeval start;
68         struct timeval finished;
69         int32_t status;
70         struct ctdb_monitor_script_status *scripts;
71 };
72
73
74 /* called from ctdb_logging when we have received output on STDERR from
75  * one of the eventscripts
76  */
77 int ctdb_log_event_script_output(struct ctdb_context *ctdb, char *str, uint16_t len)
78 {
79         struct ctdb_monitoring_status *monitoring_status =
80                 talloc_get_type(ctdb->script_monitoring_ctx,
81                         struct ctdb_monitoring_status);
82         struct ctdb_monitor_script_status *script;
83
84         if (monitoring_status == NULL) {
85                 return -1;
86         }
87
88         script = monitoring_status->scripts;
89         if (script == NULL) {
90                 return -1;
91         }
92
93         if (script->output == NULL) {
94                 script->output = talloc_asprintf(script, "%*.*s", len, len, str);
95         } else {
96                 script->output = talloc_asprintf_append(script->output, "%*.*s", len, len, str);
97         }
98
99         return 0;
100 }
101
102 /* called from the event script child process when we are starting a new
103  * monitor event
104  */
105 int32_t ctdb_control_event_script_init(struct ctdb_context *ctdb)
106 {
107         struct ctdb_monitoring_status *monitoring_status;
108
109         DEBUG(DEBUG_INFO, ("event script init called\n"));
110         if (ctdb->script_monitoring_ctx != NULL) {
111                 talloc_free(ctdb->script_monitoring_ctx);
112                 ctdb->script_monitoring_ctx = NULL;
113         }
114
115         monitoring_status = talloc_zero(ctdb, struct ctdb_monitoring_status);
116         if (monitoring_status == NULL) {
117                 DEBUG(DEBUG_ERR, (__location__ " ERROR: Failed to talloc script_monitoring context\n"));
118                 return -1;
119         }
120
121         ctdb->script_monitoring_ctx = monitoring_status;
122         monitoring_status->start = timeval_current();   
123
124         return 0;
125 }
126
127
128 /* called from the event script child process when we are star running
129  * an eventscript
130  */
131 int32_t ctdb_control_event_script_start(struct ctdb_context *ctdb, TDB_DATA indata)
132 {
133         const char *name = (const char *)indata.dptr;
134         struct ctdb_monitoring_status *monitoring_status =
135                 talloc_get_type(ctdb->script_monitoring_ctx,
136                         struct ctdb_monitoring_status);
137         struct ctdb_monitor_script_status *script;
138
139         DEBUG(DEBUG_INFO, ("event script start called : %s\n", name));
140
141         if (monitoring_status == NULL) {
142                 DEBUG(DEBUG_ERR,(__location__ " script_status is NULL when starting to run script %s\n", name));
143                 return -1;
144         }
145
146         script = talloc_zero(monitoring_status, struct ctdb_monitor_script_status);
147         if (script == NULL) {
148                 DEBUG(DEBUG_ERR,(__location__ " Failed to talloc ctdb_monitor_script_status for script %s\n", name));
149                 return -1;
150         }
151
152         script->next  = monitoring_status->scripts;
153         script->name  = talloc_strdup(script, name);
154         script->start = timeval_current();
155         monitoring_status->scripts = script;
156
157         return 0;
158 }
159
160 /* called from the event script child process when we have finished running
161  * an eventscript
162  */
163 int32_t ctdb_control_event_script_stop(struct ctdb_context *ctdb, TDB_DATA indata)
164 {
165         int32_t res = *((int32_t *)indata.dptr);
166         struct ctdb_monitoring_status *monitoring_status =
167                 talloc_get_type(ctdb->script_monitoring_ctx,
168                         struct ctdb_monitoring_status);
169         struct ctdb_monitor_script_status *script;
170
171         DEBUG(DEBUG_INFO, ("event script stop called : %d\n", (int)res));
172
173         if (monitoring_status == NULL) {
174                 DEBUG(DEBUG_ERR,(__location__ " script_status is NULL when script finished.\n"));
175                 return -1;
176         }
177
178         script = monitoring_status->scripts;
179         if (script == NULL) {
180                 DEBUG(DEBUG_ERR,(__location__ " script is NULL when the script had finished\n"));
181                 return -1;
182         }
183
184         script->finished = timeval_current();
185         script->status   = res;
186
187         return 0;
188 }
189
190 /* called from the event script child process when we have completed a
191  * monitor event
192  */
193 int32_t ctdb_control_event_script_finished(struct ctdb_context *ctdb)
194 {
195         struct ctdb_monitoring_status *monitoring_status =
196                 talloc_get_type(ctdb->script_monitoring_ctx,
197                         struct ctdb_monitoring_status);
198
199         DEBUG(DEBUG_INFO, ("event script finished called\n"));
200
201         if (monitoring_status == NULL) {
202                 DEBUG(DEBUG_ERR,(__location__ " script_status is NULL when monitoring event finished\n"));
203                 return -1;
204         }
205
206         monitoring_status->finished = timeval_current();        
207         monitoring_status->status   = MONITOR_SCRIPT_OK;
208         if (ctdb->last_monitoring_ctx) {
209                 talloc_free(ctdb->last_monitoring_ctx);
210         }
211         ctdb->last_monitoring_ctx = ctdb->script_monitoring_ctx;
212         ctdb->script_monitoring_ctx = NULL;
213
214         return 0;
215 }
216
217 static struct ctdb_monitoring_wire *marshall_monitoring_scripts(TALLOC_CTX *mem_ctx, struct ctdb_monitoring_wire *monitoring_scripts, struct ctdb_monitor_script_status *script)
218 {
219         struct ctdb_monitoring_script_wire script_wire;
220         size_t size;
221
222         if (script == NULL) {
223                 return monitoring_scripts;
224         }
225         monitoring_scripts = marshall_monitoring_scripts(mem_ctx, monitoring_scripts, script->next);
226         if (monitoring_scripts == NULL) {
227                 return NULL;
228         }
229
230         bzero(&script_wire, sizeof(struct ctdb_monitoring_script_wire));
231         strncpy(script_wire.name, script->name, MAX_SCRIPT_NAME);
232         script_wire.start    = script->start;
233         script_wire.finished = script->finished;
234         script_wire.status   = script->status;
235         script_wire.timedout = script->timedout;
236         if (script->output != NULL) {
237                 strncpy(script_wire.output, script->output, MAX_SCRIPT_OUTPUT);
238         }
239
240         size = talloc_get_size(monitoring_scripts);
241         monitoring_scripts = talloc_realloc_size(mem_ctx, monitoring_scripts, size + sizeof(struct ctdb_monitoring_script_wire));
242         if (monitoring_scripts == NULL) {
243                 DEBUG(DEBUG_ERR,(__location__ " Failed to talloc_resize monitoring_scripts blob\n"));
244                 return NULL;
245         }
246
247         memcpy(&monitoring_scripts->scripts[monitoring_scripts->num_scripts], &script_wire, sizeof(script_wire));
248         monitoring_scripts->num_scripts++;
249         
250         return monitoring_scripts;
251 }
252
253 int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb, TDB_DATA *outdata)
254 {
255         struct ctdb_monitoring_status *monitoring_status =
256                 talloc_get_type(ctdb->last_monitoring_ctx,
257                         struct ctdb_monitoring_status);
258         struct ctdb_monitoring_wire *monitoring_scripts;
259
260         if (monitoring_status == NULL) {
261                 DEBUG(DEBUG_ERR,(__location__ " last_monitor_ctx is NULL when reading status\n"));
262                 return -1;
263         }
264
265         monitoring_scripts = talloc_size(outdata, offsetof(struct ctdb_monitoring_wire, scripts));
266         if (monitoring_scripts == NULL) {
267                 DEBUG(DEBUG_ERR,(__location__ " failed to talloc monitoring_scripts structure\n"));
268                 return -1;
269         }
270         
271         monitoring_scripts->num_scripts = 0;
272         monitoring_scripts = marshall_monitoring_scripts(outdata, monitoring_scripts, monitoring_status->scripts);
273         if (monitoring_scripts == NULL) {
274                 DEBUG(DEBUG_ERR,(__location__ " Monitoring scritps is NULL. can not return data to client\n"));
275                 return -1;
276         }
277
278         outdata->dsize = talloc_get_size(monitoring_scripts);
279         outdata->dptr  = (uint8_t *)monitoring_scripts;
280
281         return 0;
282 }
283
284 /*
285   run the event script - varargs version
286   this function is called and run in the context of a forked child
287   which allows it to do blocking calls such as system()
288  */
289 static int ctdb_event_script_v(struct ctdb_context *ctdb, const char *options)
290 {
291         char *cmdstr;
292         int ret;
293         struct stat st;
294         TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
295         trbt_tree_t *tree;
296         DIR *dir;
297         struct dirent *de;
298         char *script;
299         int count;
300         int is_monitor = 0;
301
302         /* This is running in the forked child process. At this stage
303          * we want to switch from being a ctdb daemon into being a client
304          * and connect to the local daemon.
305          */
306         if (switch_from_server_to_client(ctdb) != 0) {
307                 DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch eventscript child into client mode. shutting down.\n"));
308                 exit(1);
309         }
310
311         if (!strcmp(options, "monitor")) {
312                 is_monitor = 1;
313         }
314         if (is_monitor == 1) {
315                 if (ctdb_ctrl_event_script_init(ctdb) != 0) {
316                         DEBUG(DEBUG_ERR,(__location__ " Failed to init event script monitoring\n"));
317                         talloc_free(tmp_ctx);
318                         return -1;
319                 }
320         }
321
322         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
323                 /* we guarantee that only some specifically allowed event scripts are run
324                    while in recovery */
325                 const char *allowed_scripts[] = {"startrecovery", "shutdown", "releaseip" };
326                 int i;
327                 for (i=0;i<ARRAY_SIZE(allowed_scripts);i++) {
328                         if (strncmp(options, allowed_scripts[i], strlen(allowed_scripts[i])) == 0) break;
329                 }
330                 if (i == ARRAY_SIZE(allowed_scripts)) {
331                         DEBUG(DEBUG_ERR,("Refusing to run event scripts with option '%s' while in recovery\n",
332                                  options));
333                         talloc_free(tmp_ctx);
334                         return -1;
335                 }
336         }
337
338         if (setpgid(0,0) != 0) {
339                 DEBUG(DEBUG_ERR,("Failed to create process group for event scripts - %s\n",
340                          strerror(errno)));
341                 talloc_free(tmp_ctx);
342                 return -1;              
343         }
344
345         signal(SIGTERM, sigterm);
346
347         child_state.start = timeval_current();
348         child_state.script_running = "startup";
349
350         /*
351           the service specific event scripts 
352         */
353         if (stat(ctdb->event_script_dir, &st) != 0 && 
354             errno == ENOENT) {
355                 DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
356                 talloc_free(tmp_ctx);
357                 return -1;
358         }
359
360         /* create a tree to store all the script names in */
361         tree = trbt_create(tmp_ctx, 0);
362
363         /* scan all directory entries and insert all valid scripts into the 
364            tree
365         */
366         dir = opendir(ctdb->event_script_dir);
367         if (dir == NULL) {
368                 DEBUG(DEBUG_CRIT,("Failed to open event script directory '%s'\n", ctdb->event_script_dir));
369                 talloc_free(tmp_ctx);
370                 return -1;
371         }
372
373         count = 0;
374         while ((de=readdir(dir)) != NULL) {
375                 int namlen;
376                 unsigned num;
377                 char *str;
378
379                 namlen = strlen(de->d_name);
380
381                 if (namlen < 3) {
382                         continue;
383                 }
384
385                 if (de->d_name[namlen-1] == '~') {
386                         /* skip files emacs left behind */
387                         continue;
388                 }
389
390                 if (de->d_name[2] != '.') {
391                         continue;
392                 }
393
394                 if (sscanf(de->d_name, "%02u.", &num) != 1) {
395                         continue;
396                 }
397
398                 /* Make sure the event script is executable */
399                 str = talloc_asprintf(tree, "%s/%s", ctdb->event_script_dir, de->d_name);
400                 if (stat(str, &st) != 0) {
401                         DEBUG(DEBUG_ERR,("Could not stat event script %s. Ignoring this event script\n", str));
402                         continue;
403                 }
404                 if (!(st.st_mode & S_IXUSR)) {
405                         DEBUG(DEBUG_ERR,("Event script %s is not executable. Ignoring this event script\n", str));
406                         continue;
407                 }
408                 
409                 
410                 /* store the event script in the tree */
411                 trbt_insert32(tree, (num<<16)|count++, talloc_strdup(tree, de->d_name));
412         }
413         closedir(dir);
414
415         /* fetch the scripts from the tree one by one and execute
416            them
417          */
418         while ((script=trbt_findfirstarray32(tree, 1)) != NULL) {
419                 cmdstr = talloc_asprintf(tmp_ctx, "%s/%s %s", 
420                                 ctdb->event_script_dir,
421                                 script, options);
422                 CTDB_NO_MEMORY(ctdb, cmdstr);
423
424                 DEBUG(DEBUG_INFO,("Executing event script %s\n",cmdstr));
425
426                 child_state.start = timeval_current();
427                 child_state.script_running = cmdstr;
428
429                 if (is_monitor == 1) {
430                         if (ctdb_ctrl_event_script_start(ctdb, script) != 0) {
431                                 DEBUG(DEBUG_ERR,(__location__ " Failed to start event script monitoring\n"));
432                                 talloc_free(tmp_ctx);
433                                 return -1;
434                         }
435                 }
436
437                 ret = system(cmdstr);
438                 /* if the system() call was successful, translate ret into the
439                    return code from the command
440                 */
441                 if (ret != -1) {
442                         ret = WEXITSTATUS(ret);
443                 }
444                 if (is_monitor == 1) {
445                         if (ctdb_ctrl_event_script_stop(ctdb, ret) != 0) {
446                                 DEBUG(DEBUG_ERR,(__location__ " Failed to stop event script monitoring\n"));
447                                 talloc_free(tmp_ctx);
448                                 return -1;
449                         }
450                 }
451
452                 /* return an error if the script failed */
453                 if (ret != 0) {
454                         DEBUG(DEBUG_ERR,("Event script %s failed with error %d\n", cmdstr, ret));
455                         if (is_monitor == 1) {
456                                 if (ctdb_ctrl_event_script_finished(ctdb) != 0) {
457                                         DEBUG(DEBUG_ERR,(__location__ " Failed to finish event script monitoring\n"));
458                                         talloc_free(tmp_ctx);
459                                         return -1;
460                                 }
461                         }
462
463                         talloc_free(tmp_ctx);
464                         return ret;
465                 }
466
467                 /* remove this script from the tree */
468                 talloc_free(script);
469         }
470
471         child_state.start = timeval_current();
472         child_state.script_running = "finished";
473         
474         if (is_monitor == 1) {
475                 if (ctdb_ctrl_event_script_finished(ctdb) != 0) {
476                         DEBUG(DEBUG_ERR,(__location__ " Failed to finish event script monitoring\n"));
477                         talloc_free(tmp_ctx);
478                         return -1;
479                 }
480         }
481
482         talloc_free(tmp_ctx);
483         return 0;
484 }
485
486 /* called when child is finished */
487 static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde, 
488                                       uint16_t flags, void *p)
489 {
490         struct ctdb_event_script_state *state = 
491                 talloc_get_type(p, struct ctdb_event_script_state);
492         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
493         void *private_data = state->private_data;
494         struct ctdb_context *ctdb = state->ctdb;
495         signed char rt = -1;
496
497         read(state->fd[0], &rt, sizeof(rt));
498
499         talloc_set_destructor(state, NULL);
500         talloc_free(state);
501         callback(ctdb, rt, private_data);
502
503         ctdb->event_script_timeouts = 0;
504 }
505
506 static void ctdb_ban_self(struct ctdb_context *ctdb, uint32_t ban_period)
507 {
508         int ret;
509         struct ctdb_ban_info b;
510         TDB_DATA data;
511
512         b.pnn      = ctdb->pnn;
513         b.ban_time = ban_period;
514
515         data.dptr = (uint8_t *)&b;
516         data.dsize = sizeof(b);
517
518         ret = ctdb_daemon_send_message(ctdb, CTDB_BROADCAST_CONNECTED,
519                 CTDB_SRVID_BAN_NODE, data);
520         if (ret != 0) {
521                 DEBUG(DEBUG_ERR,(__location__ " Failed to send ban message\n"));
522         }
523 }
524
525
526 /* called when child times out */
527 static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, 
528                                       struct timeval t, void *p)
529 {
530         struct ctdb_event_script_state *state = talloc_get_type(p, struct ctdb_event_script_state);
531         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
532         void *private_data = state->private_data;
533         struct ctdb_context *ctdb = state->ctdb;
534         char *options;
535         struct ctdb_monitoring_status *monitoring_status =
536                 talloc_get_type(ctdb->script_monitoring_ctx,
537                         struct ctdb_monitoring_status);
538
539         DEBUG(DEBUG_ERR,("Event script timed out : %s count : %u\n", state->options, ctdb->event_script_timeouts));
540
541         options = talloc_strdup(ctdb, state->options);
542         CTDB_NO_MEMORY_VOID(ctdb, options);
543
544         talloc_free(state);
545         if (!strcmp(options, "monitor")) {
546                 /* if it is a monitor event, we allow it to "hang" a few times
547                    before we declare it a failure and ban ourself (and make
548                    ourself unhealthy)
549                 */
550                 DEBUG(DEBUG_ERR, (__location__ " eventscript for monitor event timedout.\n"));
551
552                 ctdb->event_script_timeouts++;
553                 if (ctdb->event_script_timeouts > ctdb->tunable.script_ban_count) {
554                         ctdb->event_script_timeouts = 0;
555                         DEBUG(DEBUG_ERR, ("Maximum timeout count %u reached for eventscript. Banning self for %d seconds\n", ctdb->tunable.script_ban_count, ctdb->tunable.recovery_ban_period));
556                         ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
557                         callback(ctdb, -1, private_data);
558                 } else {
559                         callback(ctdb, 0, private_data);
560                 }
561         } else if (!strcmp(options, "startup")) {
562                 DEBUG(DEBUG_ERR, (__location__ " eventscript for startup event timedout.\n"));
563                 callback(ctdb, -1, private_data);
564         } else {
565                 /* if it is not a monitor event we ban ourself immediately */
566                 DEBUG(DEBUG_ERR, (__location__ " eventscript for NON-monitor/NON-startup event timedout. Immediately banning ourself for %d seconds\n", ctdb->tunable.recovery_ban_period));
567                 ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
568                 callback(ctdb, -1, private_data);
569         }
570
571         if (monitoring_status != NULL) {
572                 struct ctdb_monitor_script_status *script;
573
574                 script = monitoring_status->scripts;
575                 if (script != NULL) {
576                         script->timedout = 1;
577                 }
578                 monitoring_status->status = MONITOR_SCRIPT_TIMEOUT;
579                 if (ctdb->last_monitoring_ctx) {
580                         talloc_free(ctdb->last_monitoring_ctx);
581                         ctdb->last_monitoring_ctx = ctdb->script_monitoring_ctx;
582                         ctdb->script_monitoring_ctx = NULL;
583                 }
584         }
585
586         talloc_free(options);
587 }
588
589 /*
590   destroy a running event script
591  */
592 static int event_script_destructor(struct ctdb_event_script_state *state)
593 {
594         DEBUG(DEBUG_ERR,(__location__ " Sending SIGTERM to child pid:%d\n", state->child));
595         kill(state->child, SIGTERM);
596         return 0;
597 }
598
599 /*
600   run the event script in the background, calling the callback when 
601   finished
602  */
603 static int ctdb_event_script_callback_v(struct ctdb_context *ctdb, 
604                                         struct timeval timeout,
605                                         TALLOC_CTX *mem_ctx,
606                                         void (*callback)(struct ctdb_context *, int, void *),
607                                         void *private_data,
608                                         const char *fmt, va_list ap)
609 {
610         struct ctdb_event_script_state *state;
611         int ret;
612
613         state = talloc(mem_ctx, struct ctdb_event_script_state);
614         CTDB_NO_MEMORY(ctdb, state);
615
616         state->ctdb = ctdb;
617         state->callback = callback;
618         state->private_data = private_data;
619         state->options = talloc_vasprintf(state, fmt, ap);
620         CTDB_NO_MEMORY(ctdb, state->options);
621         
622         ret = pipe(state->fd);
623         if (ret != 0) {
624                 talloc_free(state);
625                 return -1;
626         }
627
628         state->child = fork();
629
630         if (state->child == (pid_t)-1) {
631                 close(state->fd[0]);
632                 close(state->fd[1]);
633                 talloc_free(state);
634                 return -1;
635         }
636
637         if (state->child == 0) {
638                 signed char rt;
639
640                 close(state->fd[0]);
641                 set_close_on_exec(state->fd[1]);
642
643                 rt = ctdb_event_script_v(ctdb, state->options);
644                 while ((ret = write(state->fd[1], &rt, sizeof(rt))) != sizeof(rt)) {
645                         sleep(1);
646                 }
647                 _exit(rt);
648         }
649
650         talloc_set_destructor(state, event_script_destructor);
651
652         close(state->fd[1]);
653
654         event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
655                      ctdb_event_script_handler, state);
656
657         if (!timeval_is_zero(&timeout)) {
658                 event_add_timed(ctdb->ev, state, timeout, ctdb_event_script_timeout, state);
659         } else {
660                 DEBUG(DEBUG_ERR, (__location__ " eventscript %s called with no timeout\n", state->options));
661         }
662
663         return 0;
664 }
665
666
667 /*
668   run the event script in the background, calling the callback when 
669   finished
670  */
671 int ctdb_event_script_callback(struct ctdb_context *ctdb, 
672                                struct timeval timeout,
673                                TALLOC_CTX *mem_ctx,
674                                void (*callback)(struct ctdb_context *, int, void *),
675                                void *private_data,
676                                const char *fmt, ...)
677 {
678         va_list ap;
679         int ret;
680
681         va_start(ap, fmt);
682         ret = ctdb_event_script_callback_v(ctdb, timeout, mem_ctx, callback, private_data, fmt, ap);
683         va_end(ap);
684
685         return ret;
686 }
687
688
689 struct callback_status {
690         bool done;
691         int status;
692 };
693
694 /*
695   called when ctdb_event_script() finishes
696  */
697 static void event_script_callback(struct ctdb_context *ctdb, int status, void *private_data)
698 {
699         struct callback_status *s = (struct callback_status *)private_data;
700         s->done = true;
701         s->status = status;
702 }
703
704 /*
705   run the event script, waiting for it to complete. Used when the caller doesn't want to 
706   continue till the event script has finished.
707  */
708 int ctdb_event_script(struct ctdb_context *ctdb, const char *fmt, ...)
709 {
710         va_list ap;
711         int ret;
712         TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
713         struct callback_status status;
714
715         va_start(ap, fmt);
716         ret = ctdb_event_script_callback_v(ctdb, timeval_zero(), tmp_ctx, event_script_callback, &status, fmt, ap);
717         va_end(ap);
718
719         if (ret != 0) {
720                 talloc_free(tmp_ctx);
721                 return ret;
722         }
723
724         status.status = -1;
725         status.done = false;
726
727         while (status.done == false && event_loop_once(ctdb->ev) == 0) /* noop */;
728
729         talloc_free(tmp_ctx);
730
731         return status.status;
732 }
733
734
735 struct eventscript_callback_state {
736         struct ctdb_req_control *c;
737 };
738
739 /*
740   called when takeip event finishes
741  */
742 static void run_eventscripts_callback(struct ctdb_context *ctdb, int status, 
743                                  void *private_data)
744 {
745         struct eventscript_callback_state *state = 
746                 talloc_get_type(private_data, struct eventscript_callback_state);
747
748         ctdb_enable_monitoring(ctdb);
749
750         if (status != 0) {
751                 DEBUG(DEBUG_ERR,(__location__ " Failed to forcibly run eventscripts\n"));
752                 ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
753                 talloc_free(state);
754                 return;
755         }
756
757         /* the control succeeded */
758         ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
759         talloc_free(state);
760         return;
761 }
762
763 /*
764   A control to force running of the eventscripts from the ctdb client tool
765 */
766 int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
767                 struct ctdb_req_control *c,
768                 TDB_DATA indata, bool *async_reply)
769 {
770         int ret;
771         struct eventscript_callback_state *state;
772
773         /* kill off any previous invokations of forced eventscripts */
774         if (ctdb->eventscripts_ctx) {
775                 talloc_free(ctdb->eventscripts_ctx);
776         }
777         ctdb->eventscripts_ctx = talloc_new(ctdb);
778         CTDB_NO_MEMORY(ctdb, ctdb->eventscripts_ctx);
779
780         state = talloc(ctdb->eventscripts_ctx, struct eventscript_callback_state);
781         CTDB_NO_MEMORY(ctdb, state);
782
783         state->c = talloc_steal(state, c);
784
785         DEBUG(DEBUG_NOTICE,("Forced running of eventscripts with arguments %s\n", indata.dptr));
786
787         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
788                 DEBUG(DEBUG_ERR, (__location__ " Aborted running eventscript \"%s\" while in RECOVERY mode\n", indata.dptr));
789                 return -1;
790         }
791
792         ctdb_disable_monitoring(ctdb);
793
794         ret = ctdb_event_script_callback(ctdb, 
795                          timeval_current_ofs(ctdb->tunable.script_timeout, 0),
796                          state, run_eventscripts_callback, state,
797                          (const char *)indata.dptr);
798
799         if (ret != 0) {
800                 ctdb_enable_monitoring(ctdb);
801                 DEBUG(DEBUG_ERR,(__location__ " Failed to run eventscripts with arguments %s\n", indata.dptr));
802                 talloc_free(state);
803                 return -1;
804         }
805
806         /* tell ctdb_control.c that we will be replying asynchronously */
807         *async_reply = true;
808
809         return 0;
810 }
811