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