ctm.c revision 7168
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.8 1995/03/04 20:36:45 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 <dir>		Base-dir
18 * -B <file>		Backup to tar-file.
19 * -d <int>		Debug TBD.
20 * -m <mail-addr>	Email me instead.
21 * -r <name>		Reconstruct file.
22 * -R <file>		Read list of files to reconstruct.
23 *
24 * Options we have:
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 *
33 */
34
35#define EXTERN /* */
36#include "ctm.h"
37
38#define CTM_STATUS ".ctm_status"
39
40extern int Proc(char *, unsigned applied);
41
42int
43main(int argc, char **argv)
44{
45    int stat=0;
46    int c;
47    extern int optopt,optind;
48    extern char * optarg;
49    FILE *statfile;
50    unsigned applied = 0;
51
52    Verbose = 1;
53    Paranoid = 1;
54    setbuf(stderr,0);
55    setbuf(stdout,0);
56
57    while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:Vv")) != -1) {
58	switch (c) {
59	    case 'c': CheckIt++;	break; /* Only check it */
60	    case 'p': Paranoid--;	break; /* Less Paranoid */
61	    case 'P': Paranoid++;	break; /* More Paranoid */
62	    case 'q': Verbose--;	break; /* Quiet */
63	    case 'v': Verbose++;	break; /* Verbose */
64	    case 'T': TmpDir = optarg;	break;
65	    case 'F': Force = 1;	break;
66	    case ':':
67		fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
68		stat++;
69		break;
70	    case '?':
71		fprintf(stderr,"Option '%c' not supported.\n",optopt);
72		stat++;
73		break;
74	    default:
75		fprintf(stderr,"Option '%c' not yet implemented.\n",optopt);
76		break;
77	}
78    }
79
80    if(stat) {
81	fprintf(stderr,"%d errors during option processing\n",stat);
82	return Exit_Pilot;
83    }
84    stat = Exit_Done;
85    argc -= optind;
86    argv += optind;
87
88    if((statfile = fopen(CTM_STATUS, "r")) == NULL)
89	fprintf(stderr, "Warning: " CTM_STATUS " not found.\n");
90    else {
91	fscanf(statfile, "%*s %u", &applied);
92	fclose(statfile);
93    }
94
95    if(!argc)
96	stat |= Proc("-", applied);
97
98    while(argc-- && stat == Exit_Done) {
99	stat |= Proc(*argv++, applied);
100	stat &= ~Exit_Version;
101    }
102
103    if(stat == Exit_Done)
104	stat = Exit_OK;
105
106    if(Verbose)
107	fprintf(stderr,"Exit(%d)\n",stat);
108    return stat;
109}
110
111int
112Proc(char *filename, unsigned applied)
113{
114    FILE *f;
115    int i;
116    char *p = strrchr(filename,'.');
117
118    if(!strcmp(filename,"-")) {
119	p = 0;
120	f = stdin;
121    } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) {
122	p = Malloc(100);
123	strcpy(p,"gunzip < ");
124	strcat(p,filename);
125	f = popen(p,"r");
126	if(!f) { perror(p); return Exit_Garbage; }
127    } else {
128	p = 0;
129	f = fopen(filename,"r");
130    }
131    if(!f) {
132	perror(filename);
133	return Exit_Garbage;
134    }
135
136    if(Verbose > 1)
137	fprintf(stderr,"Working on <%s>\n",filename);
138
139    if(FileName) Free(FileName);
140    FileName = String(filename);
141
142    /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
143    if(!p &&  -1 == fseek(f,0,SEEK_END)) {
144	char *fn = tempnam(TmpDir,"CMTclient");
145	FILE *f2 = fopen(fn,"w+");
146	int i;
147
148	if(!f2) {
149	    perror(fn);
150	    fclose(f);
151	    return Exit_Broke;
152	}
153	unlink(fn);
154	fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
155	while(EOF != (i=getc(f)))
156	    if(EOF == putc(i,f2)) {
157		fclose(f2);
158		return Exit_Broke;
159	    }
160	fclose(f);
161	f = f2;
162    }
163
164    if(!p)
165	rewind(f);
166
167    if((i=Pass1(f, applied)))
168	goto exit_and_close;
169
170    if(!p) {
171        rewind(f);
172    } else {
173	pclose(f);
174	f = popen(p,"r");
175	if(!f) { perror(p); return Exit_Broke; }
176    }
177
178    i=Pass2(f);
179
180    if(!p) {
181        rewind(f);
182    } else {
183	pclose(f);
184	f = popen(p,"r");
185	if(!f) { perror(p); return Exit_Broke; }
186    }
187
188    if(i) {
189	if((!Force) || (i & ~Exit_Forcible))
190	    goto exit_and_close;
191    }
192
193    if(CheckIt) {
194        fprintf(stderr,"All checks out ok.\n");
195	i = Exit_Done;
196	goto exit_and_close;
197    }
198
199    i=Pass3(f);
200
201exit_and_close:
202    if(!p) {
203        fclose(f);
204    } else {
205	pclose(f);
206	Free(p);
207    }
208    if(i)
209	return i;
210
211    fprintf(stderr,"All done ok\n");
212    return Exit_Done;
213}
214