1125461Speter/* 2125461Speter * ---------------------------------------------------------------------------- 3125461Speter * "THE BEER-WARE LICENSE" (Revision 42): 4125461Speter * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5125461Speter * can do whatever you want with this stuff. If we meet some day, and you think 6125984Sobrien * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7125461Speter * ---------------------------------------------------------------------------- 8125461Speter * 9125461Speter * $FreeBSD: releng/10.3/usr.sbin/ctm/ctm/ctm.c 93150 2002-03-25 13:53:46Z phk $ 10125461Speter * 11126929Speter * This is the client program of 'CTM'. It will apply a CTM-patch to a 12147687Speter * collection of files. 13125461Speter * 14209313Skib * Options we'd like to see: 15209313Skib * 16209313Skib * -a Attempt best effort. 17209313Skib * -d <int> Debug TBD. 18209313Skib * -m <mail-addr> Email me instead. 19209313Skib * -r <name> Reconstruct file. 20125461Speter * -R <file> Read list of files to reconstruct. 21126541Sobrien * 22126541Sobrien * Options we have: 23126541Sobrien * -b <dir> Base-dir 24126541Sobrien * -B <file> Backup to tar-file. 25126541Sobrien * -t Tar command (default as in TARCMD). 26147378Sups * -c Check it out, don't do anything. 27147378Sups * -F Force 28125461Speter * -q Tell us less. 29126541Sobrien * -T <tmpdir>. Temporary files. 30147378Sups * -u Set all file modification times to the timestamp 31126638Sobrien * -v Tell us more. 32126637Sobrien * -V <level> Tell us more level = number of -v 33126541Sobrien * -k Keep files and directories that would have been removed. 34142732Sobrien * -l List actions. 35142732Sobrien * 36142732Sobrien * Options we don't actually use: 37142732Sobrien * -p Less paranoid. 38142732Sobrien * -P Paranoid. 39209248Smav */ 40209248Smav 41209248Smav#define EXTERN /* */ 42209248Smav#include <paths.h> 43145727Sdwhite#include "ctm.h" 44209248Smav 45126541Sobrien#define CTM_STATUS ".ctm_status" 46126541Sobrien 47126541Sobrienextern int Proc(char *, unsigned applied); 48126541Sobrien 49125461Speterint 50126541Sobrienmain(int argc, char **argv) 51126541Sobrien{ 52126541Sobrien int stat=0, err=0; 53126541Sobrien int c; 54126541Sobrien unsigned applied = 0; 55126541Sobrien FILE *statfile; 56126541Sobrien struct CTM_Filter *nfilter = NULL; /* new filter */ 57126541Sobrien u_char * basedir; 58126541Sobrien 59126541Sobrien basedir = NULL; 60126541Sobrien Verbose = 1; 61125461Speter Paranoid = 1; 62125461Speter SetTime = 0; 63125461Speter KeepIt = 0; 64126541Sobrien ListIt = 0; 65125461Speter BackupFile = NULL; 66125461Speter TarCmd = TARCMD; 67125461Speter LastFilter = FilterList = NULL; 68125461Speter TmpDir = getenv("TMPDIR"); 69125461Speter if (TmpDir == NULL) 70125461Speter TmpDir = strdup(_PATH_TMP); 71125461Speter setbuf(stderr,0); 72125461Speter setbuf(stdout,0); 73125461Speter 74125461Speter while((c=getopt(argc,argv,"ab:B:cd:e:Fklm:pPqr:R:t:T:uV:vx:")) != -1) { 75126541Sobrien switch (c) { 76125461Speter case 'b': basedir = optarg; break; /* Base Directory */ 77125461Speter case 'B': BackupFile = optarg; break; 78125461Speter case 'c': CheckIt++; break; /* Only check it */ 79151051Sglebius case 'F': Force = 1; break; 80151051Sglebius case 'k': KeepIt++; break; /* Don't do removes */ 81151051Sglebius case 'l': ListIt++; break; /* Only list actions and files */ 82151051Sglebius case 'p': Paranoid--; break; /* Less Paranoid */ 83125461Speter case 'P': Paranoid++; break; /* More Paranoid */ 84126541Sobrien case 'q': Verbose--; break; /* Quiet */ 85126541Sobrien case 't': TarCmd = optarg; break; /* archiver command */ 86125461Speter case 'T': TmpDir = optarg; break; /* set temporary directory */ 87125461Speter case 'u': SetTime++; break; /* Set timestamp on files */ 88125461Speter case 'v': Verbose++; break; /* Verbose */ 89177586Sjkim case 'V': sscanf(optarg,"%d", &c); /* Verbose */ 90177586Sjkim Verbose += c; 91191954Skuriyama break; 92177586Sjkim case 'e': /* filter expressions */ 93234183Sjhb case 'x': 94234183Sjhb if (NULL == (nfilter = Malloc(sizeof(struct CTM_Filter)))) { 95234183Sjhb warnx("out of memory for expressions: \"%s\"", optarg); 96234183Sjhb stat++; 97234183Sjhb break; 98234183Sjhb } 99234183Sjhb 100234183Sjhb (void) memset(nfilter, 0, sizeof(struct CTM_Filter)); 101239771Sjhb 102234183Sjhb if (0 != (err = 103234183Sjhb regcomp(&nfilter->CompiledRegex, optarg, REG_NOSUB))) { 104234183Sjhb 105234183Sjhb char errmsg[128]; 106125461Speter 107125461Speter regerror(err, &nfilter->CompiledRegex, errmsg, 108125461Speter sizeof(errmsg)); 109125461Speter warnx("regular expression: \"%s\"", errmsg); 110173160Speter stat++; 111173160Speter break; 112173160Speter } 113125461Speter 114125461Speter /* note whether the filter enables or disables on match */ 115125461Speter nfilter->Action = 116125461Speter (('e' == c) ? CTM_FILTER_ENABLE : CTM_FILTER_DISABLE); 117152306Sru 118152306Sru /* link in the expression into the list */ 119152306Sru nfilter->Next = NULL; 120126541Sobrien if (NULL == FilterList) { 121125461Speter LastFilter = FilterList = nfilter; /* init head and tail */ 122125461Speter } else { /* place at tail */ 123125461Speter LastFilter->Next = nfilter; 124125461Speter LastFilter = nfilter; 125125461Speter } 126125461Speter break; 127125461Speter case ':': 128125461Speter warnx("option '%c' requires an argument",optopt); 129125461Speter stat++; 130125461Speter break; 131125461Speter case '?': 132125461Speter warnx("option '%c' not supported",optopt); 133125461Speter stat++; 134125461Speter break; 135125461Speter default: 136125461Speter warnx("option '%c' not yet implemented",optopt); 137125461Speter break; 138125461Speter } 139125461Speter } 140125461Speter 141125461Speter if(stat) { 142125461Speter warnx("%d errors during option processing",stat); 143125461Speter return Exit_Pilot; 144125461Speter } 145125461Speter stat = Exit_Done; 146125461Speter argc -= optind; 147125461Speter argv += optind; 148125461Speter 149125461Speter if (basedir == NULL) { 150125461Speter Buffer = (u_char *)Malloc(BUFSIZ + strlen(SUBSUFF) +1); 151125461Speter CatPtr = Buffer; 152125461Speter *Buffer = '\0'; 153125461Speter } else { 154125461Speter Buffer = (u_char *)Malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1); 155125461Speter strcpy(Buffer, basedir); 156125461Speter CatPtr = Buffer + strlen(basedir); 157126541Sobrien if (CatPtr[-1] != '/') { 158126541Sobrien strcat(Buffer, "/"); 159126541Sobrien CatPtr++; 160125461Speter } 161125461Speter } 162125461Speter strcat(Buffer, CTM_STATUS); 163125461Speter 164125461Speter if(ListIt) 165125461Speter applied = 0; 166125461Speter else 167125461Speter if((statfile = fopen(Buffer, "r")) == NULL) { 168125461Speter if (Verbose > 0) 169125461Speter warnx("warning: %s not found", Buffer); 170125461Speter } else { 171125461Speter fscanf(statfile, "%*s %u", &applied); 172188247Swkoszek fclose(statfile); 173188247Swkoszek } 174188247Swkoszek 175191954Skuriyama if(!argc) 176188247Swkoszek stat |= Proc("-", applied); 177125461Speter 178125461Speter while(argc-- && stat == Exit_Done) { 179125461Speter stat |= Proc(*argv++, applied); 180125461Speter stat &= ~(Exit_Version | Exit_NoMatch); 181197380Sdelphij } 182197025Sdelphij 183197025Sdelphij if(stat == Exit_Done) 184197025Sdelphij stat = Exit_OK; 185197025Sdelphij 186197025Sdelphij if(Verbose > 0) 187197397Sdelphij warnx("exit(%d)",stat); 188197397Sdelphij 189197397Sdelphij if (FilterList) 190197397Sdelphij for (nfilter = FilterList; nfilter; ) { 191197397Sdelphij struct CTM_Filter *tmp = nfilter->Next; 192125461Speter Free(nfilter); 193125461Speter nfilter = tmp; 194125461Speter } 195125461Speter return stat; 196163535Sdes} 197163535Sdes 198163535Sdesint 199163535SdesProc(char *filename, unsigned applied) 200163535Sdes{ 201163535Sdes FILE *f; 202163535Sdes int i; 203163535Sdes char *p = strrchr(filename,'.'); 204163535Sdes 205163535Sdes if(!strcmp(filename,"-")) { 206163535Sdes p = 0; 207163535Sdes f = stdin; 208163535Sdes } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) { 209163535Sdes p = alloca(20 + strlen(filename)); 210163535Sdes strcpy(p,"gunzip < "); 211163535Sdes strcat(p,filename); 212163535Sdes f = popen(p,"r"); 213163535Sdes if(!f) { warn("%s", p); return Exit_Garbage; } 214163535Sdes } else { 215163535Sdes p = 0; 216163535Sdes f = fopen(filename,"r"); 217163535Sdes } 218163535Sdes if(!f) { 219163535Sdes warn("%s", filename); 220163535Sdes return Exit_Garbage; 221163535Sdes } 222163535Sdes 223163535Sdes if(Verbose > 1) 224163535Sdes fprintf(stderr,"Working on <%s>\n",filename); 225163535Sdes 226163535Sdes Delete(FileName); 227163535Sdes FileName = String(filename); 228163535Sdes 229163535Sdes /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */ 230163535Sdes if(!p && -1 == fseek(f,0,SEEK_END)) { 231163535Sdes char *fn; 232163535Sdes FILE *f2; 233163535Sdes int fd; 234163535Sdes 235163535Sdes if (asprintf(&fn, "%s/CTMclient.XXXXXXXXXX", TmpDir) == -1) { 236163535Sdes fprintf(stderr, "Cannot allocate memory\n"); 237163535Sdes fclose(f); 238163535Sdes return Exit_Broke; 239163535Sdes } 240163535Sdes if ((fd = mkstemp(fn)) == -1 || (f2 = fdopen(fd, "w+")) == NULL) { 241163535Sdes warn("%s", fn); 242163535Sdes free(fn); 243163535Sdes if (fd != -1) 244163535Sdes close(fd); 245163535Sdes fclose(f); 246163535Sdes return Exit_Broke; 247163535Sdes } 248163535Sdes unlink(fn); 249163535Sdes if (Verbose > 0) 250163535Sdes fprintf(stderr,"Writing tmp-file \"%s\"\n",fn); 251197379Sdelphij free(fn); 252197379Sdelphij while(EOF != (i=getc(f))) 253197379Sdelphij if(EOF == putc(i,f2)) { 254126541Sobrien fclose(f2); 255126541Sobrien return Exit_Broke; 256126541Sobrien } 257126541Sobrien fclose(f); 258125461Speter f = f2; 259126541Sobrien } 260156354Syar 261126541Sobrien if(!p) 262126541Sobrien rewind(f); 263156354Syar 264126541Sobrien if((i=Pass1(f, applied))) 265126541Sobrien goto exit_and_close; 266125461Speter 267125461Speter if(ListIt) { 268125461Speter i = Exit_Done; 269125461Speter goto exit_and_close; 270125461Speter } 271125461Speter 272125461Speter if(!p) { 273126541Sobrien rewind(f); 274125461Speter } else { 275125461Speter pclose(f); 276125461Speter f = popen(p,"r"); 277171146Snjl if(!f) { warn("%s", p); return Exit_Broke; } 278171146Snjl } 279171146Snjl 280145132Sanholt i=Pass2(f); 281145132Sanholt 282153033Sanholt if(!p) { 283145132Sanholt rewind(f); 284145132Sanholt } else { 285145132Sanholt pclose(f); 286148211Sanholt f = popen(p,"r"); 287152909Sanholt if(!f) { warn("%s", p); return Exit_Broke; } 288145132Sanholt } 289145132Sanholt 290203288Srnoland if(i) { 291145132Sanholt if((!Force) || (i & ~Exit_Forcible)) 292125461Speter goto exit_and_close; 293125461Speter } 294125461Speter 295125461Speter if(CheckIt) { 296125461Speter if (Verbose > 0) 297255736Sdavidch fprintf(stderr,"All checks out ok.\n"); 298255736Sdavidch i = Exit_Done; 299125984Sobrien goto exit_and_close; 300163494Simp } 301129293Speter 302159549Sjhb /* backup files if requested */ 303203691Sbrucec if(BackupFile) { 304159549Sjhb 305203691Sbrucec i = PassB(f); 306203691Sbrucec 307203691Sbrucec if(!p) { 308234183Sjhb rewind(f); 309234183Sjhb } else { 310234183Sjhb pclose(f); 311159967Sobrien f = popen(p,"r"); 312151907Sjhb if(!f) { warn("%s", p); return Exit_Broke; } 313228085Sphilip } 314255323Sbryanv } 315173491Sbenjsc 316203691Sbrucec i=Pass3(f); 317125461Speter 318255736Sdavidchexit_and_close: 319233872Sjhb if(!p) 320148263Speter fclose(f); 321148263Speter else 322148263Speter pclose(f); 323233872Sjhb 324233872Sjhb if(i) 325233872Sjhb return i; 326234183Sjhb 327234183Sjhb if (Verbose > 0) 328234183Sjhb fprintf(stderr,"All done ok\n"); 329233872Sjhb 330233872Sjhb return Exit_Done; 331240098Sjhb} 332255323Sbryanv