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 :
19 : static struct asfd *wasfd=NULL;
20 :
21 218120 : int write_status(enum cntr_status cntr_status,
22 : const char *path, struct cntr *cntr)
23 : {
24 218120 : time_t now=0;
25 218120 : time_t diff=0;
26 : static time_t lasttime=0;
27 : static size_t l=0;
28 : static struct iobuf *wbuf=NULL;
29 :
30 218120 : if(!wasfd) return 0;
31 0 : if(!cntr || !cntr->bno)
32 : return 0;
33 :
34 : // Only update every 2 seconds.
35 0 : now=time(NULL);
36 0 : diff=now-lasttime;
37 0 : if(diff<2)
38 : {
39 : // Might as well do this in case they fiddled their
40 : // clock back in time.
41 0 : if(diff<0) lasttime=now;
42 : return 0;
43 : }
44 0 : lasttime=now;
45 :
46 : // Only get a new string if we did not manage to write the previous
47 : // one.
48 0 : if(!l)
49 : {
50 0 : cntr->cntr_status=cntr_status;
51 0 : if(!(l=cntr_to_str(cntr, path))) goto error;
52 0 : if(!wbuf && !(wbuf=iobuf_alloc())) goto error;
53 0 : iobuf_set(wbuf, CMD_APPEND, cntr->str, l);
54 : }
55 :
56 0 : switch(wasfd->append_all_to_write_buffer(wasfd, wbuf))
57 : {
58 : case APPEND_OK:
59 0 : l=0; // Fall through.
60 : case APPEND_BLOCKED:
61 : return 0;
62 : default:
63 : break;
64 : }
65 : error:
66 0 : iobuf_free(&wbuf);
67 0 : return -1;
68 : }
69 :
70 0 : static int run_server_script(struct asfd *asfd,
71 : const char *pre_or_post,
72 : const char *action_from_client,
73 : const char *script, struct strlist *script_arg,
74 : uint8_t notify, struct conf **cconfs, int backup_ret, int timer_ret)
75 : {
76 0 : int a=0;
77 0 : int ret=0;
78 0 : char *logbuf=NULL;
79 : const char *args[12];
80 0 : const char *cname=get_string(cconfs[OPT_CNAME]);
81 :
82 0 : args[a++]=script;
83 0 : args[a++]=pre_or_post;
84 0 : args[a++]=action_from_client;
85 0 : args[a++]=cname;
86 0 : args[a++]=backup_ret?"1":"0", // Indicate success or failure.
87 : // Indicate whether the timer script said OK or not.
88 0 : args[a++]=timer_ret?"1":"0",
89 0 : args[a++]=NULL;
90 :
91 : // Do not have a client storage directory, so capture the
92 : // output in a buffer to pass to the notification script.
93 0 : if(run_script_to_buf(asfd, args, script_arg, cconfs, 1, 1, 0, &logbuf))
94 : {
95 : char msg[256];
96 0 : snprintf(msg, sizeof(msg),
97 : "server %s script %s returned an error",
98 : pre_or_post, script);
99 0 : log_and_send(asfd, msg);
100 0 : ret=-1;
101 0 : if(!notify) goto end;
102 :
103 : // If this is a backup failure and the client has more servers
104 : // to failover to, do not notify.
105 0 : if(!strncmp_w(action_from_client, "backup")
106 0 : && get_int(cconfs[OPT_N_FAILURE_BACKUP_FAILOVERS_LEFT])
107 0 : && get_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT]))
108 : goto end;
109 :
110 0 : a=0;
111 0 : args[a++]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
112 0 : args[a++]=cname;
113 : // magic - set basedir blank and the
114 : // notify script will know to get the content
115 : // from the next argument (usually storagedir)
116 0 : args[a++]=""; // usually basedir
117 0 : args[a++]=logbuf?logbuf:""; //usually storagedir
118 0 : args[a++]=""; // usually file
119 0 : args[a++]=""; // usually brv
120 0 : args[a++]=""; // usually warnings
121 0 : args[a++]=NULL;
122 0 : run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
123 : cconfs, 1, 1, 0);
124 : }
125 : end:
126 0 : free_w(&logbuf);
127 0 : return ret;
128 : }
129 :
130 0 : static char *get_action_from_client(const char *buf)
131 : {
132 0 : char *cp=NULL;
133 0 : char *ret=NULL;
134 :
135 0 : if(buf)
136 : {
137 0 : if(!strcmp(buf, "backupphase1"))
138 0 : return strdup_w("backup", __func__);
139 0 : if(!strcmp(buf, "backupphase1timed"))
140 0 : return strdup_w("backup_timed", __func__);
141 : }
142 :
143 0 : if(!(ret=strdup_w(buf?buf:"", __func__)))
144 : return NULL;
145 0 : if((cp=strchr(ret, ' ')))
146 0 : *cp='\0';
147 : return ret;
148 : }
149 :
150 0 : int child(struct async *as, int is_status_server,
151 : int status_wfd, struct conf **confs, struct conf **cconfs)
152 : {
153 0 : int ret=-1;
154 0 : int srestore=0;
155 0 : int timer_ret=0;
156 0 : char *incexc=NULL;
157 0 : char *action_from_client=NULL;
158 : const char *confs_user;
159 : const char *cconfs_user;
160 : const char *confs_group;
161 : const char *cconfs_group;
162 : const char *s_script_pre;
163 : const char *s_script_post;
164 :
165 : // If we are not a status server, we are a normal child - set up the
166 : // parent socket to write status to.
167 0 : if(status_wfd>0)
168 : {
169 0 : if(!(wasfd=setup_asfd(as, "child status pipe", &status_wfd,
170 : /*listen*/"")))
171 : goto end;
172 0 : wasfd->attempt_reads=0;
173 : }
174 :
175 : /* Has to be before the chuser/chgrp stuff to allow clients to switch
176 : to different clients when both clients have different user/group
177 : settings. */
178 0 : if(extra_comms(as, &incexc, &srestore, confs, cconfs))
179 : {
180 0 : log_and_send(as->asfd, "running extra comms failed on server");
181 0 : goto end;
182 : }
183 :
184 : // Needs to happen after extra_comms, in case extra_comms resets them.
185 0 : confs_user=get_string(confs[OPT_USER]);
186 0 : cconfs_user=get_string(cconfs[OPT_USER]);
187 0 : confs_group=get_string(confs[OPT_GROUP]);
188 0 : cconfs_group=get_string(cconfs[OPT_GROUP]);
189 :
190 : /* Now that the client conf is loaded, we might want to chuser or
191 : chgrp.
192 : The main process could have already done this, so we don't want
193 : to try doing it again if cconfs has the same values, because it
194 : will fail. */
195 0 : if( (!confs_user || (cconfs_user && strcmp(confs_user, cconfs_user)))
196 0 : ||(!confs_group ||(cconfs_group && strcmp(confs_group,cconfs_group))))
197 : {
198 0 : if(chuser_and_or_chgrp(cconfs_user, cconfs_group))
199 : {
200 0 : log_and_send(as->asfd,
201 : "chuser_and_or_chgrp failed on server");
202 0 : goto end;
203 : }
204 : }
205 :
206 0 : if(as->asfd->read(as->asfd)) goto end;
207 :
208 : // If this is a status server, run the status server.
209 0 : if(is_status_server)
210 : {
211 0 : ret=status_server(as, cconfs);
212 0 : goto end;
213 : }
214 :
215 0 : if(!(action_from_client=get_action_from_client(as->asfd->rbuf->buf)))
216 : goto end;
217 0 : ret=0;
218 :
219 0 : s_script_pre=get_string(cconfs[OPT_S_SCRIPT_PRE]);
220 0 : s_script_post=get_string(cconfs[OPT_S_SCRIPT_POST]);
221 :
222 : // FIX THIS: Make the script components part of a struct, and just
223 : // pass in the correct struct. Same below.
224 :
225 0 : if(s_script_pre)
226 0 : ret=run_server_script(as->asfd, "pre", action_from_client,
227 : s_script_pre,
228 : get_strlist(cconfs[OPT_S_SCRIPT_PRE_ARG]),
229 0 : get_int(cconfs[OPT_S_SCRIPT_PRE_NOTIFY]),
230 : cconfs, ret, timer_ret);
231 :
232 0 : if(!ret)
233 0 : ret=run_action_server(as, incexc, srestore, &timer_ret, cconfs);
234 :
235 0 : if(!s_script_post)
236 : goto end;
237 0 : if(ret && !get_int(cconfs[OPT_S_SCRIPT_POST_RUN_ON_FAIL]))
238 : goto end;
239 0 : ret=run_server_script(as->asfd, "post", action_from_client,
240 : s_script_post,
241 : get_strlist(cconfs[OPT_S_SCRIPT_POST_ARG]),
242 0 : get_int(cconfs[OPT_S_SCRIPT_POST_NOTIFY]),
243 : cconfs, ret, timer_ret);
244 :
245 : end:
246 0 : free_w(&action_from_client);
247 0 : return ret;
248 : }
|