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