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