we only need to switch into client mode from the eventscript child if we are running...
[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         if (!strcmp(options, "monitor")) {
303                 is_monitor = 1;
304         }
305
306         if (is_monitor == 1) {
307                 /* This is running in the forked child process. At this stage
308                  * we want to switch from being a ctdb daemon into being a
309                  * client and connect to the real local daemon.
310                  */
311                 if (switch_from_server_to_client(ctdb) != 0) {
312                         DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch eventscript child into client mode. shutting down.\n"));
313                         _exit(1);
314                 }
315
316                 if (ctdb_ctrl_event_script_init(ctdb) != 0) {
317                         DEBUG(DEBUG_ERR,(__location__ " Failed to init event script monitoring\n"));
318                         talloc_free(tmp_ctx);
319                         return -1;
320                 }
321         }
322
323         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
324                 /* we guarantee that only some specifically allowed event scripts are run
325                    while in recovery */
326                 const char *allowed_scripts[] = {"startrecovery", "shutdown", "releaseip" };
327                 int i;
328                 for (i=0;i<ARRAY_SIZE(allowed_scripts);i++) {
329                         if (strncmp(options, allowed_scripts[i], strlen(allowed_scripts[i])) == 0) break;
330                 }
331                 if (i == ARRAY_SIZE(allowed_scripts)) {
332                         DEBUG(DEBUG_ERR,("Refusing to run event scripts with option '%s' while in recovery\n",
333                                  options));
334                         talloc_free(tmp_ctx);
335                         return -1;
336                 }
337         }
338
339         if (setpgid(0,0) != 0) {
340                 DEBUG(DEBUG_ERR,("Failed to create process group for event scripts - %s\n",
341                          strerror(errno)));
342                 talloc_free(tmp_ctx);
343                 return -1;              
344         }
345
346         signal(SIGTERM, sigterm);
347
348         child_state.start = timeval_current();
349         child_state.script_running = "startup";
350
351         /*
352           the service specific event scripts 
353         */
354         if (stat(ctdb->event_script_dir, &st) != 0 && 
355             errno == ENOENT) {
356                 DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
357                 talloc_free(tmp_ctx);
358                 return -1;
359         }
360
361         /* create a tree to store all the script names in */
362         tree = trbt_create(tmp_ctx, 0);
363
364         /* scan all directory entries and insert all valid scripts into the 
365            tree
366         */
367         dir = opendir(ctdb->event_script_dir);
368         if (dir == NULL) {
369                 DEBUG(DEBUG_CRIT,("Failed to open event script directory '%s'\n", ctdb->event_script_dir));
370                 talloc_free(tmp_ctx);
371                 return -1;
372         }
373
374         count = 0;
375         while ((de=readdir(dir)) != NULL) {
376                 int namlen;
377                 unsigned num;
378                 char *str;
379
380                 namlen = strlen(de->d_name);
381
382                 if (namlen < 3) {
383                         continue;
384                 }
385
386                 if (de->d_name[namlen-1] == '~') {
387                         /* skip files emacs left behind */
388                         continue;
389                 }
390
391                 if (de->d_name[2] != '.') {
392                         continue;
393                 }
394
395                 if (sscanf(de->d_name, "%02u.", &num) != 1) {
396                         continue;
397                 }
398
399                 /* Make sure the event script is executable */
400                 str = talloc_asprintf(tree, "%s/%s", ctdb->event_script_dir, de->d_name);
401                 if (stat(str, &st) != 0) {
402                         DEBUG(DEBUG_ERR,("Could not stat event script %s. Ignoring this event script\n", str));
403                         continue;
404                 }
405                 if (!(st.st_mode & S_IXUSR)) {
406                         DEBUG(DEBUG_ERR,("Event script %s is not executable. Ignoring this event script\n", str));
407                         continue;
408                 }
409                 
410                 
411                 /* store the event script in the tree */
412                 trbt_insert32(tree, (num<<16)|count++, talloc_strdup(tree, de->d_name));
413         }
414         closedir(dir);
415
416         /* fetch the scripts from the tree one by one and execute
417            them
418          */
419         while ((script=trbt_findfirstarray32(tree, 1)) != NULL) {
420                 cmdstr = talloc_asprintf(tmp_ctx, "%s/%s %s", 
421                                 ctdb->event_script_dir,
422                                 script, options);
423                 CTDB_NO_MEMORY(ctdb, cmdstr);
424
425                 DEBUG(DEBUG_INFO,("Executing event script %s\n",cmdstr));
426
427                 child_state.start = timeval_current();
428                 child_state.script_running = cmdstr;
429
430                 if (is_monitor == 1) {
431                         if (ctdb_ctrl_event_script_start(ctdb, script) != 0) {
432                                 DEBUG(DEBUG_ERR,(__location__ " Failed to start event script monitoring\n"));
433                                 talloc_free(tmp_ctx);
434                                 return -1;
435                         }
436                 }
437
438                 ret = system(cmdstr);
439                 /* if the system() call was successful, translate ret into the
440                    return code from the command
441                 */
442                 if (ret != -1) {
443                         ret = WEXITSTATUS(ret);
444                 }
445                 if (is_monitor == 1) {
446                         if (ctdb_ctrl_event_script_stop(ctdb, ret) != 0) {
447                                 DEBUG(DEBUG_ERR,(__location__ " Failed to stop event script monitoring\n"));
448                                 talloc_free(tmp_ctx);
449                                 return -1;
450                         }
451                 }
452
453                 /* return an error if the script failed */
454                 if (ret != 0) {
455                         DEBUG(DEBUG_ERR,("Event script %s failed with error %d\n", cmdstr, ret));
456                         if (is_monitor == 1) {
457                                 if (ctdb_ctrl_event_script_finished(ctdb) != 0) {
458                                         DEBUG(DEBUG_ERR,(__location__ " Failed to finish event script monitoring\n"));
459                                         talloc_free(tmp_ctx);
460                                         return -1;
461                                 }
462                         }
463
464                         talloc_free(tmp_ctx);
465                         return ret;
466                 }
467
468                 /* remove this script from the tree */
469                 talloc_free(script);
470         }
471
472         child_state.start = timeval_current();
473         child_state.script_running = "finished";
474         
475         if (is_monitor == 1) {
476                 if (ctdb_ctrl_event_script_finished(ctdb) != 0) {
477                         DEBUG(DEBUG_ERR,(__location__ " Failed to finish event script monitoring\n"));
478                         talloc_free(tmp_ctx);
479                         return -1;
480                 }
481         }
482
483         talloc_free(tmp_ctx);
484         return 0;
485 }
486
487 /* called when child is finished */
488 static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde, 
489                                       uint16_t flags, void *p)
490 {
491         struct ctdb_event_script_state *state = 
492                 talloc_get_type(p, struct ctdb_event_script_state);
493         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
494         void *private_data = state->private_data;
495         struct ctdb_context *ctdb = state->ctdb;
496         signed char rt = -1;
497
498         read(state->fd[0], &rt, sizeof(rt));
499
500         talloc_set_destructor(state, NULL);
501         talloc_free(state);
502         callback(ctdb, rt, private_data);
503
504         ctdb->event_script_timeouts = 0;
505 }
506
507 static void ctdb_ban_self(struct ctdb_context *ctdb, uint32_t ban_period)
508 {
509         int ret;
510         struct ctdb_ban_info b;
511         TDB_DATA data;
512
513         b.pnn      = ctdb->pnn;
514         b.ban_time = ban_period;
515
516         data.dptr = (uint8_t *)&b;
517         data.dsize = sizeof(b);
518
519         ret = ctdb_daemon_send_message(ctdb, CTDB_BROADCAST_CONNECTED,
520                 CTDB_SRVID_BAN_NODE, data);
521         if (ret != 0) {
522                 DEBUG(DEBUG_ERR,(__location__ " Failed to send ban message\n"));
523         }
524 }
525
526
527 /* called when child times out */
528 static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, 
529                                       struct timeval t, void *p)
530 {
531         struct ctdb_event_script_state *state = talloc_get_type(p, struct ctdb_event_script_state);
532         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
533         void *private_data = state->private_data;
534         struct ctdb_context *ctdb = state->ctdb;
535         char *options;
536         struct ctdb_monitoring_status *monitoring_status =
537                 talloc_get_type(ctdb->script_monitoring_ctx,
538                         struct ctdb_monitoring_status);
539
540         DEBUG(DEBUG_ERR,("Event script timed out : %s count : %u\n", state->options, ctdb->event_script_timeouts));
541
542         options = talloc_strdup(ctdb, state->options);
543         CTDB_NO_MEMORY_VOID(ctdb, options);
544
545         talloc_free(state);
546         if (!strcmp(options, "monitor")) {
547                 /* if it is a monitor event, we allow it to "hang" a few times
548                    before we declare it a failure and ban ourself (and make
549                    ourself unhealthy)
550                 */
551                 DEBUG(DEBUG_ERR, (__location__ " eventscript for monitor event timedout.\n"));
552
553                 ctdb->event_script_timeouts++;
554                 if (ctdb->event_script_timeouts > ctdb->tunable.script_ban_count) {
555                         ctdb->event_script_timeouts = 0;
556                         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));
557                         ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
558                         callback(ctdb, -1, private_data);
559                 } else {
560                         callback(ctdb, 0, private_data);
561                 }
562         } else if (!strcmp(options, "startup")) {
563                 DEBUG(DEBUG_ERR, (__location__ " eventscript for startup event timedout.\n"));
564                 callback(ctdb, -1, private_data);
565         } else {
566                 /* if it is not a monitor event we ban ourself immediately */
567                 DEBUG(DEBUG_ERR, (__location__ " eventscript for NON-monitor/NON-startup event timedout. Immediately banning ourself for %d seconds\n", ctdb->tunable.recovery_ban_period));
568                 ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
569                 callback(ctdb, -1, private_data);
570         }
571
572         if (monitoring_status != NULL) {
573                 struct ctdb_monitor_script_status *script;
574
575                 script = monitoring_status->scripts;
576                 if (script != NULL) {
577                         script->timedout = 1;
578                 }
579                 monitoring_status->status = MONITOR_SCRIPT_TIMEOUT;
580                 if (ctdb->last_monitoring_ctx) {
581                         talloc_free(ctdb->last_monitoring_ctx);
582                         ctdb->last_monitoring_ctx = ctdb->script_monitoring_ctx;
583                         ctdb->script_monitoring_ctx = NULL;
584                 }
585         }
586
587         talloc_free(options);
588 }
589
590 /*
591   destroy a running event script
592  */
593 static int event_script_destructor(struct ctdb_event_script_state *state)
594 {
595         DEBUG(DEBUG_ERR,(__location__ " Sending SIGTERM to child pid:%d\n", state->child));
596         kill(state->child, SIGTERM);
597         return 0;
598 }
599
600 /*
601   run the event script in the background, calling the callback when 
602   finished
603  */
604 static int ctdb_event_script_callback_v(struct ctdb_context *ctdb, 
605                                         struct timeval timeout,
606                                         TALLOC_CTX *mem_ctx,
607                                         void (*callback)(struct ctdb_context *, int, void *),
608                                         void *private_data,
609                                         const char *fmt, va_list ap)
610 {
611         struct ctdb_event_script_state *state;
612         int ret;
613
614         state = talloc(mem_ctx, struct ctdb_event_script_state);
615         CTDB_NO_MEMORY(ctdb, state);
616
617         state->ctdb = ctdb;
618         state->callback = callback;
619         state->private_data = private_data;
620         state->options = talloc_vasprintf(state, fmt, ap);
621         CTDB_NO_MEMORY(ctdb, state->options);
622         
623         ret = pipe(state->fd);
624         if (ret != 0) {
625                 talloc_free(state);
626                 return -1;
627         }
628
629         state->child = fork();
630
631         if (state->child == (pid_t)-1) {
632                 close(state->fd[0]);
633                 close(state->fd[1]);
634                 talloc_free(state);
635                 return -1;
636         }
637
638         if (state->child == 0) {
639                 signed char rt;
640
641                 close(state->fd[0]);
642                 set_close_on_exec(state->fd[1]);
643
644                 rt = ctdb_event_script_v(ctdb, state->options);
645                 while ((ret = write(state->fd[1], &rt, sizeof(rt))) != sizeof(rt)) {
646                         sleep(1);
647                 }
648                 _exit(rt);
649         }
650
651         talloc_set_destructor(state, event_script_destructor);
652
653         close(state->fd[1]);
654
655         event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
656                      ctdb_event_script_handler, state);
657
658         if (!timeval_is_zero(&timeout)) {
659                 event_add_timed(ctdb->ev, state, timeout, ctdb_event_script_timeout, state);
660         } else {
661                 DEBUG(DEBUG_ERR, (__location__ " eventscript %s called with no timeout\n", state->options));
662         }
663
664         return 0;
665 }
666
667
668 /*
669   run the event script in the background, calling the callback when 
670   finished
671  */
672 int ctdb_event_script_callback(struct ctdb_context *ctdb, 
673                                struct timeval timeout,
674                                TALLOC_CTX *mem_ctx,
675                                void (*callback)(struct ctdb_context *, int, void *),
676                                void *private_data,
677                                const char *fmt, ...)
678 {
679         va_list ap;
680         int ret;
681
682         va_start(ap, fmt);
683         ret = ctdb_event_script_callback_v(ctdb, timeout, mem_ctx, callback, private_data, fmt, ap);
684         va_end(ap);
685
686         return ret;
687 }
688
689
690 struct callback_status {
691         bool done;
692         int status;
693 };
694
695 /*
696   called when ctdb_event_script() finishes
697  */
698 static void event_script_callback(struct ctdb_context *ctdb, int status, void *private_data)
699 {
700         struct callback_status *s = (struct callback_status *)private_data;
701         s->done = true;
702         s->status = status;
703 }
704
705 /*
706   run the event script, waiting for it to complete. Used when the caller doesn't want to 
707   continue till the event script has finished.
708  */
709 int ctdb_event_script(struct ctdb_context *ctdb, const char *fmt, ...)
710 {
711         va_list ap;
712         int ret;
713         TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
714         struct callback_status status;
715
716         va_start(ap, fmt);
717         ret = ctdb_event_script_callback_v(ctdb, timeval_zero(), tmp_ctx, event_script_callback, &status, fmt, ap);
718         va_end(ap);
719
720         if (ret != 0) {
721                 talloc_free(tmp_ctx);
722                 return ret;
723         }
724
725         status.status = -1;
726         status.done = false;
727
728         while (status.done == false && event_loop_once(ctdb->ev) == 0) /* noop */;
729
730         talloc_free(tmp_ctx);
731
732         return status.status;
733 }
734
735
736 struct eventscript_callback_state {
737         struct ctdb_req_control *c;
738 };
739
740 /*
741   called when takeip event finishes
742  */
743 static void run_eventscripts_callback(struct ctdb_context *ctdb, int status, 
744                                  void *private_data)
745 {
746         struct eventscript_callback_state *state = 
747                 talloc_get_type(private_data, struct eventscript_callback_state);
748
749         ctdb_enable_monitoring(ctdb);
750
751         if (status != 0) {
752                 DEBUG(DEBUG_ERR,(__location__ " Failed to forcibly run eventscripts\n"));
753                 ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
754                 talloc_free(state);
755                 return;
756         }
757
758         /* the control succeeded */
759         ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
760         talloc_free(state);
761         return;
762 }
763
764 /*
765   A control to force running of the eventscripts from the ctdb client tool
766 */
767 int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
768                 struct ctdb_req_control *c,
769                 TDB_DATA indata, bool *async_reply)
770 {
771         int ret;
772         struct eventscript_callback_state *state;
773
774         /* kill off any previous invokations of forced eventscripts */
775         if (ctdb->eventscripts_ctx) {
776                 talloc_free(ctdb->eventscripts_ctx);
777         }
778         ctdb->eventscripts_ctx = talloc_new(ctdb);
779         CTDB_NO_MEMORY(ctdb, ctdb->eventscripts_ctx);
780
781         state = talloc(ctdb->eventscripts_ctx, struct eventscript_callback_state);
782         CTDB_NO_MEMORY(ctdb, state);
783
784         state->c = talloc_steal(state, c);
785
786         DEBUG(DEBUG_NOTICE,("Forced running of eventscripts with arguments %s\n", indata.dptr));
787
788         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
789                 DEBUG(DEBUG_ERR, (__location__ " Aborted running eventscript \"%s\" while in RECOVERY mode\n", indata.dptr));
790                 return -1;
791         }
792
793         ctdb_disable_monitoring(ctdb);
794
795         ret = ctdb_event_script_callback(ctdb, 
796                          timeval_current_ofs(ctdb->tunable.script_timeout, 0),
797                          state, run_eventscripts_callback, state,
798                          (const char *)indata.dptr);
799
800         if (ret != 0) {
801                 ctdb_enable_monitoring(ctdb);
802                 DEBUG(DEBUG_ERR,(__location__ " Failed to run eventscripts with arguments %s\n", indata.dptr));
803                 talloc_free(state);
804                 return -1;
805         }
806
807         /* tell ctdb_control.c that we will be replying asynchronously */
808         *async_reply = true;
809
810         return 0;
811 }
812