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

Generated by: LCOV version 1.10