ctm_pass2.c revision 56056
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: head/usr.sbin/ctm/ctm/ctm_pass2.c 56056 2000-01-15 19:45:18Z phk $ 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 GETFIELDCOPY(md5,sep); 158 if(md5 != NULL && strcmp(tmp,md5) == 0) { 159 fprintf(stderr," %s: %s already applied.\n", 160 sp->Key,name); 161 match = CTM_FILTER_DISABLE; 162 } else if(j & CTM_Q_MD5_Force) { 163 if(Force) 164 fprintf(stderr," Can and will force.\n"); 165 else 166 fprintf(stderr," Could have forced.\n"); 167 ret |= Exit_Forcible; 168 } else { 169 ret |= Exit_NotOK; 170 } 171 } 172 break; 173 } else if(j & CTM_Q_MD5_After) { 174 if(md5 == NULL) { 175 GETFIELDCOPY(md5,sep); 176 } 177 break; 178 } 179 /* Unqualified MD5 */ 180 WRONG 181 break; 182 case CTM_F_Count: 183 GETBYTECNT(cnt,sep); 184 break; 185 case CTM_F_Bytes: 186 if(cnt < 0) WRONG 187 GETDATA(trash,cnt); 188 if (!match) 189 break; 190 if(!strcmp(sp->Key,"FN")) { 191 p = tempnam(TmpDir,"CTMclient"); 192 j = ctm_edit(trash,cnt,name,p); 193 if(j) { 194 fprintf(stderr," %s: %s edit returned %d.\n", 195 sp->Key,name,j); 196 ret |= j; 197 unlink(p); 198 Free(p); 199 return ret; 200 } else if(strcmp(md5,MD5File(p,md5_1))) { 201 fprintf(stderr," %s: %s edit fails.\n", 202 sp->Key,name); 203 ret |= Exit_Mess; 204 unlink(p); 205 Free(p); 206 return ret; 207 } 208 unlink(p); 209 Free(p); 210 } else if (!strcmp(sp->Key,"FE")) { 211 p = tempnam(TmpDir,"CTMclient"); 212 ed = popen("ed","w"); 213 if (!ed) { 214 WRONG 215 } 216 fprintf(ed,"e %s\n", name); 217 if (cnt != fwrite(trash,1,cnt,ed)) { 218 warn("%s", name); 219 pclose(ed); 220 WRONG 221 } 222 fprintf(ed,"w %s\n",p); 223 if (pclose(ed)) { 224 warn("%s", p); 225 WRONG 226 } 227 if(strcmp(md5,MD5File(p,md5_1))) { 228 fprintf(stderr,"%s %s MD5 didn't come out right\n", 229 sp->Key, name); 230 WRONG 231 } 232 unlink(p); 233 Free(p); 234 } 235 236 break; 237 default: WRONG 238 } 239 } 240 } 241 242 Delete(trash); 243 Delete(name); 244 Delete(md5); 245 246 q = MD5End (&ctx,md5_1); 247 GETFIELD(p,'\n'); /* <MD5> */ 248 if(strcmp(q,p)) WRONG 249 if (-1 != getc(fd)) WRONG 250 return ret; 251} 252