LCOV - code coverage report
Current view: top level - src/server - backup.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 72 180 40.0 %
Date: 2020-05-31 21:14:12 Functions: 7 11 63.6 %

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

Generated by: LCOV version 1.13