ctm.c revision 15456
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.12 1996/02/05 16:06:46 phk 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 * -u Set all file modification times to the timestamp 32 * -v Tell us more. 33 * -V <level> Tell us more level = number of -v 34 * 35 */ 36 37#define EXTERN /* */ 38#include "ctm.h" 39 40#define CTM_STATUS ".ctm_status" 41 42extern int Proc(char *, unsigned applied); 43 44int 45main(int argc, char **argv) 46{ 47 int stat=0; 48 int c; 49 extern int optopt,optind; 50 extern char * optarg; 51 unsigned applied = 0; 52 FILE *statfile; 53 u_char * basedir; 54 55 basedir = NULL; 56 Verbose = 1; 57 Paranoid = 1; 58 SetTime = 0; 59 setbuf(stderr,0); 60 setbuf(stdout,0); 61 62 while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:uV:v")) != -1) { 63 switch (c) { 64 case 'b': basedir = optarg; break; /* Base Directory */ 65 case 'c': CheckIt++; break; /* Only check it */ 66 case 'p': Paranoid--; break; /* Less Paranoid */ 67 case 'P': Paranoid++; break; /* More Paranoid */ 68 case 'q': Verbose--; break; /* Quiet */ 69 case 'v': Verbose++; break; /* Verbose */ 70 case 'T': TmpDir = optarg; break; 71 case 'F': Force = 1; break; 72 case 'u': SetTime++; break; /* Set timestamp on files */ 73 case 'V': sscanf(optarg,"%d", &c); /* Verbose */ 74 Verbose += c; 75 break; 76 case ':': 77 fprintf(stderr,"Option '%c' requires an argument.\n",optopt); 78 stat++; 79 break; 80 case '?': 81 fprintf(stderr,"Option '%c' not supported.\n",optopt); 82 stat++; 83 break; 84 default: 85 fprintf(stderr,"Option '%c' not yet implemented.\n",optopt); 86 break; 87 } 88 } 89 90 if(stat) { 91 fprintf(stderr,"%d errors during option processing\n",stat); 92 return Exit_Pilot; 93 } 94 stat = Exit_Done; 95 argc -= optind; 96 argv += optind; 97 98 if (basedir == NULL) { 99 Buffer = (u_char *)Malloc(BUFSIZ + strlen(SUBSUFF) +1); 100 CatPtr = Buffer; 101 *Buffer = '\0'; 102 } else { 103 Buffer = (u_char *)Malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1); 104 strcpy(Buffer, basedir); 105 CatPtr = Buffer + strlen(basedir); 106 if (CatPtr[-1] != '/') { 107 strcat(Buffer, "/"); 108 CatPtr++; 109 } 110 } 111 strcat(Buffer, CTM_STATUS); 112 113 if((statfile = fopen(Buffer, "r")) == NULL) 114 fprintf(stderr, "Warning: %s not found.\n", Buffer); 115 else { 116 fscanf(statfile, "%*s %u", &applied); 117 fclose(statfile); 118 } 119 120 if(!argc) 121 stat |= Proc("-", applied); 122 123 while(argc-- && stat == Exit_Done) { 124 stat |= Proc(*argv++, applied); 125 stat &= ~Exit_Version; 126 } 127 128 if(stat == Exit_Done) 129 stat = Exit_OK; 130 131 if(Verbose) 132 fprintf(stderr,"Exit(%d)\n",stat); 133 return stat; 134} 135 136int 137Proc(char *filename, unsigned applied) 138{ 139 FILE *f; 140 int i; 141 char *p = strrchr(filename,'.'); 142 143 if(!strcmp(filename,"-")) { 144 p = 0; 145 f = stdin; 146 } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) { 147 p = alloca(20 + strlen(filename)); 148 strcpy(p,"gunzip < "); 149 strcat(p,filename); 150 f = popen(p,"r"); 151 if(!f) { perror(p); return Exit_Garbage; } 152 } else { 153 p = 0; 154 f = fopen(filename,"r"); 155 } 156 if(!f) { 157 perror(filename); 158 return Exit_Garbage; 159 } 160 161 if(Verbose > 1) 162 fprintf(stderr,"Working on <%s>\n",filename); 163 164 Delete(FileName); 165 FileName = String(filename); 166 167 /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */ 168 if(!p && -1 == fseek(f,0,SEEK_END)) { 169 char *fn = tempnam(TmpDir,"CTMclient"); 170 FILE *f2 = fopen(fn,"w+"); 171 int i; 172 173 if(!f2) { 174 perror(fn); 175 fclose(f); 176 return Exit_Broke; 177 } 178 unlink(fn); 179 fprintf(stderr,"Writing tmp-file \"%s\"\n",fn); 180 while(EOF != (i=getc(f))) 181 if(EOF == putc(i,f2)) { 182 fclose(f2); 183 return Exit_Broke; 184 } 185 fclose(f); 186 f = f2; 187 } 188 189 if(!p) 190 rewind(f); 191 192 if((i=Pass1(f, applied))) 193 goto exit_and_close; 194 195 if(!p) { 196 rewind(f); 197 } else { 198 pclose(f); 199 f = popen(p,"r"); 200 if(!f) { perror(p); return Exit_Broke; } 201 } 202 203 i=Pass2(f); 204 205 if(!p) { 206 rewind(f); 207 } else { 208 pclose(f); 209 f = popen(p,"r"); 210 if(!f) { perror(p); return Exit_Broke; } 211 } 212 213 if(i) { 214 if((!Force) || (i & ~Exit_Forcible)) 215 goto exit_and_close; 216 } 217 218 if(CheckIt) { 219 fprintf(stderr,"All checks out ok.\n"); 220 i = Exit_Done; 221 goto exit_and_close; 222 } 223 224 i=Pass3(f); 225 226exit_and_close: 227 if(!p) 228 fclose(f); 229 else 230 pclose(f); 231 232 if(i) 233 return i; 234 235 fprintf(stderr,"All done ok\n"); 236 return Exit_Done; 237} 238