LCOV - code coverage report
Current view: top level - src/server - rubble.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 0 132 0.0 %
Date: 2016-11-02 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../fsops.h"
       6             : #include "../fzp.h"
       7             : #include "../handy.h"
       8             : #include "../log.h"
       9             : #include "../prepend.h"
      10             : #include "protocol1/backup_phase4.h"
      11             : #include "protocol2/backup_phase4.h"
      12             : #include "sdirs.h"
      13             : #include "rubble.h"
      14             : 
      15           0 : static int incexc_matches(const char *fullrealwork, const char *incexc)
      16             : {
      17           0 :         int ret=0;
      18           0 :         int got=0;
      19           0 :         struct fzp *fzp=NULL;
      20           0 :         char buf[4096]="";
      21           0 :         const char *inc=NULL;
      22           0 :         char *old_incexc_path=NULL;
      23           0 :         if(!(old_incexc_path=prepend_s(fullrealwork, "incexc")))
      24             :                 return -1;
      25           0 :         if(!(fzp=fzp_open(old_incexc_path, "rb")))
      26             :         {
      27             :                 // Assume that no incexc file could be found because the client
      28             :                 // was on an old version. Assume resume is OK and return 1.
      29             :                 ret=1;
      30             :                 goto end;
      31             :         }
      32             :         inc=incexc;
      33           0 :         while((got=fzp_read(fzp, buf, sizeof(buf)))>0)
      34             :         {
      35           0 :                 if(strlen(inc)<(size_t)got) break;
      36           0 :                 if(strncmp(buf, inc, got)) break;
      37           0 :                 inc+=got;
      38             :         }
      39           0 :         if(inc && strlen(inc)) ret=0;
      40           0 :         else ret=1;
      41             : end:
      42           0 :         fzp_close(&fzp);
      43           0 :         free_w(&old_incexc_path);
      44           0 :         return ret;
      45             : }
      46             : 
      47           0 : static int working_delete(struct async *as, struct sdirs *sdirs)
      48             : {
      49             :         // Try to remove it and start again.
      50           0 :         logp("deleting old working directory\n");
      51           0 :         if(recursive_delete(sdirs->rworking))
      52             :         {
      53           0 :                 log_and_send(as->asfd,
      54             :                         "Old working directory is in the way.\n");
      55             :                 return -1;
      56             :         }
      57             :         // Get rid of the symlink.
      58           0 :         unlink(sdirs->working);
      59             :         return 0;
      60             : }
      61             : 
      62           0 : static int working_resume(struct async *as, struct sdirs *sdirs,
      63             :         const char *incexc, int *resume, struct conf **cconfs)
      64             : {
      65           0 :         if(get_string(cconfs[OPT_RESTORE_CLIENT]))
      66             :         {
      67             :                 // This client is not the original client, resuming might cause
      68             :                 // all sorts of trouble.
      69           0 :                 log_and_send(as->asfd, "Found interrupted backup - not resuming because the connected client is not the original");
      70           0 :                 return -1;
      71             :         }
      72             : 
      73           0 :         logp("Found interrupted backup.\n");
      74             : 
      75             :         // Check that the current incexc configuration is the same
      76             :         // as before.
      77           0 :         switch(incexc_matches(sdirs->rworking, incexc))
      78             :         {
      79             :                 case 1:
      80             :                         // Attempt to resume on the next backup.
      81           0 :                         logp("Will resume on the next backup request.\n");
      82           0 :                         *resume=1;
      83           0 :                         return 0;
      84             :                 case 0:
      85           0 :                         logp("Includes/excludes changed since last backup.\n");
      86           0 :                         logp("Will delete instead of resuming.\n");
      87           0 :                         return working_delete(as, sdirs);
      88             :                 case -1:
      89             :                 default:
      90             :                         return -1;
      91             :         }
      92             : }
      93             : 
      94           0 : static int get_fullrealwork(struct sdirs *sdirs)
      95             : {
      96             :         struct stat statp;
      97             : 
      98           0 :         if(sdirs_get_real_working_from_symlink(sdirs))
      99             :                 return -1;
     100             : 
     101           0 :         if(lstat(sdirs->rworking, &statp))
     102             :         {
     103           0 :                 logp("removing dangling working symlink %s -> %s\n",
     104             :                         sdirs->working, sdirs->rworking);
     105           0 :                 unlink(sdirs->working);
     106           0 :                 free_w(&sdirs->rworking);
     107             :         }
     108             :         return 0;
     109             : }
     110             : 
     111           0 : static int recover_finishing(struct async *as,
     112             :         struct sdirs *sdirs, struct conf **cconfs)
     113             : {
     114             :         int r;
     115           0 :         char msg[128]="";
     116           0 :         struct asfd *asfd=as->asfd;
     117           0 :         logp("Found finishing symlink - attempting to complete prior backup!\n");
     118             : 
     119             :         snprintf(msg, sizeof(msg),
     120             :                 "Now finalising previous backup of client. "
     121             :                 "Please try again later.");
     122           0 :         asfd->write_str(asfd, CMD_ERROR, msg);
     123             : 
     124             :         // Do not need the client connected any more.
     125             :         // Disconnect.
     126           0 :         logp("Disconnect from client.\n");
     127           0 :         as->asfd_remove(as, asfd);
     128           0 :         asfd_close(asfd);
     129             : 
     130           0 :         switch(get_protocol(cconfs))
     131             :         {
     132             :                 case PROTO_1:
     133           0 :                         r=backup_phase4_server_protocol1(sdirs, cconfs);
     134           0 :                         break;
     135             :                 case PROTO_2:
     136             :                 default:
     137           0 :                         r=backup_phase4_server_protocol2(sdirs, cconfs);
     138           0 :                         break;
     139             :         }
     140           0 :         if(r)
     141             :         {
     142           0 :                 logp("Problem with prior backup. Please check the client log on the server.");
     143           0 :                 return -1;
     144             :         }
     145           0 :         logp("Prior backup completed OK.\n");
     146             : 
     147             :         // Move the symlink to indicate that we are now in the end
     148             :         // phase.
     149             :         // FIX THIS: Check whether the rename race condition is recoverable
     150             :         // here.
     151           0 :         if(do_rename(sdirs->finishing, sdirs->current)) return -1;
     152           0 :         return 0;
     153             : }
     154             : 
     155           0 : static void log_recovery_method(struct sdirs *sdirs,
     156             :         enum recovery_method recovery_method)
     157             : {
     158           0 :         logp("found old working directory: %s\n", sdirs->rworking);
     159           0 :         logp("working_dir_recovery_method: %s\n",
     160             :                 recovery_method_to_str(recovery_method));
     161           0 : }
     162             : 
     163           0 : static int recover_working(struct async *as,
     164             :         struct sdirs *sdirs, const char *incexc,
     165             :         int *resume, struct conf **cconfs)
     166             : {
     167           0 :         int ret=-1;
     168           0 :         char msg[256]="";
     169           0 :         char *logpath=NULL;
     170             :         struct stat statp;
     171           0 :         char *phase1datatmp=NULL;
     172           0 :         enum recovery_method recovery_method=get_e_recovery_method(
     173             :                 cconfs[OPT_WORKING_DIR_RECOVERY_METHOD]);
     174             : 
     175             :         // The working directory has not finished being populated.
     176             :         // Check what to do.
     177           0 :         if(get_fullrealwork(sdirs)) goto end;
     178           0 :         if(!sdirs->rworking) goto end;
     179             : 
     180           0 :         log_recovery_method(sdirs, recovery_method);
     181             : 
     182           0 :         if(!(phase1datatmp=get_tmp_filename(sdirs->phase1data)))
     183             :                 goto end;
     184             :         // If there is still a phase1 tmp file...
     185           0 :         if(!lstat(phase1datatmp, &statp)
     186           0 :           ||
     187             :                 // ...or phase1 has not even got underway yet...
     188           0 :                 (lstat(phase1datatmp, &statp)
     189           0 :                   && lstat(sdirs->phase1data, &statp)
     190           0 :                   && lstat(sdirs->changed, &statp)
     191           0 :                   && lstat(sdirs->unchanged, &statp)))
     192             :         {
     193             :                 // ...phase 1 did not complete - delete everything.
     194           0 :                 logp("Phase 1 has not completed.\n");
     195           0 :                 recovery_method=RECOVERY_METHOD_DELETE;
     196             :         }
     197             : 
     198           0 :         if(recovery_method==RECOVERY_METHOD_DELETE)
     199             :         {
     200           0 :                 ret=working_delete(as, sdirs);
     201           0 :                 goto end;
     202             :         }
     203             : 
     204             :         // We are not deleting the old working directory - open the log inside
     205             :         // for appending.
     206           0 :         if(!(logpath=prepend_s(sdirs->rworking, "log"))
     207           0 :           || log_fzp_set(logpath, cconfs))
     208             :                 goto end;
     209             : 
     210           0 :         switch(recovery_method)
     211             :         {
     212             :                 case RECOVERY_METHOD_DELETE:
     213             :                         // Dealt with above.
     214             :                         break;
     215             :                 case RECOVERY_METHOD_RESUME:
     216           0 :                         ret=working_resume(as, sdirs, incexc, resume, cconfs);
     217           0 :                         break;
     218             :                 case RECOVERY_METHOD_UNSET:
     219             :                 default:
     220           0 :                         snprintf(msg, sizeof(msg),
     221             :                                 "Unknown working_dir_recovery_method: %d\n",
     222             :                                         (int)recovery_method);
     223           0 :                         log_and_send(as->asfd, msg);
     224           0 :                         break;
     225             :         }
     226             : 
     227             : end:
     228           0 :         free_w(&logpath);
     229           0 :         free_w(&phase1datatmp);
     230           0 :         log_fzp_set(NULL, cconfs); // fclose the logfzp
     231           0 :         return ret;
     232             : }
     233             : 
     234           0 : static int recover_currenttmp(struct sdirs *sdirs)
     235             : {
     236           0 :         logp("Found currenttmp symlink\n");
     237           0 :         switch(is_lnk_valid(sdirs->currenttmp))
     238             :         {
     239             :                 case 0:
     240           0 :                         logp("But currenttmp is not pointing at something valid.\n");
     241           0 :                         logp("Deleting it.\n");
     242           0 :                         return unlink_w(sdirs->currenttmp, __func__);
     243             :                 case -1:
     244             :                         return -1;
     245             :         }
     246             : 
     247           0 :         switch(is_lnk(sdirs->current))
     248             :         {
     249             :                 case 0:
     250           0 :                         logp("But current already exists and is not a symlink!\n");
     251           0 :                         logp("Giving up.\n");
     252             :                         return -1;
     253             :                 case 1:
     254           0 :                         logp("But current symlink already exists!\n");
     255           0 :                         switch(is_lnk_valid(sdirs->current))
     256             :                         {
     257             :                                 case 0:
     258           0 :                                         logp("But current symlink is not pointing at something valid.\n");
     259           0 :                                         logp("Replacing current with currenttmp.\n");
     260           0 :                                         return do_rename(sdirs->currenttmp,
     261           0 :                                                 sdirs->current);
     262             :                                 case 1:
     263           0 :                                         logp("And current symlink points at something valid.\n");
     264           0 :                                         logp("Deleting currenttmp.\n");
     265           0 :                                         return unlink_w(sdirs->currenttmp, __func__);
     266             :                                 default:
     267             :                                         return -1;
     268             :                         }
     269             :                 default:
     270           0 :                         logp("Renaming currenttmp to current\n");
     271           0 :                         return do_rename(sdirs->currenttmp, sdirs->current);
     272             :         }
     273             : }
     274             : 
     275             : // Return 1 if the backup is now finalising.
     276           0 : int check_for_rubble(struct async *as,
     277             :         struct sdirs *sdirs, const char *incexc,
     278             :         int *resume, struct conf **cconfs)
     279             : {
     280           0 :         struct asfd *asfd=as->asfd;
     281             : 
     282           0 :         switch(is_lnk(sdirs->finishing))
     283             :         {
     284             :                 case 1:
     285           0 :                         if(recover_finishing(as, sdirs, cconfs))
     286             :                                 return -1;
     287           0 :                         return 1;
     288             :                 case 0:
     289           0 :                         log_and_send(asfd,
     290             :                                 "Finishing directory is not a symlink.\n");
     291           0 :                         return -1;
     292             :         }
     293             : 
     294           0 :         switch(is_lnk(sdirs->working))
     295             :         {
     296             :                 case 1:
     297           0 :                         return recover_working(as,
     298             :                                 sdirs, incexc, resume, cconfs);
     299             :                 case 0:
     300           0 :                         log_and_send(asfd,
     301             :                                 "Working directory is not a symlink.\n");
     302           0 :                         return -1;
     303             :         }
     304             : 
     305           0 :         switch(is_lnk(sdirs->currenttmp))
     306             :         {
     307             :                 case 1:
     308           0 :                         return recover_currenttmp(sdirs);
     309             :                 case 0:
     310           0 :                         log_and_send(asfd,
     311             :                                 "Currenttmp directory is not a symlink.\n");
     312           0 :                         return -1;
     313             :         }
     314             : 
     315             :         return 0;
     316             : }

Generated by: LCOV version 1.10