Line data Source code
1 : #include "../../burp.h"
2 : #include "../../attribs.h"
3 : #include "../../base64.h"
4 : #include "../../conffile.h"
5 : #include "../../cstat.h"
6 : #include "../../fsops.h"
7 : #include "../../fzp.h"
8 : #include "../../handy.h"
9 : #include "../../hexmap.h"
10 : #include "../../iobuf.h"
11 : #include "../../lock.h"
12 : #include "../../log.h"
13 : #include "../../strlist.h"
14 : #include "../../protocol2/blk.h"
15 : #include "../bu_get.h"
16 : #include "../protocol2/backup_phase4.h"
17 : #include "../sdirs.h"
18 : #include "bsigs.h"
19 : #include "champ_chooser/champ_chooser.h"
20 :
21 : static struct cstat *clist=NULL;
22 : static struct lock *sparse_lock=NULL;
23 :
24 3 : static int usage(void)
25 : {
26 3 : logfmt("\nUsage: %s [options] <path to dedup_group>\n", prog);
27 3 : logfmt("\n");
28 3 : logfmt(" Options:\n");
29 3 : logfmt(" -c <path> Path to config file (default: %s).\n",
30 : config_default_path());
31 3 : logfmt("\n");
32 3 : return 1;
33 : }
34 :
35 1 : static void release_locks(void)
36 : {
37 : struct cstat *c;
38 : struct sdirs *s;
39 4 : for(c=clist; c; c=c->next)
40 : {
41 3 : s=(struct sdirs *)c->sdirs;
42 3 : if(!s) continue;
43 3 : lock_release(s->lock_storage_for_write);
44 3 : logp("released: %s\n", c->name);
45 : }
46 1 : lock_release(sparse_lock);
47 1 : lock_free(&sparse_lock);
48 1 : logp("released: sparse index\n");
49 1 : }
50 :
51 0 : static void sighandler(__attribute__ ((unused)) int signum)
52 : {
53 0 : release_locks();
54 0 : exit(1);
55 : }
56 :
57 1 : static struct sdirs *get_sdirs(struct conf **globalcs)
58 : {
59 1 : struct sdirs *sdirs=NULL;
60 1 : if(!(sdirs=sdirs_alloc())
61 1 : || sdirs_init_from_confs(sdirs, globalcs))
62 0 : sdirs_free(&sdirs);
63 1 : return sdirs;
64 : }
65 :
66 1 : static int parse_directory(const char *arg,
67 : char **directory, char **dedup_group)
68 : {
69 : char *cp;
70 1 : if(!(*directory=strdup_w(arg, __func__)))
71 : goto error;
72 1 : strip_trailing_slashes(directory);
73 1 : if(!(cp=strrchr(*directory, '/')))
74 : {
75 0 : logp("Could not parse directory '%s'\n", *directory);
76 0 : goto error;
77 : }
78 1 : *cp='\0';
79 1 : if(!(*dedup_group=strdup_w(cp+1, __func__)))
80 : goto error;
81 1 : if(!*directory || !*dedup_group)
82 : goto error;
83 : return 0;
84 : error:
85 0 : free_w(directory);
86 0 : free_w(dedup_group);
87 0 : return -1;
88 : }
89 :
90 1 : static struct conf **load_conf(const char *configfile,
91 : const char *directory, const char *dedup_group)
92 : {
93 1 : struct conf **globalcs=NULL;
94 1 : if(!(globalcs=confs_alloc())
95 1 : || confs_init(globalcs)
96 1 : || conf_load_global_only(configfile, globalcs)
97 1 : || set_string(globalcs[OPT_CNAME], "fake")
98 1 : || set_string(globalcs[OPT_DIRECTORY], directory)
99 1 : || set_string(globalcs[OPT_DEDUP_GROUP], dedup_group)
100 1 : || set_protocol(globalcs, PROTO_2))
101 0 : confs_free(&globalcs);
102 1 : return globalcs;
103 : }
104 :
105 1 : static void setup_sighandler(void)
106 : {
107 1 : signal(SIGABRT, &sighandler);
108 1 : signal(SIGTERM, &sighandler);
109 1 : signal(SIGINT, &sighandler);
110 1 : }
111 :
112 1 : static int get_sparse_lock(const char *sparse)
113 : {
114 1 : if(!(sparse_lock=try_to_get_sparse_lock(sparse)))
115 : {
116 0 : logp("Could not get sparse lock\n");
117 0 : return -1;
118 : }
119 : return 0;
120 : }
121 :
122 1 : static int get_client_locks(void)
123 : {
124 : struct cstat *c;
125 : struct sdirs *s;
126 8 : for(c=clist; c; c=c->next)
127 : {
128 3 : s=(struct sdirs *)c->sdirs;
129 3 : if(mkpath(&s->lock_storage_for_write->path, s->lockdir))
130 : {
131 0 : logp("problem with lock directory: %s\n", s->lockdir);
132 0 : return -1;
133 : }
134 :
135 3 : lock_get(s->lock_storage_for_write);
136 3 : switch(s->lock_storage_for_write->status)
137 : {
138 : case GET_LOCK_GOT:
139 3 : logp("locked: %s\n", c->name);
140 : break;
141 : case GET_LOCK_NOT_GOT:
142 0 : logp("Unable to get lock for client %s\n",
143 : c->name);
144 0 : return -1;
145 : case GET_LOCK_ERROR:
146 : default:
147 0 : logp("Problem with lock file: %s\n",
148 : s->lock_storage_for_write->path);
149 0 : return -1;
150 : }
151 : }
152 : return 0;
153 : }
154 :
155 1 : static struct cstat *get_client_list(const char *cdir, struct conf **globalcs)
156 : {
157 1 : int i=0;
158 1 : int count=0;
159 1 : char *fullpath=NULL;
160 1 : char **clients=NULL;
161 1 : struct cstat *cnew=NULL;
162 1 : const char *clientconfdir=get_string(globalcs[OPT_CLIENTCONFDIR]);
163 1 : if(entries_in_directory_alphasort(cdir, &clients, &count, 1/*atime*/, 1/*follow_symlinks*/))
164 : goto error;
165 4 : for(i=0; i<count; i++)
166 : {
167 4 : free_w(&fullpath);
168 4 : if(!(fullpath=prepend_s(cdir, clients[i])))
169 : goto end;
170 4 : switch(is_dir_lstat(fullpath))
171 : {
172 1 : case 0: continue;
173 : case 1: break;
174 0 : default: logp("is_dir(%s): %s\n",
175 0 : fullpath, strerror(errno));
176 0 : goto error;
177 : }
178 :
179 3 : if(set_string(globalcs[OPT_CNAME], clients[i]))
180 : goto error;
181 :
182 : // Have a good entry. Add it to the list.
183 3 : if(!(cnew=cstat_alloc())
184 3 : || !(cnew->sdirs=sdirs_alloc())
185 3 : || (sdirs_init_from_confs((struct sdirs *)cnew->sdirs,
186 : globalcs))
187 3 : || cstat_init(cnew, clients[i], clientconfdir))
188 : goto error;
189 3 : cstat_add_to_list(&clist, cnew);
190 3 : cnew=NULL;
191 : }
192 : goto end;
193 : error:
194 0 : cstat_list_free(&clist);
195 : end:
196 4 : for(i=0; i<count; i++)
197 4 : free_w(&(clients[i]));
198 1 : free_v((void **)&clients);
199 1 : free_w(&fullpath);
200 1 : if(cnew)
201 : {
202 0 : sdirs_free((struct sdirs **)&cnew->sdirs);
203 0 : cstat_free(&cnew);
204 : }
205 1 : return clist;
206 : }
207 :
208 1 : static void clist_free(void)
209 : {
210 : struct cstat *c;
211 1 : if(!clist)
212 : return;
213 3 : for(c=clist; c; c=c->next)
214 3 : sdirs_free((struct sdirs **)&c->sdirs);
215 1 : cstat_list_free(&clist);
216 : }
217 :
218 3 : static int merge_in_client_sparse_indexes(struct cstat *c,
219 : const char *global_sparse)
220 : {
221 3 : int ret=-1;
222 3 : char *sparse=NULL;
223 3 : struct bu *b=NULL;
224 3 : struct bu *bu_list=NULL;
225 3 : struct sdirs *s=(struct sdirs *)c->sdirs;
226 :
227 3 : if(bu_get_list(s, &bu_list))
228 : goto end;
229 12 : for(b=bu_list; b; b=b->next)
230 : {
231 9 : free_w(&sparse);
232 9 : if(!(sparse=prepend_s(b->path, "manifest/sparse")))
233 : goto end;
234 9 : logp("merge: %s\n", sparse);
235 9 : if(merge_into_global_sparse(sparse,
236 : global_sparse, sparse_lock))
237 : goto end;
238 : }
239 : ret=0;
240 : end:
241 3 : bu_list_free(&bu_list);
242 3 : free_w(&sparse);
243 3 : return ret;
244 : }
245 :
246 1 : static int merge_in_all_sparse_indexes(const char *global_sparse)
247 : {
248 : struct cstat *c;
249 :
250 1 : if(!is_reg_lstat(global_sparse)
251 0 : && unlink(global_sparse))
252 : {
253 0 : logp("Could not delete %s: %s\n",
254 0 : global_sparse, strerror(errno));
255 0 : return -1;
256 : }
257 :
258 4 : for(c=clist; c; c=c->next)
259 3 : if(merge_in_client_sparse_indexes(c, global_sparse))
260 : return -1;
261 : return 0;
262 : }
263 :
264 5 : int run_bsparse(int argc, char *argv[])
265 : {
266 5 : int ret=1;
267 : int option;
268 5 : char *directory=NULL;
269 5 : char *dedup_group=NULL;
270 5 : const char *configfile=NULL;
271 5 : struct sdirs *sdirs=NULL;
272 5 : struct conf **globalcs=NULL;
273 :
274 5 : base64_init();
275 5 : configfile=config_default_path();
276 :
277 11 : while((option=getopt(argc, argv, "c:Vh?"))!=-1)
278 : {
279 4 : switch(option)
280 : {
281 : case 'c':
282 1 : configfile=optarg;
283 1 : break;
284 : case 'V':
285 1 : logfmt("%s-%s\n", prog, PACKAGE_VERSION);
286 1 : return 0;
287 : case 'h':
288 : case '?':
289 2 : return usage();
290 : }
291 : }
292 :
293 2 : if(optind>=argc || optind<argc-1)
294 1 : return usage();
295 :
296 1 : if(parse_directory(argv[optind], &directory, &dedup_group))
297 : goto end;
298 :
299 1 : logp("config file: %s\n", configfile);
300 1 : logp("directory: %s\n", directory);
301 1 : logp("dedup_group: %s\n", dedup_group);
302 :
303 1 : if(!(globalcs=load_conf(configfile, directory, dedup_group))
304 1 : || !(sdirs=get_sdirs(globalcs)))
305 : goto end;
306 :
307 1 : logp("clients: %s\n", sdirs->clients);
308 1 : logp("sparse file: %s\n", sdirs->global_sparse);
309 :
310 1 : setup_sighandler();
311 :
312 1 : if(get_sparse_lock(sdirs->global_sparse))
313 : goto end;
314 :
315 1 : if(!get_client_list(sdirs->clients, globalcs))
316 : {
317 0 : logp("Did not find any client directories\n");
318 0 : goto end;
319 : }
320 :
321 1 : if(get_client_locks())
322 : goto end;
323 :
324 1 : if(merge_in_all_sparse_indexes(sdirs->global_sparse))
325 : goto end;
326 :
327 1 : ret=0;
328 : end:
329 1 : release_locks();
330 1 : sdirs_free(&sdirs);
331 1 : free_w(&directory);
332 1 : free_w(&dedup_group);
333 1 : confs_free(&globalcs);
334 1 : clist_free();
335 1 : return ret;
336 : }
|