Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cmd.h"
6 : #include "../cntr.h"
7 : #include "../conf.h"
8 : #include "../cstat.h"
9 : #include "../handy.h"
10 : #include "../iobuf.h"
11 : #include "../log.h"
12 : #include "../prepend.h"
13 : #include "../run_script.h"
14 : #include "extra_comms.h"
15 : #include "monitor/status_server.h"
16 : #include "run_action.h"
17 : #include "child.h"
18 : #include "timer.h"
19 :
20 : static struct asfd *wasfd=NULL;
21 :
22 : static enum action act=ACTION_UNSET;
23 :
24 1035 : static int write_status(
25 : enum cntr_status cntr_status,
26 : const char *path,
27 : struct cntr *cntr,
28 : time_t now
29 : ) {
30 : static size_t l=0;
31 : static struct iobuf *wbuf=NULL;
32 : static time_t lasttime=0;
33 1035 : time_t diff=0;
34 :
35 : // Only update every 2 seconds.
36 1035 : diff=now-lasttime;
37 1035 : if(diff<2)
38 : {
39 : // Might as well do this in case they fiddled their
40 : // clock back in time.
41 1026 : if(diff<0) lasttime=now;
42 : return 0;
43 : }
44 9 : lasttime=now;
45 :
46 9 : if(!wasfd) return 0;
47 0 : if(!cntr || !cntr->bno)
48 : return 0;
49 :
50 : // Only get a new string if we did not manage to write the previous
51 : // one.
52 0 : if(!l)
53 : {
54 0 : cntr->cntr_status=cntr_status;
55 0 : if(!(l=cntr_to_str(cntr, path))) goto error;
56 0 : if(!wbuf && !(wbuf=iobuf_alloc())) goto error;
57 0 : iobuf_set(wbuf, CMD_APPEND, cntr->str, l);
58 : }
59 :
60 0 : switch(wasfd->append_all_to_write_buffer(wasfd, wbuf))
61 : {
62 : case APPEND_OK:
63 0 : l=0; // Fall through.
64 : case APPEND_BLOCKED:
65 : return 0;
66 : default:
67 : break;
68 : }
69 : error:
70 0 : iobuf_free(&wbuf);
71 0 : return -1;
72 : }
73 :
74 0 : static int check_timer_script(
75 : enum cntr_status cntr_status,
76 : struct asfd *asfd,
77 : struct sdirs *sdirs,
78 : struct conf **confs,
79 : time_t now
80 : ) {
81 : int interval;
82 0 : time_t diff=0;
83 : static time_t lasttime=0;
84 :
85 0 : if(cntr_status!=CNTR_STATUS_SCANNING
86 0 : && cntr_status!=CNTR_STATUS_BACKUP)
87 : return 0;
88 :
89 : // The conf is in minutes, so multiply by 60 to get seconds.
90 0 : interval=get_int(confs[OPT_TIMER_REPEAT_INTERVAL]) * 60;
91 0 : if (!interval)
92 : return 0;
93 :
94 0 : diff=now-lasttime;
95 0 : if(diff<interval)
96 : {
97 : // Might as well do this in case they fiddled their
98 : // clock back in time.
99 0 : if(diff<0) lasttime=now;
100 : return 0;
101 : }
102 0 : lasttime=now;
103 :
104 0 : return run_timer(
105 : asfd,
106 : sdirs,
107 : confs
108 : );
109 : }
110 :
111 1066 : int timed_operation(
112 : enum cntr_status cntr_status,
113 : const char *path,
114 : struct asfd *asfd,
115 : struct sdirs *sdirs,
116 : struct conf **confs
117 : ) {
118 1066 : time_t now=0;
119 :
120 1066 : if(!confs) return 0;
121 :
122 1035 : now=time(NULL);
123 :
124 1035 : if(write_status(cntr_status, path, get_cntr(confs), now))
125 : return -1;
126 :
127 1035 : if(act!=ACTION_BACKUP_TIMED)
128 : return 0;
129 0 : return check_timer_script(cntr_status,
130 : asfd, sdirs, confs, now);
131 : }
132 :
133 145 : int timed_operation_status_only(
134 : enum cntr_status cntr_status,
135 : const char *path,
136 : struct conf **confs
137 : ) {
138 145 : return timed_operation(
139 : cntr_status,
140 : path,
141 : NULL, /*asfd*/
142 : NULL, /*sdirs*/
143 : confs
144 : );
145 : }
146 :
147 0 : static int run_server_script(struct asfd *asfd,
148 : const char *pre_or_post,
149 : const char *action_from_client,
150 : const char *script, struct strlist *script_arg,
151 : uint8_t notify, struct conf **cconfs, int backup_ret, int timer_ret)
152 : {
153 0 : int a=0;
154 0 : int ret=0;
155 0 : char *logbuf=NULL;
156 : const char *args[12];
157 0 : const char *cname=get_string(cconfs[OPT_CNAME]);
158 :
159 0 : args[a++]=script;
160 0 : args[a++]=pre_or_post;
161 0 : args[a++]=action_from_client;
162 0 : args[a++]=cname;
163 0 : args[a++]=backup_ret?"1":"0", // Indicate success or failure.
164 : // Indicate whether the timer script said OK or not.
165 0 : args[a++]=timer_ret?"1":"0",
166 0 : args[a++]=NULL;
167 :
168 : // Do not have a client storage directory, so capture the
169 : // output in a buffer to pass to the notification script.
170 0 : if(run_script_to_buf(asfd, args, script_arg, cconfs, 1, 1, 0, &logbuf))
171 : {
172 : char msg[256];
173 0 : snprintf(msg, sizeof(msg),
174 : "server %s script %s returned an error",
175 : pre_or_post, script);
176 0 : log_and_send(asfd, msg);
177 0 : ret=-1;
178 0 : if(!notify) goto end;
179 :
180 : // If this is a backup failure and the client has more servers
181 : // to failover to, do not notify.
182 0 : if(!strncmp_w(action_from_client, "backup")
183 0 : && get_int(cconfs[OPT_N_FAILURE_BACKUP_FAILOVERS_LEFT])
184 0 : && get_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT]))
185 : goto end;
186 :
187 0 : a=0;
188 0 : args[a++]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
189 0 : args[a++]=cname;
190 : // magic - set basedir blank and the
191 : // notify script will know to get the content
192 : // from the next argument (usually storagedir)
193 0 : args[a++]=""; // usually basedir
194 0 : args[a++]=logbuf?logbuf:""; //usually storagedir
195 0 : args[a++]=""; // usually file
196 0 : args[a++]=""; // usually brv
197 0 : args[a++]=""; // usually warnings
198 0 : args[a++]=NULL;
199 0 : run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
200 : cconfs, 1, 1, 0);
201 : }
202 : end:
203 0 : free_w(&logbuf);
204 0 : return ret;
205 : }
206 :
207 0 : static char *get_action_from_client(const char *buf)
208 : {
209 0 : char *cp=NULL;
210 0 : char *ret=NULL;
211 :
212 0 : if(buf)
213 : {
214 0 : if(!strcmp(buf, "backupphase1"))
215 : {
216 0 : act=ACTION_BACKUP;
217 0 : return strdup_w("backup", __func__);
218 : }
219 0 : if(!strcmp(buf, "backupphase1timed"))
220 : {
221 0 : act=ACTION_BACKUP_TIMED;
222 0 : return strdup_w("backup_timed", __func__);
223 : }
224 : }
225 :
226 0 : if(!(ret=strdup_w(buf?buf:"", __func__)))
227 : return NULL;
228 0 : if((cp=strchr(ret, ' ')))
229 0 : *cp='\0';
230 : return ret;
231 : }
232 :
233 0 : int child(struct async *as, int is_status_server,
234 : int status_wfd, struct conf **confs, struct conf **cconfs)
235 : {
236 0 : int ret=-1;
237 0 : int srestore=0;
238 0 : int timer_ret=0;
239 0 : char *incexc=NULL;
240 0 : char *action_from_client=NULL;
241 : const char *confs_user;
242 : const char *cconfs_user;
243 : const char *confs_group;
244 : const char *cconfs_group;
245 : const char *s_script_pre;
246 : const char *s_script_post;
247 :
248 : // If we are not a status server, we are a normal child - set up the
249 : // parent socket to write status to.
250 0 : if(status_wfd>0)
251 : {
252 0 : if(!(wasfd=setup_asfd(as, "child status pipe", &status_wfd,
253 : /*listen*/"")))
254 : goto end;
255 0 : wasfd->attempt_reads=0;
256 : }
257 : /* Has to be before the chuser/chgrp stuff to allow clients to switch
258 : to different clients when both clients have different user/group
259 : settings. */
260 0 : if(extra_comms(as, &incexc, &srestore, confs, cconfs))
261 : {
262 0 : log_and_send(as->asfd, "running extra comms failed on server");
263 0 : goto end;
264 : }
265 :
266 : // Needs to happen after extra_comms, in case extra_comms resets them.
267 0 : confs_user=get_string(confs[OPT_USER]);
268 0 : cconfs_user=get_string(cconfs[OPT_USER]);
269 0 : confs_group=get_string(confs[OPT_GROUP]);
270 0 : cconfs_group=get_string(cconfs[OPT_GROUP]);
271 :
272 : /* Now that the client conf is loaded, we might want to chuser or
273 : chgrp.
274 : The main process could have already done this, so we don't want
275 : to try doing it again if cconfs has the same values, because it
276 : will fail. */
277 0 : if( (!confs_user || (cconfs_user && strcmp(confs_user, cconfs_user)))
278 0 : ||(!confs_group ||(cconfs_group && strcmp(confs_group,cconfs_group))))
279 : {
280 0 : if(chuser_and_or_chgrp(cconfs_user, cconfs_group, 0))
281 : {
282 0 : log_and_send(as->asfd,
283 : "chuser_and_or_chgrp failed on server");
284 0 : goto end;
285 : }
286 : }
287 :
288 0 : if(as->asfd->read(as->asfd))
289 : goto end;
290 :
291 : // If this is a status server, run the status server.
292 0 : if(is_status_server)
293 : {
294 0 : ret=status_server(as, cconfs);
295 0 : goto end;
296 : }
297 :
298 0 : if(!(action_from_client=get_action_from_client(as->asfd->rbuf->buf)))
299 : goto end;
300 0 : ret=0;
301 :
302 0 : s_script_pre=get_string(cconfs[OPT_S_SCRIPT_PRE]);
303 0 : s_script_post=get_string(cconfs[OPT_S_SCRIPT_POST]);
304 :
305 : // FIX THIS: Make the script components part of a struct, and just
306 : // pass in the correct struct. Same below.
307 :
308 0 : if(s_script_pre)
309 0 : ret=run_server_script(as->asfd, "pre", action_from_client,
310 : s_script_pre,
311 : get_strlist(cconfs[OPT_S_SCRIPT_PRE_ARG]),
312 0 : get_int(cconfs[OPT_S_SCRIPT_PRE_NOTIFY]),
313 : cconfs, ret, timer_ret);
314 :
315 0 : if(!ret)
316 0 : ret=run_action_server(as, incexc, srestore, &timer_ret, cconfs);
317 :
318 0 : if(!s_script_post)
319 : goto end;
320 0 : if(ret && !get_int(cconfs[OPT_S_SCRIPT_POST_RUN_ON_FAIL]))
321 : goto end;
322 0 : ret=run_server_script(as->asfd, "post", action_from_client,
323 : s_script_post,
324 : get_strlist(cconfs[OPT_S_SCRIPT_POST_ARG]),
325 0 : get_int(cconfs[OPT_S_SCRIPT_POST_NOTIFY]),
326 : cconfs, ret, timer_ret);
327 :
328 : end:
329 0 : free_w(&action_from_client);
330 0 : return ret;
331 : }
|