Line data Source code
1 : #include "../burp.h"
2 : #include "../action.h"
3 : #include "../alloc.h"
4 : #include "../asfd.h"
5 : #include "../async.h"
6 : #include "../conf.h"
7 : #include "../cmd.h"
8 : #include "../cntr.h"
9 : #include "../fsops.h"
10 : #include "../handy.h"
11 : #include "../iobuf.h"
12 : #include "../log.h"
13 : #include "../run_script.h"
14 : #include "auth.h"
15 : #include "backup_phase1.h"
16 : #include "backup_phase3.h"
17 : #include "bu_get.h"
18 : #include "compress.h"
19 : #include "delete.h"
20 : #include "sdirs.h"
21 : #include "protocol1/backup_phase2.h"
22 : #include "protocol1/backup_phase4.h"
23 : #include "backup.h"
24 : #include "rubble.h"
25 : #include "timer.h"
26 :
27 1 : static void log_rshash(struct conf **confs)
28 : {
29 1 : logp("Using librsync hash %s\n",
30 : rshash_to_str(get_e_rshash(confs[OPT_RSHASH])));
31 1 : }
32 :
33 1 : static int open_log(struct asfd *asfd,
34 : struct sdirs *sdirs, struct conf **cconfs, int resume)
35 : {
36 1 : int ret=-1;
37 1 : char *logpath=NULL;
38 1 : const char *peer_version=get_string(cconfs[OPT_PEER_VERSION]);
39 :
40 1 : logp("Backup %s: %s\n", resume?"resumed":"started", sdirs->rworking);
41 :
42 1 : if(!(logpath=prepend_s(sdirs->rworking, "log"))) goto end;
43 1 : if(log_fzp_set(logpath, cconfs))
44 : {
45 0 : logp("could not open log file: %s\n", logpath);
46 : goto end;
47 : }
48 :
49 1 : logp("Backup %s\n", resume?"resumed":"started");
50 1 : logp("Client version: %s\n", peer_version?:"");
51 1 : log_rshash(cconfs);
52 1 : if(get_int(cconfs[OPT_CLIENT_IS_WINDOWS]))
53 0 : logp("Client is Windows\n");
54 :
55 : // Make sure a warning appears in the backup log.
56 : // The client will already have been sent a message with logw.
57 : // This time, prevent it sending a logw to the client by specifying
58 : // NULL for asfd and cntr.
59 1 : if(get_int(cconfs[OPT_VERSION_WARN]))
60 1 : version_warn(NULL, NULL, cconfs);
61 :
62 : ret=0;
63 : end:
64 1 : free_w(&logpath);
65 1 : return ret;
66 : }
67 :
68 1 : static int write_incexc(const char *realworking, const char *incexc)
69 : {
70 1 : int ret=-1;
71 1 : char *tmp=NULL;
72 1 : char *path=NULL;
73 1 : struct fzp *fzp=NULL;
74 :
75 1 : if(!incexc || !*incexc) return 0;
76 :
77 0 : if(!(path=prepend_s(realworking, "incexc"))
78 0 : || !(tmp=prepend(path, ".tmp"))
79 0 : || !(fzp=fzp_open(tmp, "wb")))
80 : goto end;
81 :
82 0 : fzp_printf(fzp, "%s", incexc);
83 0 : if(fzp_close(&fzp))
84 : {
85 0 : logp("error writing to %s in %s\n", tmp, __func__);
86 0 : goto end;
87 : }
88 0 : if(do_rename(tmp, path))
89 : goto end;
90 0 : ret=0;
91 : end:
92 0 : free_w(&path);
93 0 : free_w(&tmp);
94 0 : return ret;
95 : }
96 :
97 1 : static int backup_phase1_server(struct async *as,
98 : struct sdirs *sdirs, struct conf **cconfs)
99 : {
100 1 : int breaking=get_int(cconfs[OPT_BREAKPOINT]);
101 1 : if(breaking==1)
102 0 : return breakpoint(breaking, __func__);
103 1 : return backup_phase1_server_all(as, sdirs, cconfs);
104 : }
105 :
106 0 : static int backup_phase2_server(struct async *as, struct sdirs *sdirs,
107 : const char *incexc, int resume, struct conf **cconfs)
108 : {
109 0 : int breaking=get_int(cconfs[OPT_BREAKPOINT]);
110 0 : if(breaking==2)
111 0 : return breakpoint(breaking, __func__);
112 :
113 0 : return backup_phase2_server_protocol1(as, sdirs,
114 : incexc, resume, cconfs);
115 : }
116 :
117 0 : static int backup_phase3_server(struct sdirs *sdirs, struct conf **cconfs)
118 : {
119 0 : int breaking=get_int(cconfs[OPT_BREAKPOINT]);
120 0 : if(breaking==3)
121 0 : return breakpoint(breaking, __func__);
122 :
123 0 : return backup_phase3_server_all(sdirs, cconfs);
124 : }
125 :
126 0 : static int backup_phase4_server(struct sdirs *sdirs, struct conf **cconfs)
127 : {
128 0 : int breaking=get_int(cconfs[OPT_BREAKPOINT]);
129 0 : if(breaking==4)
130 0 : return breakpoint(breaking, __func__);
131 :
132 0 : log_fzp_set(NULL, cconfs);
133 : // Phase4 will open logfp again (in case it is resuming).
134 0 : return backup_phase4_server_protocol1(sdirs, cconfs);
135 : }
136 :
137 0 : static int get_bno_from_sdirs(struct sdirs *sdirs)
138 : {
139 0 : char *cp=NULL;
140 : // Should be easier than this.
141 0 : if(!(cp=strrchr(sdirs->rworking, '/')))
142 : return 0;
143 0 : return atoi(cp+1);
144 : }
145 :
146 1 : static uint64_t get_new_bno(struct sdirs *sdirs)
147 : {
148 1 : uint64_t index=0;
149 1 : struct bu *bu=NULL;
150 1 : struct bu *bu_list=NULL;
151 :
152 : // Want to prefix the timestamp with an index that increases by
153 : // one each time. This makes it far more obvious which backup depends
154 : // on which - even if the system clock moved around.
155 :
156 : // This function orders the array with the highest index number last.
157 1 : if(bu_get_list(sdirs, &bu_list))
158 : return -1;
159 2 : for(bu=bu_list; bu; bu=bu->next)
160 0 : if(!bu->next)
161 0 : index=bu->bno;
162 1 : bu_list_free(&bu_list);
163 :
164 1 : return index+1;
165 : }
166 :
167 1 : static int do_backup_server(struct async *as, struct sdirs *sdirs,
168 : struct conf **cconfs, const char *incexc, int resume,
169 : uint64_t bno_new)
170 : {
171 1 : int ret=0;
172 1 : int do_phase2=1;
173 1 : struct asfd *asfd=as->asfd;
174 1 : struct cntr *cntr=get_cntr(cconfs);
175 :
176 1 : if(resume)
177 : {
178 0 : if(sdirs_get_real_working_from_symlink(sdirs)
179 0 : || sdirs_get_real_manifest(sdirs))
180 : goto error;
181 :
182 0 : if(open_log(asfd, sdirs, cconfs, resume))
183 : goto error;
184 :
185 0 : if(!(cntr->bno=get_bno_from_sdirs(sdirs)))
186 : {
187 0 : logp("Could not get old backup number when resuming.");
188 0 : goto error;
189 : }
190 : }
191 : else
192 : {
193 : // Not resuming - need to set everything up fresh.
194 1 : cntr->bno=bno_new;
195 1 : if(sdirs_create_real_working(sdirs, bno_new,
196 1 : get_string(cconfs[OPT_TIMESTAMP_FORMAT]))
197 1 : || sdirs_get_real_manifest(sdirs))
198 : goto error;
199 :
200 1 : if(open_log(asfd, sdirs, cconfs, resume))
201 : goto error;
202 :
203 1 : if(write_incexc(sdirs->rworking, incexc))
204 : {
205 0 : logp("unable to write incexc\n");
206 0 : goto error;
207 : }
208 :
209 1 : if(backup_phase1_server(as, sdirs, cconfs))
210 : {
211 1 : logp("error in phase 1\n");
212 1 : goto error;
213 : }
214 : }
215 :
216 0 : if(resume)
217 : {
218 : struct stat statp;
219 0 : if(lstat(sdirs->phase1data, &statp)
220 0 : && !lstat(sdirs->changed, &statp)
221 0 : && !lstat(sdirs->unchanged, &statp))
222 : {
223 : // In this condition, it looks like there was an
224 : // interruption during phase3. Skip phase2.
225 0 : do_phase2=0;
226 : }
227 : }
228 :
229 0 : if(do_phase2)
230 : {
231 0 : if(backup_phase2_server(as, sdirs, incexc, resume, cconfs))
232 : {
233 0 : logp("error in backup phase 2\n");
234 0 : goto error;
235 : }
236 :
237 0 : asfd->write_str(asfd, CMD_GEN, "okbackupend");
238 : }
239 :
240 : // Close the connection with the client, the rest of the job we can do
241 : // by ourselves.
242 0 : logp("Backup ending - disconnect from client.\n");
243 0 : if(asfd_flush_asio(asfd))
244 : goto error;
245 0 : as->asfd_remove(as, asfd);
246 0 : asfd_close(asfd);
247 :
248 0 : if(backup_phase3_server(sdirs, cconfs))
249 : {
250 0 : logp("error in backup phase 3\n");
251 0 : goto error;
252 : }
253 :
254 : // Write backup_stats before flipping the symlink, so that is there
255 : // even if phase4 is interrupted.
256 0 : cntr_set_bytes(cntr, asfd);
257 0 : if(cntr_stats_to_file(cntr, sdirs->working, ACTION_BACKUP))
258 : goto error;
259 0 : unlink(sdirs->counters_d);
260 0 : unlink(sdirs->counters_n);
261 :
262 0 : if(do_rename(sdirs->working, sdirs->finishing))
263 : goto error;
264 :
265 0 : if(backup_phase4_server(sdirs, cconfs))
266 : {
267 0 : logp("error in backup phase 4\n");
268 0 : goto error;
269 : }
270 :
271 0 : cntr_print(cntr, ACTION_BACKUP);
272 :
273 : // Move the symlink to indicate that we are now in the end phase. The
274 : // rename() race condition is automatically recoverable here.
275 0 : if(do_rename(sdirs->finishing, sdirs->current))
276 : goto error;
277 :
278 0 : logp("Backup completed.\n");
279 0 : log_fzp_set(NULL, cconfs);
280 0 : logp("Backup completed: %s\n", sdirs->rworking);
281 0 : compress_filename(sdirs->rworking,
282 : "log", "log.gz", get_int(cconfs[OPT_COMPRESSION]));
283 :
284 0 : goto end;
285 : error:
286 : ret=-1;
287 : end:
288 :
289 1 : if(ret)
290 1 : logp("Backup failed\n");
291 1 : log_fzp_set(NULL, cconfs);
292 1 : if(ret)
293 : {
294 : // Make an entry in the main output, for failed backups.
295 1 : logp("Backup failed: %s\n", sdirs->rworking);
296 : }
297 1 : return ret;
298 : }
299 :
300 1 : int run_backup(struct async *as, struct sdirs *sdirs, struct conf **cconfs,
301 : const char *incexc, int *timer_ret, int resume)
302 : {
303 : int ret;
304 : uint64_t bno_new;
305 1 : char okstr[32]="";
306 1 : struct asfd *asfd=as->asfd;
307 1 : struct iobuf *rbuf=asfd->rbuf;
308 1 : const char *cname=get_string(cconfs[OPT_CNAME]);
309 :
310 1 : if(get_string(cconfs[OPT_SUPER_CLIENT]))
311 : {
312 : // This client is not the original client, so a backup might
313 : // cause all sorts of trouble.
314 0 : logp("Not allowing backup of %s\n", cname);
315 0 : return asfd->write_str(asfd, CMD_GEN, "Backup is not allowed");
316 : }
317 :
318 : // Set quality of service bits on backups.
319 1 : asfd->set_bulk_packets(asfd);
320 :
321 1 : if(!strncmp_w(rbuf->buf, "backupphase1timed"))
322 : {
323 0 : int checkonly=!strncmp_w(rbuf->buf, "backupphase1timedcheck");
324 0 : if(checkonly) logp("Client asked for a timer check only.\n");
325 :
326 0 : if((*timer_ret=run_timer(asfd, sdirs, cconfs))<0)
327 : {
328 0 : logp("Error running timer for %s\n", cname);
329 0 : return -1;
330 : }
331 0 : else if(*timer_ret)
332 : {
333 0 : if(!checkonly)
334 0 : logp("Not running backup of %s\n", cname);
335 0 : return asfd->write_str(asfd,
336 : CMD_GEN, "timer conditions not met");
337 : }
338 0 : if(checkonly)
339 : {
340 0 : logp("Client asked for a timer check only,\n");
341 0 : logp("so a backup is not happening right now.\n");
342 0 : return asfd->write_str(asfd,
343 : CMD_GEN, "timer conditions met");
344 : }
345 0 : logp("Running backup of %s\n", cname);
346 : }
347 1 : else if(!get_int(cconfs[OPT_CLIENT_CAN_FORCE_BACKUP]))
348 : {
349 0 : logp("Not allowing forced backup of %s\n", cname);
350 0 : return asfd->write_str(asfd,
351 : CMD_GEN, "Forced backup is not allowed");
352 : }
353 :
354 1 : if((bno_new=get_new_bno(sdirs))<0)
355 : return -1;
356 1 : if(get_string(cconfs[OPT_SEED_SRC])
357 0 : && get_string(cconfs[OPT_SEED_DST])
358 0 : && bno_new!=1)
359 : {
360 0 : log_and_send(asfd, "When seeding, there must be no previous backups for this client\n");
361 0 : return -1;
362 : }
363 :
364 1 : snprintf(okstr, sizeof(okstr), "%s:%d",
365 : resume?"resume":"ok", get_int(cconfs[OPT_COMPRESSION]));
366 1 : if(asfd->write_str(asfd, CMD_GEN, okstr)) return -1;
367 :
368 1 : if((ret=do_backup_server(as, sdirs, cconfs, incexc, resume, bno_new)))
369 : goto end;
370 :
371 0 : if((ret=delete_backups(sdirs, cname,
372 : get_strlist(cconfs[OPT_KEEP]),
373 0 : get_string(cconfs[OPT_MANUAL_DELETE]))))
374 : goto end;
375 : end:
376 : return ret;
377 : }
|