Line data Source code
1 : #include "../burp.h"
2 : #include "../action.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cmd.h"
6 : #include "../cntr.h"
7 : #include "../handy.h"
8 : #include "../fsops.h"
9 : #include "../iobuf.h"
10 : #include "../lock.h"
11 : #include "../log.h"
12 : #include "../regexp.h"
13 : #include "../run_script.h"
14 : #include "main.h"
15 : #include "backup.h"
16 : #include "delete.h"
17 : #include "diff.h"
18 : #include "list.h"
19 : #include "protocol2/restore.h"
20 : #include "restore.h"
21 : #include "rubble.h"
22 : #include "sdirs.h"
23 : #include "run_action.h"
24 : #include "timestamp.h"
25 :
26 : // FIX THIS: Somewhat haphazard.
27 : /* Return 0 for everything OK. -1 for error, or 1 to mean that there was
28 : another process that has the lock. */
29 2 : static int get_lock_sdirs_for_write(struct asfd *asfd, struct sdirs *sdirs)
30 : {
31 : struct stat statp;
32 :
33 : // Make sure the lock directory exists.
34 2 : if(mkpath(&sdirs->lock_storage_for_write->path, sdirs->lockdir))
35 : {
36 0 : asfd->write_str(asfd, CMD_ERROR, "problem with lock directory");
37 0 : goto error;
38 : }
39 :
40 2 : lock_get(sdirs->lock_storage_for_write);
41 2 : switch(sdirs->lock_storage_for_write->status)
42 : {
43 : case GET_LOCK_GOT: break;
44 : case GET_LOCK_NOT_GOT:
45 0 : if(!lstat(sdirs->finishing, &statp))
46 : {
47 0 : char msg[256]="";
48 0 : logp("finalising previous backup\n");
49 0 : snprintf(msg, sizeof(msg),
50 : "Finalising previous backup of client. "
51 : "Please try again later.");
52 0 : asfd->write_str(asfd, CMD_ERROR, msg);
53 : }
54 : else
55 : {
56 0 : logp("Another instance of client is already running.\n");
57 0 : asfd->write_str(asfd, CMD_ERROR,
58 : "another instance is already running");
59 : }
60 : goto lockedout;
61 : case GET_LOCK_ERROR:
62 : default:
63 0 : logp("Problem with lock file on server: %s\n",
64 : sdirs->lock_storage_for_write->path);
65 0 : asfd->write_str(asfd, CMD_ERROR,
66 : "problem with lock file on server");
67 0 : goto error;
68 : }
69 :
70 : return 0;
71 : lockedout:
72 : return 1;
73 : error:
74 : return -1;
75 : }
76 :
77 : static int client_can_generic(struct conf **cconfs, enum conf_opt o)
78 : {
79 5 : return get_int(cconfs[o]);
80 : }
81 :
82 0 : int client_can_monitor(struct conf **cconfs)
83 : {
84 0 : return client_can_generic(cconfs, OPT_CLIENT_CAN_MONITOR);
85 : }
86 :
87 1 : static int client_can_restore(struct conf **cconfs)
88 : {
89 1 : const char *restore_path=get_string(cconfs[OPT_RESTORE_PATH]);
90 :
91 : // If there is a restore file on the server, it is always OK.
92 1 : if(restore_path && is_reg_lstat(restore_path)==1)
93 : {
94 : // Remove the file.
95 0 : unlink(restore_path);
96 0 : return 1;
97 : }
98 :
99 1 : return client_can_generic(cconfs, OPT_CLIENT_CAN_RESTORE);
100 : }
101 :
102 1 : void maybe_do_notification(struct asfd *asfd,
103 : int status, const char *clientdir,
104 : const char *storagedir, const char *filename,
105 : const char *brv, struct conf **cconfs)
106 : {
107 1 : int a=0;
108 : const char *args[12];
109 1 : struct cntr *cntr=get_cntr(cconfs);
110 1 : args[a++]=NULL; // Fill in the script name later.
111 1 : args[a++]=get_string(cconfs[OPT_CNAME]);
112 1 : args[a++]=clientdir;
113 1 : args[a++]=storagedir;
114 1 : args[a++]=filename;
115 1 : args[a++]=brv;
116 1 : if(status)
117 : {
118 1 : args[0]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
119 1 : args[a++]="0";
120 1 : args[a++]=NULL;
121 1 : run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
122 : cconfs, 1, 1, 1);
123 : }
124 0 : else if((get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
125 0 : && cntr->ent[CMD_WARNING]->count > 0)
126 0 : || (get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])
127 0 : && cntr->ent[CMD_TOTAL]->changed > 0)
128 0 : || (!get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
129 0 : && !get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])))
130 : {
131 0 : char warnings[32]="";
132 0 : snprintf(warnings, sizeof(warnings), "%" PRIu64,
133 0 : cntr->ent[CMD_WARNING]->count);
134 0 : args[0]=get_string(cconfs[OPT_N_SUCCESS_SCRIPT]);
135 0 : args[a++]=warnings;
136 0 : args[a++]=NULL;
137 0 : run_script(asfd, args, get_strlist(cconfs[OPT_N_SUCCESS_ARG]),
138 : cconfs, 1, 1, 1);
139 : }
140 1 : }
141 :
142 18 : static int parse_restore_str(
143 : const char *str,
144 : enum action *act,
145 : int *input,
146 : char **backupnostr,
147 : char **restoreregex
148 : ) {
149 18 : int ret=-1;
150 18 : char *cp=NULL;
151 18 : char *copy=NULL;
152 :
153 18 : if(!str)
154 : {
155 1 : logp("NULL passed to %s\n", __func__);
156 1 : goto end;
157 : }
158 :
159 17 : if(!(copy=strdup_w(str, __func__)))
160 : goto end;
161 :
162 17 : if(!strncmp_w(copy, "restore "))
163 7 : *act=ACTION_RESTORE;
164 10 : else if(!strncmp_w(copy, "verify "))
165 7 : *act=ACTION_VERIFY;
166 : else
167 : {
168 3 : logp("Could not parse %s in %s\n", copy, __func__);
169 3 : goto end;
170 : }
171 :
172 14 : if(!(cp=strchr(copy, ' ')))
173 : {
174 0 : logp("Could not parse %s in %s\n", copy, __func__);
175 0 : goto end;
176 : }
177 14 : cp++;
178 14 : *input=0;
179 14 : if(!strncmp_w(cp, "restore_list "))
180 : {
181 6 : cp+=strlen("restore_list ");
182 6 : *input=1;
183 : }
184 14 : if(!(*backupnostr=strdup_w(cp, __func__)))
185 : goto end;
186 14 : if((cp=strchr(*backupnostr, ':')))
187 : {
188 8 : *cp='\0';
189 8 : cp++;
190 8 : if(!(*restoreregex=strdup_w(cp, __func__)))
191 : goto end;
192 : }
193 :
194 : ret=0;
195 : end:
196 18 : free_w(©);
197 18 : return ret;
198 : }
199 :
200 : #ifndef UTEST
201 : static
202 : #endif
203 18 : int parse_restore_str_and_set_confs(const char *str, enum action *act,
204 : struct conf **cconfs)
205 : {
206 18 : int ret=-1;
207 18 : int input=0;
208 18 : char *backupnostr=NULL;
209 18 : char *restoreregex=NULL;
210 :
211 18 : if(parse_restore_str(str, act, &input, &backupnostr, &restoreregex))
212 : goto end;
213 :
214 14 : if(set_string(cconfs[OPT_RESTORE_LIST], input?"":NULL))
215 : goto end;
216 14 : if(set_string(cconfs[OPT_BACKUP], backupnostr))
217 : goto end;
218 14 : if(restoreregex && *restoreregex
219 4 : && set_string(cconfs[OPT_REGEX], restoreregex))
220 : goto end;
221 : ret=0;
222 : end:
223 18 : free_w(&backupnostr);
224 18 : free_w(&restoreregex);
225 18 : return ret;
226 : }
227 :
228 2 : static int run_restore(struct asfd *asfd,
229 : struct sdirs *sdirs, struct conf **cconfs, int srestore)
230 : {
231 2 : int ret=-1;
232 2 : char *dir_for_notify=NULL;
233 2 : enum action act=ACTION_RESTORE;
234 2 : struct iobuf *rbuf=asfd->rbuf;
235 2 : const char *cname=get_string(cconfs[OPT_CNAME]);
236 :
237 2 : if(parse_restore_str_and_set_confs(rbuf->buf, &act, cconfs))
238 : goto end;
239 :
240 2 : iobuf_free_content(rbuf);
241 :
242 2 : if(act==ACTION_RESTORE)
243 : {
244 : int r;
245 1 : if((r=client_can_restore(cconfs))<0)
246 : goto end;
247 1 : else if(!r)
248 : {
249 0 : logp("Not allowing restore of %s\n", cname);
250 0 : if(!asfd->write_str(asfd, CMD_GEN,
251 0 : "Client restore is not allowed")) ret=0;
252 : goto end;
253 : }
254 : }
255 2 : if(act==ACTION_VERIFY
256 1 : && !(client_can_generic(cconfs, OPT_CLIENT_CAN_VERIFY)))
257 : {
258 0 : logp("Not allowing verify of %s\n", cname);
259 0 : if(!asfd->write_str(asfd, CMD_GEN,
260 0 : "Client verify is not allowed")) ret=0;
261 : goto end;
262 : }
263 :
264 2 : if(get_string(cconfs[OPT_RESTORE_LIST]))
265 : {
266 : // Should start receiving the input file here.
267 0 : if(asfd->write_str(asfd, CMD_GEN, "ok restore_list"))
268 : goto end;
269 0 : if(receive_a_file(asfd, sdirs->restore_list, get_cntr(cconfs)))
270 : {
271 : goto end;
272 : }
273 : }
274 : else
275 : {
276 2 : if(asfd->write_str(asfd, CMD_GEN, "ok"))
277 : goto end;
278 : }
279 :
280 2 : ret=do_restore_server(asfd, sdirs, act,
281 : srestore, &dir_for_notify, cconfs);
282 2 : if(dir_for_notify)
283 0 : maybe_do_notification(asfd, ret,
284 0 : sdirs->client, dir_for_notify,
285 : act==ACTION_RESTORE?"restorelog":"verifylog",
286 0 : act==ACTION_RESTORE?"restore":"verify",
287 : cconfs);
288 : end:
289 2 : free_w(&dir_for_notify);
290 2 : return ret;
291 : }
292 :
293 1 : static int run_delete(struct asfd *asfd,
294 : struct sdirs *sdirs, struct conf **cconfs)
295 : {
296 1 : char *backupno=NULL;
297 1 : struct iobuf *rbuf=asfd->rbuf;
298 1 : const char *cname=get_string(cconfs[OPT_CNAME]);
299 1 : if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DELETE))
300 : {
301 0 : logp("Not allowing delete of %s\n", cname);
302 0 : asfd->write_str(asfd, CMD_GEN, "Client delete is not allowed");
303 0 : return -1;
304 : }
305 1 : backupno=rbuf->buf+strlen("delete ");
306 1 : return do_delete_server(asfd, sdirs,
307 : cconfs, cname, backupno,
308 1 : get_string(cconfs[OPT_MANUAL_DELETE]));
309 : }
310 :
311 1 : static int run_list(struct asfd *asfd,
312 : struct sdirs *sdirs, struct conf **cconfs)
313 : {
314 1 : int ret=-1;
315 1 : char *cp=NULL;
316 1 : char *backupno=NULL;
317 1 : char *browsedir=NULL;
318 1 : char *listregex=NULL;
319 1 : struct iobuf *rbuf=asfd->rbuf;
320 :
321 1 : if(!client_can_generic(cconfs, OPT_CLIENT_CAN_LIST))
322 : {
323 0 : logp("Not allowing list of %s\n",
324 : get_string(cconfs[OPT_CNAME]));
325 0 : asfd->write_str(asfd, CMD_GEN, "Client list is not allowed");
326 0 : goto end;
327 : }
328 :
329 1 : if(!strncmp_w(rbuf->buf, "list "))
330 : {
331 1 : if((cp=strchr(rbuf->buf, ':')))
332 : {
333 0 : *cp='\0';
334 0 : if(!(listregex=strdup_w(cp+1, __func__)))
335 : goto end;
336 : }
337 1 : if(!(backupno=strdup_w(rbuf->buf+strlen("list "), __func__)))
338 : goto end;
339 :
340 : }
341 0 : else if(!strncmp_w(rbuf->buf, "listb "))
342 : {
343 0 : if((cp=strchr(rbuf->buf, ':')))
344 : {
345 0 : *cp='\0';
346 0 : if(!(browsedir=strdup_w(cp+1, __func__)))
347 : goto end;
348 : }
349 0 : strip_trailing_slashes(&browsedir);
350 0 : if(!(backupno=strdup_w(rbuf->buf+strlen("listb "), __func__)))
351 : goto end;
352 : }
353 1 : if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
354 :
355 1 : iobuf_free_content(asfd->rbuf);
356 :
357 1 : if(list_server_init(asfd, sdirs, cconfs,
358 : get_protocol(cconfs), backupno, listregex, browsedir))
359 : goto end;
360 1 : ret=do_list_server();
361 : end:
362 1 : free_w(&backupno);
363 1 : free_w(&browsedir);
364 1 : free_w(&listregex);
365 1 : list_server_free();
366 1 : return ret;
367 : }
368 :
369 1 : static int run_diff(struct asfd *asfd,
370 : struct sdirs *sdirs, struct conf **cconfs)
371 : {
372 1 : int ret=-1;
373 1 : char *backup1=NULL;
374 1 : char *backup2=NULL;
375 1 : struct iobuf *rbuf=asfd->rbuf;
376 :
377 1 : if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DIFF))
378 : {
379 0 : logp("Not allowing diff of %s\n",
380 : get_string(cconfs[OPT_CNAME]));
381 0 : asfd->write_str(asfd, CMD_GEN, "Client diff is not allowed");
382 0 : goto end;
383 : }
384 :
385 1 : if(!strncmp_w(rbuf->buf, "diff "))
386 : {
387 : char *cp;
388 1 : if((cp=strchr(rbuf->buf, ':')))
389 : {
390 0 : *cp='\0';
391 0 : if(!(backup2=strdup_w(cp+1, __func__)))
392 : goto end;
393 : }
394 1 : if(!(backup1=strdup_w(rbuf->buf+strlen("diff "), __func__)))
395 : goto end;
396 : }
397 1 : if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
398 :
399 1 : iobuf_free_content(asfd->rbuf);
400 :
401 1 : ret=do_diff_server(asfd, sdirs,
402 : cconfs, get_protocol(cconfs), backup1, backup2);
403 : end:
404 1 : free_w(&backup1);
405 1 : free_w(&backup2);
406 1 : return ret;
407 : }
408 :
409 : static int unknown_command(struct asfd *asfd, const char *func)
410 : {
411 2 : iobuf_log_unexpected(asfd->rbuf, func);
412 2 : asfd->write_str(asfd, CMD_ERROR, "unknown command");
413 : return -1;
414 : }
415 :
416 0 : static const char *buf_to_notify_str(struct iobuf *rbuf)
417 : {
418 0 : const char *buf=rbuf->buf;
419 0 : if(!strncmp_w(buf, "backup")) return "backup";
420 0 : else if(!strncmp_w(buf, "delete")) return "delete";
421 0 : else if(!strncmp_w(buf, "diff")) return "diff";
422 0 : else if(!strncmp_w(buf, "list")) return "list";
423 0 : else if(!strncmp_w(buf, "restore")) return "restore";
424 0 : else if(!strncmp_w(buf, "verify")) return "verify";
425 : else return "unknown";
426 : }
427 :
428 9 : static int maybe_write_first_created_file(struct sdirs *sdirs,
429 : const char *tstmp)
430 : {
431 9 : if(is_reg_lstat(sdirs->created)>0
432 9 : || is_lnk_lstat(sdirs->current)>0
433 9 : || is_lnk_lstat(sdirs->currenttmp)>0
434 9 : || is_lnk_lstat(sdirs->working)>0
435 9 : || is_lnk_lstat(sdirs->finishing)>0)
436 : return 0;
437 :
438 9 : return timestamp_write(sdirs->created, tstmp);
439 : }
440 :
441 9 : static int log_command(struct async *as,
442 : struct sdirs *sdirs, struct conf **cconfs, const char *tstmp)
443 : {
444 9 : struct fzp *fzp=NULL;
445 9 : struct asfd *asfd=as->asfd;
446 9 : struct iobuf *rbuf=asfd->rbuf;
447 9 : char *cname=get_string(cconfs[OPT_CONNECT_CLIENT]);
448 :
449 9 : if(rbuf->cmd!=CMD_GEN)
450 : return 0;
451 :
452 8 : if(!(fzp=fzp_open(sdirs->command, "a")))
453 : return -1;
454 8 : fzp_printf(fzp, "%s %s %s %s\n", tstmp, asfd->peer_addr, cname,
455 : iobuf_to_printable(rbuf));
456 8 : if(fzp_close(&fzp))
457 : return -1;
458 :
459 : return 0;
460 : }
461 :
462 10 : static int run_action_server_do(struct async *as, struct sdirs *sdirs,
463 : const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
464 : {
465 : int max_parallel_backups;
466 10 : int working=0;
467 : int ret;
468 10 : int resume=0;
469 10 : char msg[256]="";
470 10 : char tstmp[48]="";
471 10 : struct iobuf *rbuf=as->asfd->rbuf;
472 :
473 : // Make sure some directories exist.
474 10 : if(mkpath(&sdirs->current, sdirs->dedup))
475 : {
476 1 : snprintf(msg, sizeof(msg),
477 : "could not mkpath %s", sdirs->current);
478 1 : log_and_send(as->asfd, msg);
479 1 : return -1;
480 : }
481 :
482 9 : if(timestamp_get_new(/*index*/0,
483 : tstmp, sizeof(tstmp),
484 : /*bufforfile*/NULL, /*bs*/0,
485 : /*format*/NULL))
486 : return -1;
487 :
488 : // Carry on if these fail, otherwise you will not be able to restore
489 : // from readonly backups.
490 9 : maybe_write_first_created_file(sdirs, tstmp);
491 9 : log_command(as, sdirs, cconfs, tstmp);
492 :
493 9 : if(rbuf->cmd!=CMD_GEN)
494 2 : return unknown_command(as->asfd, __func__);
495 :
496 : // List and diff should work well enough without needing to lock
497 : // anything.
498 8 : if(!strncmp_w(rbuf->buf, "list ")
499 7 : || !strncmp_w(rbuf->buf, "listb "))
500 1 : return run_list(as->asfd, sdirs, cconfs);
501 :
502 7 : if(!strncmp_w(rbuf->buf, "diff "))
503 1 : return run_diff(as->asfd, sdirs, cconfs);
504 :
505 : // Old clients will send 'delete', possibly accidentally due to the
506 : // user trying to use the new diff/long diff options.
507 : // Stop them from working, just to be safe.
508 6 : if(!strncmp_w(rbuf->buf, "delete "))
509 : {
510 1 : logp("old style delete from %s denied\n",
511 : get_string(cconfs[OPT_CNAME]));
512 1 : as->asfd->write_str(as->asfd, CMD_ERROR,
513 : "old style delete is not supported on this server");
514 1 : return -1;
515 : }
516 :
517 : // Restore and verify should work well enough by locking only the
518 : // backup directory they are interested in.
519 5 : if(!strncmp_w(rbuf->buf, "restore ")
520 4 : || !strncmp_w(rbuf->buf, "verify "))
521 : {
522 2 : ret=run_restore(as->asfd, sdirs, cconfs, srestore);
523 2 : unlink(sdirs->restore_list);
524 2 : return ret;
525 : }
526 :
527 3 : if(strncmp_w(rbuf->buf, "backup")
528 2 : && strncmp_w(rbuf->buf, "Delete "))
529 2 : return unknown_command(as->asfd, __func__);
530 :
531 : // Beyond this point, only need to deal with backup and delete.
532 : // These require locking out all other backups and deletes.
533 :
534 2 : switch((ret=get_lock_sdirs_for_write(as->asfd, sdirs)))
535 : {
536 : case 0: break; // OK.
537 : case 1: return 1; // Locked out.
538 : default: // Error.
539 0 : maybe_do_notification(as->asfd, ret,
540 : "", "error in get_lock_sdirs()",
541 : "", buf_to_notify_str(rbuf), cconfs);
542 0 : return -1;
543 : }
544 :
545 2 : switch((ret=check_for_rubble_and_clean(as, sdirs,
546 : incexc, &resume, cconfs)))
547 : {
548 : case 0: break; // OK.
549 : case 1: return 1; // Now finalising.
550 : default: // Error.
551 0 : maybe_do_notification(as->asfd, ret,
552 : "", "error in check_for_rubble()",
553 : "", buf_to_notify_str(rbuf), cconfs);
554 0 : return -1;
555 : }
556 :
557 2 : if(!strncmp_w(rbuf->buf, "Delete "))
558 1 : return run_delete(as->asfd, sdirs, cconfs);
559 :
560 : // Only backup action left to deal with.
561 1 : working = server_get_working(NULL);
562 1 : max_parallel_backups = get_int(cconfs[OPT_MAX_PARALLEL_BACKUPS]);
563 :
564 1 : logp("%d/%d working (cur/max)\n", working, max_parallel_backups);
565 :
566 1 : if(max_parallel_backups && working >= max_parallel_backups)
567 : {
568 0 : struct asfd *asfd=as->asfd;
569 0 : logp("max parallel backups reached\n");
570 0 : return asfd->write_str(asfd, CMD_GEN, "max parallel backups");
571 : }
572 :
573 1 : ret=run_backup(as, sdirs,
574 : cconfs, incexc, timer_ret, resume);
575 :
576 : // If this is a backup failure and the client has more servers
577 : // to failover to, do not notify.
578 1 : if(ret
579 1 : && get_int(cconfs[OPT_N_FAILURE_BACKUP_FAILOVERS_LEFT])
580 1 : && get_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT]))
581 : return ret;
582 :
583 1 : if(*timer_ret<0)
584 0 : maybe_do_notification(as->asfd, ret,
585 : "", "error running timer script",
586 : "", "backup", cconfs);
587 1 : else if(!*timer_ret)
588 1 : maybe_do_notification(as->asfd, ret,
589 1 : sdirs->client, sdirs->current,
590 : "log", "backup", cconfs);
591 : return ret;
592 : }
593 :
594 10 : int run_action_server(struct async *as,
595 : const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
596 : {
597 10 : int ret=-1;
598 10 : struct sdirs *sdirs=NULL;
599 10 : if((sdirs=sdirs_alloc())
600 10 : && !sdirs_init_from_confs(sdirs, cconfs))
601 10 : ret=run_action_server_do(as,
602 : sdirs, incexc, srestore, timer_ret, cconfs);
603 10 : if(sdirs) lock_release(sdirs->lock_storage_for_write);
604 10 : sdirs_free(&sdirs);
605 10 : return ret;
606 : }
|