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