ctm.c revision 13917
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $Id: ctm.c,v 1.11 1995/05/30 03:47:19 rgrimes Exp $ 10 * 11 * This is the client program of 'CTM'. It will apply a CTM-patch to a 12 * collection of files. 13 * 14 * Options we'd like to see: 15 * 16 * -a Attempt best effort. 17 * -B <file> Backup to tar-file. 18 * -d <int> Debug TBD. 19 * -m <mail-addr> Email me instead. 20 * -r <name> Reconstruct file. 21 * -R <file> Read list of files to reconstruct. 22 * 23 * Options we have: 24 * -b <dir> Base-dir 25 * -c Check it out, don't do anything. 26 * -F Force 27 * -p Less paranoid. 28 * -P Paranoid. 29 * -q Tell us less. 30 * -T <tmpdir>. Temporary files. 31 * -v Tell us more. 32 * -V <level> Tell us more level = number of -v 33 * 34 */ 35 36#define EXTERN /* */ 37#include "ctm.h" 38 39#define CTM_STATUS ".ctm_status" 40 41extern int Proc(char *, unsigned applied); 42 43int 44main(int argc, char **argv) 45{ 46 int stat=0; 47 int c; 48 extern int optopt,optind; 49 extern char * optarg; 50 unsigned applied = 0; 51 FILE *statfile; 52 u_char * basedir; 53 54 basedir = NULL; 55 Verbose = 1; 56 Paranoid = 1; 57 setbuf(stderr,0); 58 setbuf(stdout,0); 59 60 while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:V:v")) != -1) { 61 switch (c) { 62 case 'b': basedir = optarg; break; /* Base Directory */ 63 case 'c': CheckIt++; break; /* Only check it */ 64 case 'p': Paranoid--; break; /* Less Paranoid */ 65 case 'P': Paranoid++; break; /* More Paranoid */ 66 case 'q': Verbose--; break; /* Quiet */ 67 case 'v': Verbose++; break; /* Verbose */ 68 case 'T': TmpDir = optarg; break; 69 case 'F': Force = 1; break; 70 case 'V': sscanf(optarg,"%d", &c); /* Verbose */ 71 Verbose += c; 72 break; 73 case ':': 74 fprintf(stderr,"Option '%c' requires an argument.\n",optopt); 75 stat++; 76 break; 77 case '?': 78 fprintf(stderr,"Option '%c' not supported.\n",optopt); 79 stat++; 80 break; 81 default: 82 fprintf(stderr,"Option '%c' not yet implemented.\n",optopt); 83 break; 84 } 85 } 86 87 if(stat) { 88 fprintf(stderr,"%d errors during option processing\n",stat); 89 return Exit_Pilot; 90 } 91 stat = Exit_Done; 92 argc -= optind; 93 argv += optind; 94 95 if (basedir == NULL) { 96 Buffer = (u_char *)Malloc(BUFSIZ + strlen(SUBSUFF) +1); 97 CatPtr = Buffer; 98 *Buffer = '\0'; 99 } else { 100 Buffer = (u_char *)Malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1); 101 strcpy(Buffer, basedir); 102 CatPtr = Buffer + strlen(basedir); 103 if (CatPtr[-1] != '/') { 104 strcat(Buffer, "/"); 105 CatPtr++; 106 } 107 } 108 strcat(Buffer, CTM_STATUS); 109 110 if((statfile = fopen(Buffer, "r")) == NULL) 111 fprintf(stderr, "Warning: %s not found.\n", Buffer); 112 else { 113 fscanf(statfile, "%*s %u", &applied); 114 fclose(statfile); 115 } 116 117 if(!argc) 118 stat |= Proc("-", applied); 119 120 while(argc-- && stat == Exit_Done) { 121 stat |= Proc(*argv++, applied); 122 stat &= ~Exit_Version; 123 } 124 125 if(stat == Exit_Done) 126 stat = Exit_OK; 127 128 if(Verbose) 129 fprintf(stderr,"Exit(%d)\n",stat); 130 return stat; 131} 132 133int 134Proc(char *filename, unsigned applied) 135{ 136 FILE *f; 137 int i; 138 char *p = strrchr(filename,'.'); 139 140 if(!strcmp(filename,"-")) { 141 p = 0; 142 f = stdin; 143 } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) { 144 p = alloca(20 + strlen(filename)); 145 strcpy(p,"gunzip < "); 146 strcat(p,filename); 147 f = popen(p,"r"); 148 if(!f) { perror(p); return Exit_Garbage; } 149 } else { 150 p = 0; 151 f = fopen(filename,"r"); 152 } 153 if(!f) { 154 perror(filename); 155 return Exit_Garbage; 156 } 157 158 if(Verbose > 1) 159 fprintf(stderr,"Working on <%s>\n",filename); 160 161 Delete(FileName); 162 FileName = String(filename); 163 164 /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */ 165 if(!p && -1 == fseek(f,0,SEEK_END)) { 166 char *fn = tempnam(TmpDir,"CTMclient"); 167 FILE *f2 = fopen(fn,"w+"); 168 int i; 169 170 if(!f2) { 171 perror(fn); 172 fclose(f); 173 return Exit_Broke; 174 } 175 unlink(fn); 176 fprintf(stderr,"Writing tmp-file \"%s\"\n",fn); 177 while(EOF != (i=getc(f))) 178 if(EOF == putc(i,f2)) { 179 fclose(f2); 180 return Exit_Broke; 181 } 182 fclose(f); 183 f = f2; 184 } 185 186 if(!p) 187 rewind(f); 188 189 if((i=Pass1(f, applied))) 190 goto exit_and_close; 191 192 if(!p) { 193 rewind(f); 194 } else { 195 pclose(f); 196 f = popen(p,"r"); 197 if(!f) { perror(p); return Exit_Broke; } 198 } 199 200 i=Pass2(f); 201 202 if(!p) { 203 rewind(f); 204 } else { 205 pclose(f); 206 f = popen(p,"r"); 207 if(!f) { perror(p); return Exit_Broke; } 208 } 209 210 if(i) { 211 if((!Force) || (i & ~Exit_Forcible)) 212 goto exit_and_close; 213 } 214 215 if(CheckIt) { 216 fprintf(stderr,"All checks out ok.\n"); 217 i = Exit_Done; 218 goto exit_and_close; 219 } 220 221 i=Pass3(f); 222 223exit_and_close: 224 if(!p) 225 fclose(f); 226 else 227 pclose(f); 228 229 if(i) 230 return i; 231 232 fprintf(stderr,"All done ok\n"); 233 return Exit_Done; 234} 235