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