ctm.c revision 2887
1/* $Id$
2 *
3 * ----------------------------------------------------------------------------
4 * "THE BEER-WARE LICENSE" (Revision 42):
5 * <phk@login.dkuug.dk> wrote this file.  As long as you retain this notice you
6 * can do whatever you want with this stuff. If we meet some day, and you think
7 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
8 * ----------------------------------------------------------------------------
9 *
10 * $Id$
11 *
12 * This is the client program of 'CTM'.  It will apply a CTM-patch to a
13 * collection of files.
14 *
15 * Options we'd like to see:
16 *
17 * -a 			Attempt best effort.
18 * -b <dir>		Base-dir
19 * -B <file>		Backup to tar-file.
20 * -c			Check it out, "ma non troppo"
21 * -d <int>		Debug TBD.
22 * -m <mail-addr>	Email me instead.
23 * -p			Less paranoid.
24 * -P			Paranoid.
25 * -q 			Be quiet.
26 * -r <name>		Reconstruct file.
27 * -R <file>		Read list of files to reconstruct.
28 * -T <tmpdir>.		Temporary files.
29 * -v 			Tell about each file.
30 *
31 * Exit-codes, bitmap, logical or of:
32 * 1	Couldn't do something we wanted to, not fatal.
33 * 2	Couldn't do something we wanted to, fatal.
34 * 4	Input file corrupt.
35 * 8	Cannot apply input file.
36 * 16   Corruption while applying input file.
37 *
38 */
39
40#define EXTERN /* */
41#include "ctm.h"
42
43extern int Proc(char *);
44
45int
46main(int argc, char **argv)
47{
48    int stat=0;
49    int i,j,c;
50    extern int optopt,optind;
51    extern char * optarg;
52
53    Verbose = 1;
54    Paranoid = 1;
55    setbuf(stderr,0);
56    setbuf(stdout,0);
57
58    while((c=getopt(argc,argv,"ab:B:cd:m:pPqr:R:T:Vv")) != -1) {
59	switch (c) {
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 ':':
66		fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
67		stat++;
68		break;
69	    case '?':
70		fprintf(stderr,"Option '%c' not supported.\n",optopt);
71		stat++;
72		break;
73	    default:
74		fprintf(stderr,"Option '%c' not yet implemented.\n",optopt);
75		break;
76	}
77    }
78
79    if(stat) {
80	fprintf(stderr,"%d errors during option processing\n",stat);
81	exit(1);
82    }
83    stat = 0;
84    argc -= optind;
85    argv += optind;
86
87    if(!argc)
88	stat |= Proc("-");
89
90    while(argc--)
91	stat |= Proc(*argv++);
92
93    return stat;
94}
95
96int
97Proc(char *filename)
98{
99    FILE *f;
100    int i;
101    char *p = strrchr(filename,'.');
102
103    if(!strcmp(filename,"-")) {
104	p = 0;
105	f = stdin;
106    } else if(!strcmp(p,".gz") || !strcmp(p,".Z")) {
107	p = Malloc(100);
108	strcpy(p,"gunzip < ");
109	strcat(p,filename);
110	f = popen(p,"r");
111    } else {
112	p = 0;
113	f = fopen(filename,"r");
114    }
115    if(!f) {
116	perror(filename);
117	return 1;
118    }
119
120    if(Verbose > 1)
121	fprintf(stderr,"Working on <%s>\n",filename);
122
123    if(FileName) Free(FileName);
124    FileName = String(filename);
125
126    /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
127    if(!p &&  -1 == fseek(f,0,SEEK_END)) {
128	char *fn = tempnam(NULL,"CMTclient");
129	FILE *f2 = fopen(fn,"w+");
130	int i;
131
132	if(!f2) {
133	    perror(fn);
134	    fclose(f);
135	    return 2;
136	}
137	unlink(fn);
138	fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
139	while(EOF != (i=getc(f)))
140	    putc(i,f2);
141	fclose(f);
142	f = f2;
143    }
144
145    if(!p)
146	rewind(f);
147    if((i=Pass1(f)))
148	return i;
149    if(!p) {
150        rewind(f);
151    } else {
152	pclose(f);
153	f = popen(p,"r");
154    }
155    if((i=Pass2(f)))
156	return i;
157    if(!p) {
158        rewind(f);
159    } else {
160	pclose(f);
161	f = popen(p,"r");
162    }
163    if((i=Pass3(f)))
164	return i;
165    if(!p) {
166        fclose(f);
167    } else {
168	pclose(f);
169    }
170    return 0;
171}
172