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