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