Play viking, get axe ... take axe to useless deadwood that has existed way
[dragonfly.git] / usr.sbin / ctm / ctm / ctm_pass1.c
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  * $FreeBSD: src/usr.sbin/ctm/ctm/ctm_pass1.c,v 1.16 1999/08/28 01:15:59 peter Exp $
10  * $DragonFly: src/usr.sbin/ctm/ctm/Attic/ctm_pass1.c,v 1.2 2003/06/17 04:29:53 dillon Exp $
11  *
12  */
13
14 #include "ctm.h"
15 #define BADREAD 1
16
17 /*---------------------------------------------------------------------------*/
18 /* Pass1 -- Validate the incoming CTM-file.
19  */
20
21 int
22 Pass1(FILE *fd, unsigned applied)
23 {
24     u_char *p,*q;
25     MD5_CTX ctx;
26     int i,j,sep,cnt;
27     u_char *md5=0,*name=0,*trash=0;
28     struct CTM_Syntax *sp;
29     int slashwarn=0, match=0, total_matches=0;
30     unsigned current;
31     char md5_1[33];
32
33     if(Verbose>3)
34         printf("Pass1 -- Checking integrity of incoming CTM-patch\n");
35     MD5Init (&ctx);
36
37     GETFIELD(p,' ');                            /* CTM_BEGIN */
38     if(strcmp(p,"CTM_BEGIN")) {
39         Fatal("Probably not a CTM-patch at all.");
40         if(Verbose>3)
41             fprintf(stderr,"Expected \"CTM_BEGIN\" got \"%s\".\n",p);
42         return 1;
43     }
44
45     GETFIELDCOPY(Version,' ');                          /* <Version> */
46     if(strcmp(Version,VERSION)) {
47         Fatal("CTM-patch is wrong version.");
48         if(Verbose>3)
49             fprintf(stderr,"Expected \"%s\" got \"%s\".\n",VERSION,p);
50         return 1;
51     }
52
53     GETFIELDCOPY(Name,' ');                             /* <Name> */
54     GETFIELDCOPY(Nbr,' ');                              /* <Nbr> */
55     GETFIELDCOPY(TimeStamp,' ');                        /* <TimeStamp> */
56     GETFIELDCOPY(Prefix,'\n');                          /* <Prefix> */
57
58     sscanf(Nbr, "%u", &current);
59     if (FilterList || ListIt)
60         current = 0;    /* ignore if -l or if filters are present */
61     if(current && current <= applied) {
62         if(Verbose > 0)
63             fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
64                     current);
65         return Exit_Version;
66     }
67
68     for(;;) {
69         Delete(md5);
70         Delete(name);
71         Delete(trash);
72         cnt = -1;
73         /* if a filter list is defined we assume that all pathnames require
74            an action opposite to that requested by the first filter in the
75            list.
76            If no filter is defined, all pathnames are assumed to match. */
77         match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
78
79         GETFIELD(p,' ');                        /* CTM_something */
80
81         if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') {
82             Fatal("Expected CTM keyword.");
83             fprintf(stderr,"Got [%s]\n",p);
84             return 1;
85         }
86
87         if(!strcmp(p+3,"_END"))
88             break;
89
90         for(sp=Syntax;sp->Key;sp++)
91             if(!strcmp(p+3,sp->Key))
92                 goto found;
93         Fatal("Expected CTM keyword.");
94         fprintf(stderr,"Got [%s]\n",p);
95         return 1;
96     found:
97         if(Verbose > 5)
98             fprintf(stderr,"%s ",sp->Key);
99         for(i=0;(j = sp->List[i]);i++) {
100             if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
101                 sep = ' ';
102             else
103                 sep = '\n';
104
105             if(Verbose > 5)
106                 fprintf(stderr," %x(%d)",sp->List[i],sep);
107
108             switch (j & CTM_F_MASK) {
109                 case CTM_F_Name: /* XXX check for garbage and .. */
110                     GETFIELDCOPY(name,sep);
111                     j = strlen(name);
112                     if(name[j-1] == '/' && !slashwarn)  {
113                         fprintf(stderr,"Warning: contains trailing slash\n");
114                         slashwarn++;
115                     }
116                     if (name[0] == '/') {
117                         Fatal("Absolute paths are illegal.");
118                         return Exit_Mess;
119                     }
120                     q = name;
121                     for (;;) {
122                         if (q[0] == '.' && q[1] == '.')
123                             if (q[2] == '/' || q[2] == '\0') {
124                                 Fatal("Paths containing '..' are illegal.");
125                                 return Exit_Mess;
126                             }
127                         if ((q = strchr(q, '/')) == NULL)
128                             break;
129                         q++;
130                     }
131
132                     /* if we have been asked to `keep' files then skip
133                        removes; i.e. we don't match these entries at
134                        all. */
135                     if (KeepIt &&
136                         (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
137                         match = CTM_FILTER_DISABLE;
138                         break;
139                     }
140
141                     /* If filter expression have been defined, match the
142                        path name against the expression list.  */
143                     
144                     if (FilterList) {
145                         struct CTM_Filter *filter;
146
147                         for (filter = FilterList; filter; 
148                              filter = filter->Next) {
149                                 if (0 == regexec(&filter->CompiledRegex, name,
150                                         0, 0, 0))
151                                         /* if the name matches, adopt the 
152                                            action */
153                                         match = filter->Action;
154                         }
155                     }
156
157                     /* Add up the total number of matches */
158                     total_matches += match;
159                     break;
160                 case CTM_F_Uid:
161                     GETFIELD(p,sep);
162                     while(*p) {
163                         if(!isdigit(*p)) {
164                             Fatal("Non-digit in uid.");
165                             return 32;
166                         }
167                         p++;
168                     }
169                     break;
170                 case CTM_F_Gid:
171                     GETFIELD(p,sep);
172                     while(*p) {
173                         if(!isdigit(*p)) {
174                             Fatal("Non-digit in gid.");
175                             return 32;
176                         }
177                         p++;
178                     }
179                     break;
180                 case CTM_F_Mode:
181                     GETFIELD(p,sep);
182                     while(*p) {
183                         if(!isdigit(*p)) {
184                             Fatal("Non-digit in mode.");
185                             return 32;
186                         }
187                         p++;
188                     }
189                     break;
190                 case CTM_F_MD5:
191                     if(j & CTM_Q_MD5_Chunk) {
192                         GETFIELDCOPY(md5,sep);  /* XXX check for garbage */
193                     } else if(j & CTM_Q_MD5_Before) {
194                         GETFIELD(p,sep);  /* XXX check for garbage */
195                     } else if(j & CTM_Q_MD5_After) {
196                         GETFIELD(p,sep);  /* XXX check for garbage */
197                     } else {
198                         fprintf(stderr,"List = 0x%x\n",j);
199                         Fatal("Unqualified MD5.");
200                         return 32;
201                     }
202                     break;
203                 case CTM_F_Count:
204                     GETBYTECNT(cnt,sep);
205                     break;
206                 case CTM_F_Bytes:
207                     if(cnt < 0) WRONG
208                     GETDATA(trash,cnt);
209                     p = MD5Data(trash,cnt,md5_1);
210                     if(md5 && strcmp(md5,p)) {
211                         Fatal("Internal MD5 failed.");
212                         return Exit_Garbage;
213                 default:
214                         fprintf(stderr,"List = 0x%x\n",j);
215                         Fatal("List had garbage.");
216                         return Exit_Garbage;
217                     }
218             }
219         }
220         if(Verbose > 5)
221             putc('\n',stderr);
222         if(ListIt && match)
223             printf("> %s %s\n", sp->Key, name);
224     }
225
226     Delete(md5);
227     Delete(name);
228     Delete(trash);
229
230     q = MD5End (&ctx,md5_1);
231     if(Verbose > 2)
232         printf("Expecting Global MD5 <%s>\n",q);
233     GETFIELD(p,'\n');                   /* <MD5> */
234     if(Verbose > 2)
235         printf("Reference Global MD5 <%s>\n",p);
236     if(strcmp(q,p)) {
237         Fatal("MD5 sum doesn't match.");
238         fprintf(stderr,"\tI have:<%s>\n",q);
239         fprintf(stderr,"\tShould have been:<%s>\n",p);
240         return Exit_Garbage;
241     }
242     if (-1 != getc(fd)) {
243         if(!Force) {
244             Fatal("Trailing junk in CTM-file.  Can Force with -F.");
245             return 16;
246         }
247     }
248     if ((Verbose > 1) && (0 == total_matches))
249         printf("No matches in \"%s\"\n", FileName);
250     return (total_matches ? Exit_OK : Exit_NoMatch);
251 }