]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/ctm/ctm/ctm_pass3.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / ctm / ctm / ctm_pass3.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> 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  * $FreeBSD$
10  *
11  */
12
13 #include "ctm.h"
14 #define BADREAD 32
15
16 /*---------------------------------------------------------------------------*/
17 /* Pass3 -- Validate the incoming CTM-file.
18  */
19
20 int
21 settime(const char *name, const struct timeval *times)
22 {
23         if (SetTime)
24             if (utimes(name,times)) {
25                 warn("utimes(): %s", name);
26                 return -1;
27             }
28         return 0;
29 }
30
31 int
32 Pass3(FILE *fd)
33 {
34     u_char *p,*q,buf[BUFSIZ];
35     MD5_CTX ctx;
36     int i,j,sep,cnt;
37     u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
38     struct CTM_Syntax *sp;
39     FILE *ed=0;
40     struct stat st;
41     char md5_1[33];
42     int match=0;
43     struct timeval times[2];
44     struct CTM_Filter *filter = NULL;
45     if(Verbose>3)
46         printf("Pass3 -- Applying the CTM-patch\n");
47     MD5Init (&ctx);
48
49     GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
50     GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
51     GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
52     GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
53     GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
54     GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
55
56     /*
57      * This would be cleaner if mktime() worked in UTC rather than
58      * local time.
59      */
60     if (SetTime) {
61         struct tm tm;
62         char *tz;
63         char buf[5];
64         int i;
65
66 #define SUBSTR(off,len) strncpy(buf, &TimeStamp[off], len), buf[len] = '\0'
67 #define WRONGDATE { fprintf(stderr, " %s failed date validation\n",\
68         TimeStamp); WRONG}
69
70         if (strlen(TimeStamp) != 15 || TimeStamp[14] != 'Z') WRONGDATE
71         for (i = 0; i < 14; i++)
72             if (!isdigit(TimeStamp[i])) WRONGDATE
73
74         tz = getenv("TZ");
75         if (setenv("TZ", "UTC", 1) < 0) WRONG
76         tzset();
77
78         tm.tm_isdst = tm.tm_gmtoff = 0;
79
80         SUBSTR(0, 4);
81         tm.tm_year = atoi(buf) - 1900;
82         SUBSTR(4, 2);
83         tm.tm_mon = atoi(buf) - 1;
84         if (tm.tm_mon < 0 || tm.tm_mon > 11) WRONGDATE
85         SUBSTR(6, 2);
86         tm.tm_mday = atoi(buf);
87         if (tm.tm_mday < 1 || tm.tm_mday > 31) WRONG;
88         SUBSTR(8, 2);
89         tm.tm_hour = atoi(buf);
90         if (tm.tm_hour > 24) WRONGDATE
91         SUBSTR(10, 2);
92         tm.tm_min = atoi(buf);
93         if (tm.tm_min > 59) WRONGDATE
94         SUBSTR(12, 2);
95         tm.tm_sec = atoi(buf);
96         if (tm.tm_min > 62) WRONGDATE   /* allow leap seconds */
97     
98         times[0].tv_sec = times[1].tv_sec = mktime(&tm);
99         if (times[0].tv_sec == -1) WRONGDATE
100         times[0].tv_usec = times[1].tv_usec = 0;
101
102         if (tz) {
103             if (setenv("TZ", tz, 1) < 0) WRONGDATE
104          } else {
105             unsetenv("TZ");
106         }
107     }
108
109     for(;;) {
110         Delete(md5);
111         Delete(uid);
112         Delete(gid);
113         Delete(mode);
114         Delete(md5before);
115         Delete(trash);
116         Delete(name);
117         cnt = -1;
118
119         GETFIELD(p,' ');
120
121         if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
122
123         if(!strcmp(p+3,"_END"))
124             break;
125
126         for(sp=Syntax;sp->Key;sp++)
127             if(!strcmp(p+3,sp->Key))
128                 goto found;
129         WRONG
130     found:
131         for(i=0;(j = sp->List[i]);i++) {
132             if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
133                 sep = ' ';
134             else
135                 sep = '\n';
136
137             switch (j & CTM_F_MASK) {
138                 case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
139                 case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
140                 case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
141                 case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
142                 case CTM_F_MD5:
143                     if(j & CTM_Q_MD5_Before)
144                         GETFIELDCOPY(md5before,sep);
145                     else
146                         GETFIELDCOPY(md5,sep);
147                     break;
148                 case CTM_F_Count: GETBYTECNT(cnt,sep); break;
149                 case CTM_F_Bytes: GETDATA(trash,cnt); break;
150                 default: WRONG
151                 }
152             }
153         /* XXX This should go away.  Disallow trailing '/' */
154         j = strlen(name)-1;
155         if(name[j] == '/') name[j] = '\0';
156
157         /*
158          * If a filter list is specified, run thru the filter list and
159          * match `name' against filters.  If the name matches, set the
160          * required action to that specified in the filter.
161          * The default action if no filterlist is given is to match
162          * everything.  
163          */
164
165         match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
166         for (filter = FilterList; filter; filter = filter->Next) {
167             if (0 == regexec(&filter->CompiledRegex, name,
168                 0, 0, 0)) {
169                 match = filter->Action;
170             }
171         }
172
173         if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
174                 continue;
175
176         if (Verbose > 0)
177                 fprintf(stderr,"> %s %s\n",sp->Key,name);
178         if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
179             i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
180             if(i < 0) {
181                 warn("%s", name);
182                 WRONG
183             }
184             if(cnt != write(i,trash,cnt)) {
185                 warn("%s", name);
186                 WRONG
187             }
188             close(i);
189             if(strcmp(md5,MD5File(name,md5_1))) {
190                 fprintf(stderr,"  %s %s MD5 didn't come out right\n",
191                    sp->Key,name);
192                 WRONG
193             }
194             if (settime(name,times)) WRONG
195             continue;
196         }
197         if(!strcmp(sp->Key,"FE")) {
198             ed = popen("ed","w");
199             if(!ed) {
200                 WRONG
201             }
202             fprintf(ed,"e %s\n",name);
203             if(cnt != fwrite(trash,1,cnt,ed)) {
204                 warn("%s", name);
205                 pclose(ed);
206                 WRONG
207             }
208             fprintf(ed,"w %s\n",name);
209             if(pclose(ed)) {
210                 warn("ed");
211                 WRONG
212             }
213             if(strcmp(md5,MD5File(name,md5_1))) {
214                 fprintf(stderr,"  %s %s MD5 didn't come out right\n",
215                    sp->Key,name);
216                 WRONG
217             }
218             if (settime(name,times)) WRONG
219             continue;
220         }
221         if(!strcmp(sp->Key,"FN")) {
222             strcpy(buf,name);
223             strcat(buf,TMPSUFF);
224             i = ctm_edit(trash,cnt,name,buf);
225             if(i) {
226                 fprintf(stderr," %s %s Edit failed with code %d.\n",
227                     sp->Key,name,i);
228                 WRONG
229             }
230             if(strcmp(md5,MD5File(buf,md5_1))) {
231                 fprintf(stderr," %s %s Edit failed MD5 check.\n",
232                     sp->Key,name);
233                 WRONG
234             }
235             if (rename(buf,name) == -1)
236                 WRONG
237             if (settime(name,times)) WRONG
238             continue;
239         }
240         if(!strcmp(sp->Key,"DM")) {
241             if(0 > mkdir(name,0777)) {
242                 sprintf(buf,"mkdir -p %s",name);
243                 system(buf);
244             }
245             if(0 > stat(name,&st) || ((st.st_mode & S_IFMT) != S_IFDIR)) {
246                 fprintf(stderr,"<%s> mkdir failed\n",name);
247                 WRONG
248             }
249             if (settime(name,times)) WRONG
250             continue;
251         }
252         if(!strcmp(sp->Key,"FR")) {
253             if (KeepIt) { 
254                 if (Verbose > 1) 
255                         printf("<%s> not removed\n", name);
256             }
257             else if (0 != unlink(name)) {
258                 fprintf(stderr,"<%s> unlink failed\n",name);
259                 if (!Force)
260                     WRONG
261             }
262             continue;
263         }
264         if(!strcmp(sp->Key,"DR")) {
265             /*
266              * We cannot use rmdir() because we do not get the directories
267              * in '-depth' order (cvs-cur.0018.gz for examples)
268              */
269             if (KeepIt) {
270                 if (Verbose > 1) {
271                         printf("<%s> not removed\n", name);
272                 }
273             } else {
274                     sprintf(buf,"rm -rf %s",name);
275                     system(buf);
276             }
277             continue;
278         }
279         WRONG
280     }
281
282     Delete(md5);
283     Delete(uid);
284     Delete(gid);
285     Delete(mode);
286     Delete(md5before);
287     Delete(trash);
288     Delete(name);
289
290     q = MD5End (&ctx,md5_1);
291     GETFIELD(p,'\n');
292     if(strcmp(q,p)) WRONG
293     if (-1 != getc(fd)) WRONG
294     return 0;
295 }