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