Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../bu.h"
4 : #include "../../cstat.h"
5 : #include "../../conffile.h"
6 : #include "../../fsops.h"
7 : #include "../../lock.h"
8 : #include "../../log.h"
9 : #include "../../strlist.h"
10 : #include "../bu_get.h"
11 : #include "../sdirs.h"
12 : #include "cstat.h"
13 :
14 : #ifndef UTEST
15 : static
16 : #endif
17 19 : int cstat_permitted(struct cstat *cstat,
18 : struct conf **monitor_cconfs, struct conf **cconfs)
19 : {
20 : struct strlist *rclient;
21 : const char *monitorconf_cname;
22 :
23 19 : monitorconf_cname=get_string(monitor_cconfs[OPT_CNAME]);
24 19 : if(!monitorconf_cname)
25 : return 0;
26 :
27 : // Allow clients to look at themselves.
28 4 : if(!strcmp(cstat->name, monitorconf_cname))
29 : return 1;
30 :
31 : // Do not allow clients using the super_client option to see more
32 : // than the client that it is pretending to be.
33 3 : if(get_string(monitor_cconfs[OPT_SUPER_CLIENT]))
34 : return 0;
35 :
36 : // If we are listed in this restore_client list, or super_client list.
37 6 : for(rclient=get_strlist(cconfs[OPT_RESTORE_CLIENTS]);
38 2 : rclient; rclient=rclient->next)
39 3 : if(!strcmp(get_string(monitor_cconfs[OPT_CNAME]), rclient->path))
40 : return 1;
41 2 : for(rclient=get_strlist(cconfs[OPT_SUPER_CLIENTS]);
42 0 : rclient; rclient=rclient->next)
43 0 : if(!strcmp(get_string(monitor_cconfs[OPT_CNAME]), rclient->path))
44 : return 1;
45 : return 0;
46 : }
47 :
48 15 : static int cstat_set_sdirs_protocol_unknown(struct cstat *cstat,
49 : struct conf **cconfs)
50 : {
51 : struct stat buf1;
52 : struct stat buf2;
53 15 : struct sdirs *sdirs1=NULL;
54 15 : struct sdirs *sdirs2=NULL;
55 :
56 15 : if(!(sdirs1=sdirs_alloc())
57 15 : || !(sdirs2=sdirs_alloc()))
58 : goto error;
59 :
60 15 : set_protocol(cconfs, PROTO_1);
61 15 : if(sdirs_init_from_confs(sdirs1, cconfs))
62 : goto error;
63 15 : set_protocol(cconfs, PROTO_2);
64 15 : if(sdirs_init_from_confs(sdirs2, cconfs))
65 : goto error;
66 :
67 30 : if(lstat(sdirs2->client, &buf2))
68 : goto protocol1; // No protocol2 client directory.
69 :
70 0 : if(lstat(sdirs1->client, &buf1))
71 : goto protocol2; // No protocol1 client directory.
72 :
73 : // Both directories exist.
74 :
75 0 : if(buf2.st_mtime>buf1.st_mtime)
76 : goto protocol2; // 2 was modified most recently.
77 :
78 : // Fall through to protocol1.
79 :
80 : protocol1:
81 15 : cstat->sdirs=sdirs1;
82 15 : cstat->protocol=PROTO_1;
83 15 : sdirs_free(&sdirs2);
84 15 : set_protocol(cconfs, PROTO_AUTO);
85 : return 0;
86 : protocol2:
87 0 : cstat->sdirs=sdirs2;
88 0 : cstat->protocol=PROTO_2;
89 0 : sdirs_free(&sdirs1);
90 0 : set_protocol(cconfs, PROTO_AUTO);
91 : return 0;
92 : error:
93 0 : sdirs_free(&sdirs1);
94 0 : sdirs_free(&sdirs2);
95 0 : set_protocol(cconfs, PROTO_AUTO);
96 : return -1;
97 : }
98 :
99 0 : static int cstat_set_sdirs_protocol_known(struct cstat *cstat,
100 : struct conf **cconfs)
101 : {
102 0 : struct sdirs *sdirs=NULL;
103 :
104 0 : if(!(sdirs=sdirs_alloc()))
105 : return -1;
106 0 : if(sdirs_init_from_confs(sdirs, cconfs))
107 : {
108 0 : sdirs_free(&sdirs);
109 : return -1;
110 : }
111 0 : cstat->sdirs=sdirs;
112 : return 0;
113 : }
114 :
115 15 : static int cstat_set_sdirs(struct cstat *cstat, struct conf **cconfs)
116 : {
117 15 : enum protocol protocol=get_protocol(cconfs);
118 15 : sdirs_free((struct sdirs **)&cstat->sdirs);
119 :
120 15 : if(protocol==PROTO_AUTO)
121 15 : return cstat_set_sdirs_protocol_unknown(cstat, cconfs);
122 :
123 0 : cstat->protocol=protocol;
124 0 : return cstat_set_sdirs_protocol_known(cstat, cconfs);
125 : }
126 :
127 15 : static int set_cstat_from_conf(struct cstat *cstat,
128 : struct conf **monitor_cconfs, struct conf **cconfs)
129 : {
130 15 : struct strlist *s=NULL;
131 : // Make sure the permitted flag is set appropriately.
132 15 : cstat->permitted=cstat_permitted(cstat, monitor_cconfs, cconfs);
133 :
134 15 : if(cstat_set_sdirs(cstat, cconfs))
135 : return -1;
136 15 : strlists_free(&cstat->labels);
137 21 : for(s=get_strlist(cconfs[OPT_LABEL]); s; s=s->next)
138 6 : if(strlist_add_sorted(&cstat->labels, s->path, s->flag))
139 : return -1;
140 : return 0;
141 : }
142 :
143 : #ifndef UTEST
144 : static
145 : #endif
146 24 : int cstat_get_client_names(struct cstat **clist, const char *clientconfdir)
147 : {
148 24 : int i=0;
149 24 : int n=0;
150 24 : int ret=-1;
151 : struct cstat *c;
152 : struct cstat *cnew;
153 24 : struct dirent **dir=NULL;
154 :
155 24 : if((n=scandir(clientconfdir, &dir, filter_dot, NULL))<0)
156 : {
157 1 : logp("scandir failed for %s in %s: %s\n",
158 1 : clientconfdir, __func__, strerror(errno));
159 1 : goto end;
160 : }
161 75 : for(i=0; i<n; i++)
162 : {
163 75 : if(!cname_valid(dir[i]->d_name))
164 2 : continue;
165 175 : for(c=*clist; c; c=c->next)
166 : {
167 119 : if(!c->name) continue;
168 119 : if(!strcmp(dir[i]->d_name, c->name))
169 : break;
170 : }
171 73 : if(c) continue;
172 :
173 : // We do not have this client yet. Add it.
174 56 : if(!(cnew=cstat_alloc())
175 56 : || cstat_init(cnew, dir[i]->d_name, clientconfdir))
176 : goto end;
177 56 : cstat_add_to_list(clist, cnew);
178 : }
179 :
180 : ret=0;
181 : end:
182 24 : if(dir)
183 : {
184 75 : for(i=0; i<n; i++)
185 75 : free(dir[i]);
186 23 : free(dir);
187 : }
188 24 : return ret;
189 : }
190 :
191 : static void cstat_free_w(struct cstat **cstat)
192 : {
193 8 : sdirs_free((struct sdirs **)&(*cstat)->sdirs);
194 8 : cstat_free(cstat);
195 : }
196 :
197 : #ifndef UTEST
198 : static
199 : #endif
200 8 : void cstat_remove(struct cstat **clist, struct cstat **cstat)
201 : {
202 : struct cstat *c;
203 8 : if(!cstat || !*cstat) return;
204 8 : if(*clist==*cstat)
205 : {
206 4 : *clist=(*clist)->next;
207 4 : if(*clist) (*clist)->prev=NULL;
208 4 : cstat_free_w(cstat);
209 4 : *cstat=*clist;
210 4 : return;
211 : }
212 10 : for(c=*clist; c; c=c->next)
213 : {
214 7 : if(c->next!=*cstat)
215 3 : continue;
216 4 : c->next=(*cstat)->next;
217 4 : if(c->next)
218 3 : c->next->prev=(*cstat)->prev;
219 4 : cstat_free_w(cstat);
220 4 : *cstat=*clist;
221 4 : return;
222 : }
223 : }
224 :
225 : // Returns -1 on error, otherwise the number of clients that were reloaded.
226 : #ifndef UTEST
227 : static
228 : #endif
229 12 : int cstat_reload_from_client_confs(struct cstat **clist,
230 : struct conf **monitor_cconfs,
231 : struct conf **globalcs, struct conf **cconfs)
232 : {
233 : struct cstat *c;
234 : struct stat statp;
235 : static time_t global_mtime=0;
236 12 : time_t global_mtime_new=0;
237 : const char *globalconffile;
238 12 : int reloaded=0;
239 :
240 12 : globalconffile=get_string(globalcs[OPT_CONFFILE]);
241 :
242 12 : if(stat(globalconffile, &statp)
243 11 : || !S_ISREG(statp.st_mode))
244 : {
245 1 : logp("Could not stat main conf file %s: %s\n",
246 1 : globalconffile, strerror(errno));
247 1 : return -1;
248 : }
249 11 : global_mtime_new=statp.st_mtime;
250 :
251 : // FIX THIS: If '. included' conf files have changed, this code will
252 : // not detect them. I guess that conf.c should make a list of them.
253 : while(1)
254 : {
255 41 : for(c=*clist; c; c=c->next)
256 : {
257 : // Look at the client conf files to see if they have
258 : // changed, and reload bits and pieces if they have.
259 :
260 31 : if(!c->conffile) continue;
261 62 : if(stat(c->conffile, &statp)
262 28 : || !S_ISREG(statp.st_mode))
263 : {
264 3 : cstat_remove(clist, &c);
265 3 : break; // Go to the beginning of the list.
266 : }
267 28 : if(statp.st_mtime==c->conf_mtime
268 12 : && global_mtime_new==global_mtime)
269 : {
270 : // The conf files have not changed - no need to
271 : // do anything.
272 12 : continue;
273 : }
274 16 : c->conf_mtime=statp.st_mtime;
275 :
276 16 : confs_free_content(cconfs);
277 16 : if(set_string(cconfs[OPT_CNAME], c->name))
278 : return -1;
279 16 : if(conf_load_clientconfdir(globalcs, cconfs))
280 : {
281 : // If the file has junk in it, we will keep
282 : // trying to reload it after removal.
283 : // So, just deny permission to view it.
284 1 : c->permitted=0;
285 1 : continue;
286 : }
287 :
288 15 : if(set_cstat_from_conf(c, monitor_cconfs, cconfs))
289 : return -1;
290 15 : reloaded++;
291 : }
292 : // Only stop if the end of the list was not reached.
293 13 : if(!c) break;
294 : }
295 11 : if(global_mtime!=global_mtime_new)
296 3 : global_mtime=global_mtime_new;
297 : return reloaded;
298 : }
299 :
300 22 : void cstat_set_run_status(struct cstat *cstat, enum run_status run_status)
301 : {
302 22 : if(!cstat->permitted)
303 : return;
304 20 : cstat->run_status=run_status;
305 : }
306 :
307 : // Return -1 on error, or the number of reloaded clients.
308 : #ifndef UTEST
309 : static
310 : #endif
311 8 : int reload_from_clientdir(struct cstat **clist)
312 : {
313 8 : int reloaded=0;
314 : struct cstat *c;
315 27 : for(c=*clist; c; c=c->next)
316 : {
317 : struct stat statp;
318 : struct sdirs *sdirs;
319 :
320 36 : if(!c->permitted) continue;
321 :
322 6 : sdirs=(struct sdirs *)c->sdirs;
323 6 : if(!sdirs || !sdirs->client) continue;
324 12 : if(stat(sdirs->client, &statp))
325 2 : continue;
326 :
327 4 : if(statp.st_mtime==c->clientdir_mtime)
328 : {
329 : // clientdir has not changed - no need to do anything.
330 2 : continue;
331 : }
332 2 : c->clientdir_mtime=statp.st_mtime;
333 :
334 2 : bu_list_free(&c->bu);
335 : // FIX THIS: should probably not load everything each time.
336 : // if(bu_get_current(sdirs, &c->bu))
337 : // goto error;
338 2 : if(bu_get_list_with_working(sdirs, &c->bu))
339 : goto error;
340 2 : reloaded++;
341 : }
342 : return reloaded;
343 : error:
344 0 : return -1;
345 : }
346 :
347 2 : int cstat_load_data_from_disk(struct cstat **clist,
348 : struct conf **monitor_cconfs,
349 : struct conf **globalcs, struct conf **cconfs)
350 : {
351 2 : if(!globalcs) return -1;
352 2 : return cstat_get_client_names(clist,
353 2 : get_string(globalcs[OPT_CLIENTCONFDIR]))
354 2 : || cstat_reload_from_client_confs(clist,
355 : monitor_cconfs, globalcs, cconfs)<0
356 4 : || reload_from_clientdir(clist)<0;
357 : }
358 :
359 26 : int cstat_set_backup_list(struct cstat *cstat)
360 : {
361 26 : struct bu *bu=NULL;
362 :
363 : // Free any previous list.
364 26 : bu_list_free(&cstat->bu);
365 :
366 26 : if(!cstat->permitted) return 0;
367 :
368 24 : if(bu_get_list_with_working((struct sdirs *)cstat->sdirs, &bu))
369 : {
370 : //logp("error when looking up current backups\n");
371 : return 0;
372 : }
373 :
374 : // Find the end of the list just loaded, so we can traverse
375 : // it backwards later.
376 50 : while(bu && bu->next) bu=bu->next;
377 :
378 23 : cstat->bu=bu;
379 23 : return 0;
380 : }
|