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