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