]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/ctm/ctm/ctm_pass2.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / ctm / ctm / ctm_pass2.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 /* Pass2 -- Validate the incoming CTM-file.
18  */
19
20 int
21 Pass2(FILE *fd)
22 {
23     u_char *p,*q,*md5=0;
24     MD5_CTX ctx;
25     int i,j,sep,cnt,fdesc;
26     u_char *trash=0,*name=0;
27     struct CTM_Syntax *sp;
28     struct stat st;
29     int ret = 0;
30     int match = 0;
31     char md5_1[33];
32     struct CTM_Filter *filter;
33     FILE *ed = NULL;
34     static char *template = NULL;
35
36     if(Verbose>3)
37         printf("Pass2 -- Checking if CTM-patch will apply\n");
38     MD5Init (&ctx);
39
40     GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
41     GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
42     GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
43     /* XXX Lookup name in /etc/ctm,conf, read stuff */
44     GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
45     /* XXX Verify that this is the next patch to apply */
46     GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
47     GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
48     /* XXX drop or use ? */
49
50     for(;;) {
51         Delete(trash);
52         Delete(name);
53         Delete(md5);
54         cnt = -1;
55
56         /* if a filter list was specified, check file name against
57            the filters specified 
58            if no filter was given operate on all files. */
59         match = (FilterList ? 
60                     !(FilterList->Action) : CTM_FILTER_ENABLE);
61
62         GETFIELD(p,' ');
63
64         if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
65
66         if(!strcmp(p+3,"_END"))
67             break;
68
69         for(sp=Syntax;sp->Key;sp++)
70             if(!strcmp(p+3,sp->Key))
71                 goto found;
72         WRONG
73     found:
74         for(i=0;(j = sp->List[i]);i++) {
75             if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
76                 sep = ' ';
77             else
78                 sep = '\n';
79
80             switch (j & CTM_F_MASK) {
81                 case CTM_F_Name:
82                     GETNAMECOPY(name,sep,j,0);
83                     /* If `keep' was specified, we won't remove any files,
84                        so don't check if the file exists */
85                     if (KeepIt &&
86                         (!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
87                         match = CTM_FILTER_DISABLE;
88                         break;
89                     }
90
91                     for (filter = FilterList; filter; filter = filter->Next)                            if (0 == regexec(&filter->CompiledRegex, name,
92                                     0, 0, 0)) {
93                                     match = filter->Action;
94                             }
95
96                     if (CTM_FILTER_DISABLE == match)
97                             break;      /* should ignore this file */
98
99                     /* XXX Check DR DM rec's for parent-dir */
100                     if(j & CTM_Q_Name_New) {
101                         /* XXX Check DR FR rec's for item */
102                         if(-1 != stat(name,&st)) {
103                             fprintf(stderr,"  %s: %s exists.\n",
104                                 sp->Key,name);
105                             ret |= Exit_Forcible;
106                         }
107                         break;
108                     }
109                     if(-1 == stat(name,&st)) {
110                         fprintf(stderr,"  %s: %s doesn't exist.\n",
111                             sp->Key,name);
112                         if (sp->Key[1] == 'R')
113                             ret |= Exit_Forcible;
114                         else
115                             ret |= Exit_NotOK;
116                         break;
117                     }
118                     if (SetTime && getuid() && (getuid() != st.st_uid)) {
119                             fprintf(stderr,
120                                 "  %s: %s not mine, cannot set time.\n",
121                                 sp->Key,name);
122                             ret |= Exit_NotOK;
123                     }
124                     if (j & CTM_Q_Name_Dir) {
125                         if((st.st_mode & S_IFMT) != S_IFDIR) {
126                             fprintf(stderr,
127                                 "  %s: %s exist, but isn't dir.\n",
128                                 sp->Key,name);
129                             ret |= Exit_NotOK;
130                         }
131                         break;
132                     }
133                     if (j & CTM_Q_Name_File) {
134                         if((st.st_mode & S_IFMT) != S_IFREG) {
135                             fprintf(stderr,
136                                 "  %s: %s exist, but isn't file.\n",
137                                 sp->Key,name);
138                             ret |= Exit_NotOK;
139                         }
140                         break;
141                     }
142                     break;
143                 case CTM_F_Uid:
144                 case CTM_F_Gid:
145                 case CTM_F_Mode:
146                     GETFIELD(p,sep);
147                     break;
148                 case CTM_F_MD5:
149                     if(!name) WRONG
150                     if(j & CTM_Q_MD5_Before) {
151                         char *tmp;
152                         GETFIELD(p,sep);
153                         if(match && (st.st_mode & S_IFMT) == S_IFREG &&
154                           (tmp = MD5File(name,md5_1)) != NULL &&
155                           strcmp(tmp,p)) {
156                             fprintf(stderr,"  %s: %s md5 mismatch.\n",
157                                 sp->Key,name);
158                             GETFIELDCOPY(md5,sep);
159                             if(md5 != NULL && strcmp(tmp,md5) == 0) {
160                                 fprintf(stderr,"  %s: %s already applied.\n",
161                                         sp->Key,name);
162                                 match = CTM_FILTER_DISABLE;
163                             } else if(j & CTM_Q_MD5_Force) {
164                                 if(Force)
165                                     fprintf(stderr,"  Can and will force.\n");
166                                 else
167                                     fprintf(stderr,"  Could have forced.\n");
168                                 ret |= Exit_Forcible;
169                             } else {
170                                 ret |= Exit_NotOK;
171                             }
172                         }
173                         break;
174                     } else if(j & CTM_Q_MD5_After) {
175                         if(md5 == NULL) {
176                             GETFIELDCOPY(md5,sep);
177                         }
178                         break;
179                     }
180                     /* Unqualified MD5 */
181                     WRONG
182                     break;
183                 case CTM_F_Count:
184                     GETBYTECNT(cnt,sep);
185                     break;
186                 case CTM_F_Bytes:
187                     if(cnt < 0) WRONG
188                     GETDATA(trash,cnt);
189                     if (!match)
190                         break;
191                     if (!template) {
192                         if (asprintf(&template, "%s/CTMclientXXXXXX",
193                                 TmpDir) == -1) {
194                             fprintf(stderr, "  %s: malloc failed.\n",
195                                 sp->Key);
196                             ret |= Exit_Mess;
197                             return ret;
198                         }
199                     }
200                     if(!strcmp(sp->Key,"FN")) {
201                         if ((p = strdup(template)) == NULL) {
202                             fprintf(stderr, "  %s: malloc failed.\n",
203                                 sp->Key);
204                             ret |= Exit_Mess;
205                             return ret;
206                         }
207                         if ((fdesc = mkstemp(p)) == -1) {
208                             fprintf(stderr, "  %s: mkstemp failed.\n",
209                                 sp->Key);
210                             ret |= Exit_Mess;
211                             Free(p);
212                             return ret;
213                         }
214                         if (close(fdesc) == -1) {
215                             fprintf(stderr, "  %s: close failed.\n",
216                                 sp->Key);
217                             ret |= Exit_Mess;
218                             unlink(p);
219                             Free(p);
220                             return ret;
221                         }
222                         j = ctm_edit(trash,cnt,name,p);
223                         if(j) {
224                             fprintf(stderr,"  %s: %s edit returned %d.\n",
225                                 sp->Key,name,j);
226                             ret |= j;
227                             unlink(p);
228                             Free(p);
229                             return ret;
230                         } else if(strcmp(md5,MD5File(p,md5_1))) {
231                             fprintf(stderr,"  %s: %s edit fails.\n",
232                                 sp->Key,name);
233                             ret |= Exit_Mess;
234                             unlink(p);
235                             Free(p);
236                             return ret;
237                         }
238                         unlink(p);
239                         Free(p);
240                     } else if (!strcmp(sp->Key,"FE")) {
241                         if ((p = strdup(template)) == NULL) {
242                             fprintf(stderr, "  %s: malloc failed.\n",
243                                 sp->Key);
244                             ret |= Exit_Mess;
245                             return ret;
246                         }
247                         if ((fdesc = mkstemp(p)) == -1) {
248                             fprintf(stderr, "  %s: mkstemp failed.\n",
249                                 sp->Key);
250                             ret |= Exit_Mess;
251                             Free(p);
252                             return ret;
253                         }
254                         if (close(fdesc) == -1) {
255                             fprintf(stderr, "  %s: close failed.\n",
256                                 sp->Key);
257                             ret |= Exit_Mess;
258                             unlink(p);
259                             Free(p);
260                             return ret;
261                         }
262                         ed = popen("ed","w");
263                         if (!ed) {
264                             WRONG
265                         }
266                         fprintf(ed,"e %s\n", name);
267                         if (cnt != fwrite(trash,1,cnt,ed)) {
268                             warn("%s", name);
269                             pclose(ed);
270                             WRONG
271                         }
272                         fprintf(ed,"w %s\n",p);
273                         if (pclose(ed)) {
274                             warn("%s", p);
275                             WRONG
276                         }
277                         if(strcmp(md5,MD5File(p,md5_1))) {
278                             fprintf(stderr,"%s %s MD5 didn't come out right\n",
279                                 sp->Key, name);
280                             WRONG
281                         }
282                         unlink(p);
283                         Free(p);
284                     }
285
286                     break;
287                 default: WRONG
288             }
289         }
290     }
291
292     Delete(trash);
293     Delete(name);
294     Delete(md5);
295
296     q = MD5End (&ctx,md5_1);
297     GETFIELD(p,'\n');                   /* <MD5> */
298     if(strcmp(q,p)) WRONG
299     if (-1 != getc(fd)) WRONG
300     return ret;
301 }