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