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 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/usr.sbin/ctm/ctm/ctm.c,v 1.19.2.1 2000/08/23 08:51:25 kris Exp $
10 * $DragonFly: src/usr.sbin/ctm/ctm/Attic/ctm.c,v 1.2 2003/06/17 04:29:53 dillon Exp $
12 * This is the client program of 'CTM'. It will apply a CTM-patch to a
13 * collection of files.
15 * Options we'd like to see:
17 * -a Attempt best effort.
19 * -m <mail-addr> Email me instead.
20 * -r <name> Reconstruct file.
21 * -R <file> Read list of files to reconstruct.
25 * -B <file> Backup to tar-file.
26 * -t Tar command (default as in TARCMD).
27 * -c Check it out, don't do anything.
30 * -T <tmpdir>. Temporary files.
31 * -u Set all file modification times to the timestamp
33 * -V <level> Tell us more level = number of -v
34 * -k Keep files and directories that would have been removed.
37 * Options we don't actually use:
46 #define CTM_STATUS ".ctm_status"
48 extern int Proc(char *, unsigned applied);
51 main(int argc, char **argv)
57 struct CTM_Filter *nfilter = NULL; /* new filter */
68 LastFilter = FilterList = NULL;
69 TmpDir = getenv("TMPDIR");
71 TmpDir = strdup(_PATH_TMP);
75 while((c=getopt(argc,argv,"ab:B:cd:e:Fklm:pPqr:R:t:T:uV:vx:")) != -1) {
77 case 'b': basedir = optarg; break; /* Base Directory */
78 case 'B': BackupFile = optarg; break;
79 case 'c': CheckIt++; break; /* Only check it */
80 case 'F': Force = 1; break;
81 case 'k': KeepIt++; break; /* Don't do removes */
82 case 'l': ListIt++; break; /* Only list actions and files */
83 case 'p': Paranoid--; break; /* Less Paranoid */
84 case 'P': Paranoid++; break; /* More Paranoid */
85 case 'q': Verbose--; break; /* Quiet */
86 case 't': TarCmd = optarg; break; /* archiver command */
87 case 'T': TmpDir = optarg; break; /* set temporary directory */
88 case 'u': SetTime++; break; /* Set timestamp on files */
89 case 'v': Verbose++; break; /* Verbose */
90 case 'V': sscanf(optarg,"%d", &c); /* Verbose */
93 case 'e': /* filter expressions */
95 if (NULL == (nfilter = Malloc(sizeof(struct CTM_Filter)))) {
96 warnx("out of memory for expressions: \"%s\"", optarg);
101 (void) memset(nfilter, 0, sizeof(struct CTM_Filter));
104 regcomp(&nfilter->CompiledRegex, optarg, REG_NOSUB))) {
108 regerror(err, &nfilter->CompiledRegex, errmsg,
110 warnx("regular expression: \"%s\"", errmsg);
115 /* note whether the filter enables or disables on match */
117 (('e' == c) ? CTM_FILTER_ENABLE : CTM_FILTER_DISABLE);
119 /* link in the expression into the list */
120 nfilter->Next = NULL;
121 if (NULL == FilterList) {
122 LastFilter = FilterList = nfilter; /* init head and tail */
123 } else { /* place at tail */
124 LastFilter->Next = nfilter;
125 LastFilter = nfilter;
129 warnx("option '%c' requires an argument",optopt);
133 warnx("option '%c' not supported",optopt);
137 warnx("option '%c' not yet implemented",optopt);
143 warnx("%d errors during option processing",stat);
150 if (basedir == NULL) {
151 Buffer = (u_char *)Malloc(BUFSIZ + strlen(SUBSUFF) +1);
155 Buffer = (u_char *)Malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1);
156 strcpy(Buffer, basedir);
157 CatPtr = Buffer + strlen(basedir);
158 if (CatPtr[-1] != '/') {
163 strcat(Buffer, CTM_STATUS);
168 if((statfile = fopen(Buffer, "r")) == NULL) {
170 warnx("warning: %s not found", Buffer);
172 fscanf(statfile, "%*s %u", &applied);
177 stat |= Proc("-", applied);
179 while(argc-- && stat == Exit_Done) {
180 stat |= Proc(*argv++, applied);
181 stat &= ~(Exit_Version | Exit_NoMatch);
184 if(stat == Exit_Done)
188 warnx("exit(%d)",stat);
191 for (nfilter = FilterList; nfilter; ) {
192 struct CTM_Filter *tmp = nfilter->Next;
200 Proc(char *filename, unsigned applied)
204 char *p = strrchr(filename,'.');
206 if(!strcmp(filename,"-")) {
209 } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) {
210 p = alloca(20 + strlen(filename));
211 strcpy(p,"gunzip < ");
214 if(!f) { warn("%s", p); return Exit_Garbage; }
217 f = fopen(filename,"r");
220 warn("%s", filename);
225 fprintf(stderr,"Working on <%s>\n",filename);
228 FileName = String(filename);
230 /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
231 if(!p && -1 == fseek(f,0,SEEK_END)) {
236 if (asprintf(&fn, "%s/CTMclient.XXXXXXXXXX", TmpDir) == -1) {
237 fprintf(stderr, "Cannot allocate memory\n");
241 if ((fd = mkstemp(fn)) == -1 || (f2 = fdopen(fd, "w+")) == NULL) {
251 fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
253 while(EOF != (i=getc(f)))
254 if(EOF == putc(i,f2)) {
265 if((i=Pass1(f, applied)))
278 if(!f) { warn("%s", p); return Exit_Broke; }
288 if(!f) { warn("%s", p); return Exit_Broke; }
292 if((!Force) || (i & ~Exit_Forcible))
298 fprintf(stderr,"All checks out ok.\n");
303 /* backup files if requested */
313 if(!f) { warn("%s", p); return Exit_Broke; }
329 fprintf(stderr,"All done ok\n");