vhashify-init.hc (9279B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; version 2 of the License. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "pathconfig.h" 19 #include "lib_internal/util-dotfile.h" 20 21 #include <sys/param.h> 22 23 static UNUSED void 24 freeHashList(HashDirCollection *hash_vec) 25 { 26 for (struct HashDirInfo *itm = Vector_begin(hash_vec); 27 itm!=Vector_end(hash_vec); 28 ++itm) { 29 free(const_cast(char *)(itm->path.d)); 30 } 31 32 Vector_free(hash_vec); 33 } 34 35 static size_t 36 initHashList(HashDirCollection *hash_vec, char const *hashdir) 37 { 38 int cur_dir = Eopen(".", O_RDONLY|O_DIRECTORY, 0); 39 Echdir(hashdir); 40 41 DIR *d = Eopendir("."); 42 struct dirent *ep; 43 size_t l = strlen(hashdir); 44 size_t res = 0; 45 46 while ((ep=readdir(d)) != 0) { 47 struct stat st; 48 49 if (isDotfile(ep->d_name) || 50 stat(ep->d_name, &st)==-1 || !S_ISDIR(st.st_mode)) 51 continue; 52 53 if (HashDirInfo_findDevice(hash_vec, st.st_dev)!=0) { 54 WRITE_MSG(2, "Duplicate hash-dir entry '"); 55 WRITE_STR(2, ep->d_name); 56 WRITE_MSG(2, "' found\n"); 57 continue; 58 } 59 60 char *full_path = Emalloc(l + strlen(ep->d_name) + 3); 61 char *ptr = full_path + l; 62 63 memcpy(full_path, hashdir, l); 64 while (ptr>full_path && ptr[-1]=='/') --ptr; 65 *ptr++ = '/'; 66 strcpy(ptr, ep->d_name); 67 strcat(ptr, "/"); // append a trailing '/' 68 69 70 struct HashDirInfo tmp = { 71 .device = st.st_dev, 72 .path = { full_path, strlen(full_path) }, 73 }; 74 75 res = MAX(res, tmp.path.l); 76 77 memcpy(Vector_pushback(hash_vec), &tmp, sizeof tmp); 78 } 79 80 if (Vector_count(hash_vec)==0) { 81 WRITE_MSG(2, "Could not find a place for the hashified files at '"); 82 WRITE_STR(2, hashdir); 83 WRITE_MSG(2, "'.\n"); 84 exit(wrapper_exit_code); 85 } 86 87 Eclosedir(d); 88 Efchdir(cur_dir); 89 Eclose(cur_dir); 90 91 return res; 92 } 93 94 static bool 95 initHashMethod(struct HashDirConfiguration *conf, char const *filename) 96 { 97 int fd = open(filename, O_RDONLY); 98 if (fd==-1 && conf->method==0) 99 conf->method = ensc_crypto_hash_get_default(); 100 101 if (fd==-1) { 102 char const *hash_name; 103 assert(conf->method!=0); 104 if (conf->method==0) return false; 105 if (global_args->dry_run) return true; // do not create the file 106 107 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644); 108 109 hash_name = ensc_crypto_hash_get_name(conf->method); 110 TEMP_FAILURE_RETRY(write(fd, hash_name, strlen(hash_name))); 111 TEMP_FAILURE_RETRY(write(fd, "\n", 1)); 112 } 113 else { 114 off_t s = Elseek(fd, 0, SEEK_END); 115 char buf[s + 1]; 116 Elseek(fd, 0, SEEK_SET); 117 118 conf->method=0; 119 120 if (s>0 && read(fd, buf, s+1)==s) { 121 while (s>0 && (buf[s-1]=='\0' || buf[s-1]=='\n')) 122 --s; 123 buf[s] = '\0'; 124 125 conf->method = ensc_crypto_hash_find(buf); 126 if (conf->method==0) { 127 WRITE_MSG(2, "Can not find hash-function '"); 128 WRITE_STR(2, buf); 129 WRITE_MSG(2, "'\n"); 130 } 131 } 132 else 133 WRITE_MSG(2, "Can not read configuration file for hash-method\n"); 134 } 135 136 if (conf->method!=0 && ensc_crypto_hash_get_digestsize(conf->method)*8>HASH_MAXBITS) { 137 WRITE_MSG(2, "Wow... what an huge hash-function. I can not handle so much bits; giving up...\n"); 138 conf->method=0; 139 } 140 141 Eclose(fd); 142 return conf->method!=0; 143 } 144 145 static bool 146 initHashBlocks(struct HashDirConfiguration *conf, char const *filename) 147 { 148 int fd = open(filename, O_RDONLY); 149 150 if (fd==-1) { 151 char str[sizeof("all,start,middle,end,")] = { [0] = '\0' }; 152 153 if (global_args->dry_run) return true; // do not create the file 154 155 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644); 156 157 if (conf->blocks== hshALL) strcat(str, "all\n"); 158 if (conf->blocks & hshSTART) strcat(str, "start\n"); 159 if (conf->blocks & hshMIDDLE) strcat(str, "middle\n"); 160 if (conf->blocks & hshEND) strcat(str, "end\n"); 161 162 EwriteAll(fd, str, strlen(str)); 163 } 164 else { 165 off_t s = Elseek(fd, 0, SEEK_END); 166 char buf[s + 1]; 167 Elseek(fd, 0, SEEK_SET); 168 169 conf->blocks = hshINVALID; 170 171 if (s>0 && read(fd, buf, s+1)==s) { 172 char *tok = buf; 173 char *sep = "\n,\t "; 174 175 buf[s] = '\0'; 176 conf->blocks = hshALL; 177 178 do { 179 char *ptr = strsep(&tok, sep); 180 181 if (*ptr=='#') { sep = "\n"; continue; } 182 sep = "\n,\t "; 183 if (*ptr=='\0') continue; 184 185 if (strcasecmp(ptr, "all") ==0) conf->blocks = hshALL; 186 else { 187 if (conf->blocks==hshINVALID) conf->blocks = 0; 188 189 else if (strcasecmp(ptr, "start") ==0) conf->blocks |= hshSTART; 190 else if (strcasecmp(ptr, "middle")==0) conf->blocks |= hshMIDDLE; 191 else if (strcasecmp(ptr, "end") ==0) conf->blocks |= hshEND; 192 else { 193 WRITE_MSG(2, "Invalid block descriptor '"); 194 WRITE_STR(2, ptr); 195 WRITE_MSG(2, "'\n"); 196 conf->blocks = hshINVALID; 197 tok = 0; 198 } 199 } 200 } while (tok!=0); 201 } 202 else 203 WRITE_MSG(2, "Can not read configuration file for hash-blocks\n"); 204 } 205 206 Eclose(fd); 207 return conf->blocks!=hshINVALID; 208 } 209 210 static bool 211 initHashBlockSize(struct HashDirConfiguration *conf, char const *filename) 212 { 213 if (conf->blocks==hshALL) return true; 214 215 int fd = open(filename, O_RDONLY); 216 if (fd==-1) { 217 char str[sizeof("0x") + sizeof(size_t)*3+2] = { 218 [0] = '0', [1] = 'x' 219 }; 220 size_t len = utilvserver_fmt_xuint(str+2, conf->blocksize); 221 222 if (global_args->dry_run) return true; // do not create the file 223 224 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644); 225 EwriteAll(fd, str, len+2); 226 } 227 else { 228 off_t s = Elseek(fd, 0, SEEK_END); 229 char buf[s + 1]; 230 Elseek(fd, 0, SEEK_SET); 231 232 conf->blocksize = (size_t)(-1); 233 234 if (s>0 && read(fd, buf, s+1)==s) { 235 char *errptr; 236 237 while (s>0 && (buf[s-1]=='\0' || buf[s-1]=='\n')) 238 --s; 239 buf[s] = '\0'; 240 241 conf->blocksize = strtol(buf, &errptr, 0); 242 if (errptr==buf || (*errptr!='\0' && *errptr!='\n')) { 243 WRITE_MSG(2, "Failed to parse blocksize '"); 244 WRITE_STR(2, buf); 245 WRITE_MSG(2, "'\n"); 246 conf->blocksize = (size_t)(-1); 247 } 248 } 249 else 250 WRITE_MSG(2, "Can not read configuration file for hash-blocksize\n"); 251 } 252 253 Eclose(fd); 254 return conf->blocksize!=(size_t)(-1); 255 } 256 257 static bool 258 initHashConf(struct HashDirConfiguration *conf, char const *hashdir) 259 { 260 size_t l = strlen(hashdir); 261 char tmp[l + MAX(MAX(sizeof("/method"), sizeof("/blocks")), 262 sizeof("/blocksize"))]; 263 264 memcpy(tmp, hashdir, l); 265 266 return ((strcpy(tmp+l, "/method"), initHashMethod (conf, tmp)) && 267 (strcpy(tmp+l, "/blocks"), initHashBlocks (conf, tmp)) && 268 (strcpy(tmp+l, "/blocksize"), initHashBlockSize(conf, tmp))); 269 } 270 271 static char * 272 searchHashdir(char const *lhs, char const *rhs) 273 { 274 size_t l1 = strlen(lhs); 275 size_t l2 = rhs ? strlen(rhs) : 0; 276 char * res = Emalloc(l1 + l2 + 1); 277 struct stat st; 278 279 strcpy(res, lhs); 280 if (rhs) strcat(res, rhs); 281 282 if (stat(res, &st)==-1 || !S_ISDIR(st.st_mode)) { 283 free(res); 284 res = 0; 285 } 286 287 return res; 288 } 289 290 static void 291 initModeManually(struct Arguments const UNUSED *args, int argc, char *argv[]) 292 { 293 assert(args->hash_dir!=0); 294 295 if (argc<2) { 296 WRITE_MSG(2, "No exclude list specified\n"); 297 exit(1); 298 } 299 300 if (!initHashConf(&global_info.hash_conf, args->hash_dir)) { 301 WRITE_MSG(2, "failed to initialize hash-configuration\n"); 302 exit(1); 303 } 304 305 global_info.hash_dirs_max_size = initHashList(&global_info.hash_dirs, 306 args->hash_dir); 307 MatchList_initManually(&global_info.dst_list, 0, strdup(argv[0]), argv[1]); 308 } 309 310 static void 311 initModeVserver(struct Arguments const UNUSED *args, int argc, char *argv[]) 312 { 313 char const *hashdir = args->hash_dir; 314 struct MatchVserverInfo vserver = { 315 .name = argv[0], 316 .use_pkgmgmt = true 317 }; 318 319 if (!MatchVserverInfo_init(&vserver)) { 320 WRITE_MSG(2, "Failed to initialize unification for vserver\n"); 321 exit(1); 322 } 323 324 if (argc!=1) { 325 WRITE_MSG(2, "More than one vserver is not supported\n"); 326 exit(1); 327 } 328 329 if (!MatchList_initByVserver(&global_info.dst_list, &vserver)) { 330 WRITE_MSG(2, "unification not configured for this vserver\n"); 331 exit(1); 332 } 333 334 if (hashdir==0) hashdir = searchHashdir(vserver.appdir.d, "/hash"); 335 if (hashdir==0) hashdir = searchHashdir(CONFDIR "/.defaults/apps/vunify/hash", 0); 336 337 if (hashdir==0) { 338 WRITE_MSG(2, "no hash-directory configured for this vserver.\n"); 339 exit(1); 340 } 341 342 if (!initHashConf(&global_info.hash_conf, hashdir)) { 343 WRITE_MSG(2, "failed to initialize hash-configuration\n"); 344 exit(1); 345 } 346 347 global_info.hash_dirs_max_size = initHashList(&global_info.hash_dirs, hashdir); 348 349 free(const_cast(char *)(hashdir)); 350 MatchVserverInfo_free(&vserver); 351 } 352