/* * Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com> * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Redis nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "fmacros.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include "config.h"#define ERROR(...) { \ char __buf[1024]; \ sprintf(__buf, __VA_ARGS__); \ sprintf(error, "0x%16llx: %s", (long long)epos, __buf); \}staticcharerror[1024];staticoff_tepos;intconsumeNewline(char*buf){if(strncmp(buf,"\r\n",2)!=0){ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]);return0;}return1;}intreadLong(FILE*fp,charprefix,long*target){charbuf[128],*eptr;epos=ftello(fp);if(fgets(buf,sizeof(buf),fp)==NULL){return0;}if(buf[0]!=prefix){ERROR("Expected prefix '%c', got: '%c'",buf[0],prefix);return0;}*target=strtol(buf+1,&eptr,10);returnconsumeNewline(eptr);}intreadBytes(FILE*fp,char*target,longlength){longreal;epos=ftello(fp);real=fread(target,1,length,fp);if(real!=length){ERROR("Expected to read %ld bytes, got %ld bytes",length,real);return0;}return1;}intreadString(FILE*fp,char**target){longlen;*target=NULL;if(!readLong(fp,'$',&len)){return0;}/* Increase length to also consume \r\n */len+=2;*target=(char*)malloc(len);if(!readBytes(fp,*target,len)){return0;}if(!consumeNewline(*target+len-2)){return0;}(*target)[len-2]='\0';return1;}intreadArgc(FILE*fp,long*target){returnreadLong(fp,'*',target);}off_tprocess(FILE*fp){longargc;off_tpos=0;inti,multi=0;char*str;while(1){if(!multi)pos=ftello(fp);if(!readArgc(fp,&argc))break;for(i=0;i<argc;i++){if(!readString(fp,&str))break;if(i==0){if(strcasecmp(str,"multi")==0){if(multi++){ERROR("Unexpected MULTI");break;}}elseif(strcasecmp(str,"exec")==0){if(--multi){ERROR("Unexpected EXEC");break;}}}free(str);}/* Stop if the loop did not finish */if(i<argc){if(str)free(str);break;}}if(feof(fp)&&multi&&strlen(error)==0){ERROR("Reached EOF before reading EXEC for MULTI");}if(strlen(error)>0){printf("%s\n",error);}returnpos;}intmain(intargc,char**argv){char*filename;intfix=0;if(argc<2){printf("Usage: %s [--fix] <file.aof>\n",argv[0]);exit(1);}elseif(argc==2){filename=argv[1];}elseif(argc==3){if(strcmp(argv[1],"--fix")!=0){printf("Invalid argument: %s\n",argv[1]);exit(1);}filename=argv[2];fix=1;}else{printf("Invalid arguments\n");exit(1);}FILE*fp=fopen(filename,"r+");if(fp==NULL){printf("Cannot open file: %s\n",filename);exit(1);}structredis_statsb;if(redis_fstat(fileno(fp),&sb)==-1){printf("Cannot stat file: %s\n",filename);exit(1);}off_tsize=sb.st_size;if(size==0){printf("Empty file: %s\n",filename);exit(1);}off_tpos=process(fp);off_tdiff=size-pos;printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",(longlong)size,(longlong)pos,(longlong)diff);if(diff>0){if(fix){charbuf[2];printf("This will shrink the AOF from %lld bytes, with %lld bytes, to %lld bytes\n",(longlong)size,(longlong)diff,(longlong)pos);printf("Continue? [y/N]: ");if(fgets(buf,sizeof(buf),stdin)==NULL||strncasecmp(buf,"y",1)!=0){printf("Aborting...\n");exit(1);}if(ftruncate(fileno(fp),pos)==-1){printf("Failed to truncate AOF\n");exit(1);}else{printf("Successfully truncated AOF\n");}}else{printf("AOF is not valid\n");exit(1);}}else{printf("AOF is valid\n");}fclose(fp);return0;}