1 1.1 christos // 2 1.1 christos // validate.c - 3 1.1 christos // 4 1.1 christos // Written by Eryk Vershen 5 1.1 christos // 6 1.1 christos 7 1.1 christos /* 8 1.1 christos * Copyright 1997,1998 by Apple Computer, Inc. 9 1.1 christos * All Rights Reserved 10 1.1 christos * 11 1.1 christos * Permission to use, copy, modify, and distribute this software and 12 1.1 christos * its documentation for any purpose and without fee is hereby granted, 13 1.1 christos * provided that the above copyright notice appears in all copies and 14 1.1 christos * that both the copyright notice and this permission notice appear in 15 1.1 christos * supporting documentation. 16 1.1 christos * 17 1.1 christos * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 18 1.1 christos * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 1.1 christos * FOR A PARTICULAR PURPOSE. 20 1.1 christos * 21 1.1 christos * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 22 1.1 christos * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 23 1.1 christos * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 24 1.1 christos * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 25 1.1 christos * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 1.1 christos */ 27 1.1 christos 28 1.1 christos 29 1.1 christos // for *printf() 30 1.1 christos #include <stdio.h> 31 1.1 christos // for malloc(), free() 32 1.1 christos #ifndef __linux__ 33 1.1 christos #include <stdlib.h> 34 1.1 christos #else 35 1.1 christos #include <malloc.h> 36 1.1 christos #endif 37 1.1 christos // for O_RDONLY 38 1.1 christos #include <fcntl.h> 39 1.1 christos // for errno 40 1.1 christos #include <errno.h> 41 1.2 christos #include <inttypes.h> 42 1.1 christos 43 1.1 christos #include "validate.h" 44 1.1 christos #include "deblock_media.h" 45 1.1 christos #include "pathname.h" 46 1.1 christos #include "convert.h" 47 1.1 christos #include "io.h" 48 1.1 christos #include "errors.h" 49 1.1 christos 50 1.1 christos 51 1.1 christos // 52 1.1 christos // Defines 53 1.1 christos // 54 1.1 christos 55 1.1 christos 56 1.1 christos // 57 1.1 christos // Types 58 1.1 christos // 59 1.1 christos enum range_state { 60 1.1 christos kUnallocated, 61 1.1 christos kAllocated, 62 1.1 christos kMultiplyAllocated 63 1.1 christos }; 64 1.1 christos 65 1.1 christos struct range_list { 66 1.1 christos struct range_list *next; 67 1.1 christos struct range_list *prev; 68 1.1 christos enum range_state state; 69 1.1 christos int valid; 70 1.2 christos uint32_t start; 71 1.2 christos uint32_t end; 72 1.1 christos }; 73 1.1 christos typedef struct range_list range_list; 74 1.1 christos 75 1.1 christos 76 1.1 christos // 77 1.1 christos // Global Constants 78 1.1 christos // 79 1.1 christos 80 1.1 christos 81 1.1 christos // 82 1.1 christos // Global Variables 83 1.1 christos // 84 1.1 christos static char *buffer; 85 1.1 christos static Block0 *b0; 86 1.1 christos static DPME *mb; 87 1.1 christos static partition_map_header *the_map; 88 1.1 christos static MEDIA the_media; 89 1.1 christos static int g; 90 1.1 christos 91 1.1 christos 92 1.1 christos // 93 1.1 christos // Forward declarations 94 1.1 christos // 95 1.1 christos int get_block_zero(void); 96 1.1 christos int get_block_n(int n); 97 1.2 christos range_list *new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high); 98 1.1 christos void initialize_list(range_list **list); 99 1.2 christos void add_range(range_list **list, uint32_t base, uint32_t len, int allocate); 100 1.1 christos void print_range_list(range_list *list); 101 1.1 christos void delete_list(range_list *list); 102 1.1 christos void coalesce_list(range_list *list); 103 1.1 christos 104 1.1 christos 105 1.1 christos // 106 1.1 christos // Routines 107 1.1 christos // 108 1.1 christos int 109 1.1 christos get_block_zero(void) 110 1.1 christos { 111 1.1 christos int rtn_value; 112 1.1 christos 113 1.1 christos if (the_map != NULL) { 114 1.1 christos b0 = the_map->misc; 115 1.1 christos rtn_value = 1; 116 1.1 christos } else { 117 1.1 christos if (read_media(the_media, (long long) 0, PBLOCK_SIZE, buffer) == 0) { 118 1.1 christos rtn_value = 0; 119 1.1 christos } else { 120 1.1 christos b0 = (Block0 *) buffer; 121 1.1 christos convert_block0(b0, 1); 122 1.1 christos rtn_value = 1; 123 1.1 christos } 124 1.1 christos } 125 1.1 christos return rtn_value; 126 1.1 christos } 127 1.1 christos 128 1.1 christos 129 1.1 christos int 130 1.1 christos get_block_n(int n) 131 1.1 christos { 132 1.1 christos partition_map * entry; 133 1.1 christos int rtn_value; 134 1.1 christos 135 1.1 christos if (the_map != NULL) { 136 1.1 christos entry = find_entry_by_disk_address(n, the_map); 137 1.1 christos if (entry != 0) { 138 1.1 christos mb = entry->data; 139 1.1 christos rtn_value = 1; 140 1.1 christos } else { 141 1.1 christos rtn_value = 0; 142 1.1 christos } 143 1.1 christos } else { 144 1.1 christos if (read_media(the_media, ((long long) n) * g, PBLOCK_SIZE, (void *)buffer) == 0) { 145 1.1 christos rtn_value = 0; 146 1.1 christos } else { 147 1.1 christos mb = (DPME *) buffer; 148 1.1 christos convert_dpme(mb, 1); 149 1.1 christos rtn_value = 1; 150 1.1 christos } 151 1.1 christos } 152 1.1 christos return rtn_value; 153 1.1 christos } 154 1.1 christos 155 1.1 christos 156 1.1 christos range_list * 157 1.2 christos new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high) 158 1.1 christos { 159 1.1 christos range_list *item; 160 1.1 christos 161 1.1 christos item = (range_list *) malloc(sizeof(struct range_list)); 162 1.1 christos item->next = 0; 163 1.1 christos item->prev = 0; 164 1.1 christos item->state = state; 165 1.1 christos item->valid = valid; 166 1.1 christos item->start = low; 167 1.1 christos item->end = high; 168 1.1 christos return item; 169 1.1 christos } 170 1.1 christos 171 1.1 christos 172 1.1 christos void 173 1.1 christos initialize_list(range_list **list) 174 1.1 christos { 175 1.1 christos range_list *item; 176 1.1 christos 177 1.1 christos item = new_range_list_item(kUnallocated, 0, 0, 0xFFFFFFFF); 178 1.1 christos *list = item; 179 1.1 christos } 180 1.1 christos 181 1.1 christos 182 1.1 christos void 183 1.1 christos delete_list(range_list *list) 184 1.1 christos { 185 1.1 christos range_list *item; 186 1.1 christos range_list *cur; 187 1.1 christos 188 1.1 christos for (cur = list; cur != 0; ) { 189 1.1 christos item = cur; 190 1.1 christos cur = cur->next; 191 1.1 christos free(item); 192 1.1 christos } 193 1.1 christos } 194 1.1 christos 195 1.1 christos 196 1.1 christos void 197 1.2 christos add_range(range_list **list, uint32_t base, uint32_t len, int allocate) 198 1.1 christos { 199 1.1 christos range_list *item; 200 1.1 christos range_list *cur; 201 1.2 christos uint32_t low; 202 1.2 christos uint32_t high; 203 1.1 christos 204 1.1 christos if (list == 0 || *list == 0) { 205 1.1 christos /* XXX initialized list will always have one element */ 206 1.1 christos return; 207 1.1 christos } 208 1.1 christos 209 1.1 christos low = base; 210 1.1 christos high = base + len - 1; 211 1.1 christos if (len == 0 || high < len - 1) { 212 1.1 christos /* XXX wrapped around */ 213 1.1 christos return; 214 1.1 christos } 215 1.1 christos 216 1.1 christos cur = *list; 217 1.1 christos while (low <= high) { 218 1.1 christos if (cur == 0) { 219 1.1 christos /* XXX should never occur */ 220 1.1 christos break; 221 1.1 christos } 222 1.1 christos if (low <= cur->end) { 223 1.1 christos if (cur->start < low) { 224 1.1 christos item = new_range_list_item(cur->state, cur->valid, cur->start, low-1); 225 1.1 christos /* insert before here */ 226 1.1 christos if (cur->prev == 0) { 227 1.1 christos item->prev = 0; 228 1.1 christos *list = item; 229 1.1 christos } else { 230 1.1 christos item->prev = cur->prev; 231 1.1 christos item->prev->next = item; 232 1.1 christos } 233 1.1 christos cur->prev = item; 234 1.1 christos item->next = cur; 235 1.1 christos 236 1.1 christos cur->start = low; 237 1.1 christos } 238 1.1 christos if (high < cur->end) { 239 1.1 christos item = new_range_list_item(cur->state, cur->valid, high+1, cur->end); 240 1.1 christos /* insert after here */ 241 1.1 christos if (cur->next == 0) { 242 1.1 christos item->next = 0; 243 1.1 christos } else { 244 1.1 christos item->next = cur->next; 245 1.1 christos item->next->prev = item; 246 1.1 christos } 247 1.1 christos cur->next = item; 248 1.1 christos item->prev = cur; 249 1.1 christos 250 1.1 christos cur->end = high; 251 1.1 christos } 252 1.1 christos 253 1.1 christos if (allocate) { 254 1.1 christos switch (cur->state) { 255 1.1 christos case kUnallocated: 256 1.1 christos cur->state = kAllocated; 257 1.1 christos break; 258 1.1 christos case kAllocated: 259 1.1 christos case kMultiplyAllocated: 260 1.1 christos cur->state = kMultiplyAllocated; 261 1.1 christos break; 262 1.1 christos } 263 1.1 christos } else { 264 1.1 christos cur->valid = 1; 265 1.1 christos } 266 1.1 christos low = cur->end + 1; 267 1.1 christos } 268 1.1 christos cur = cur->next; 269 1.1 christos } 270 1.1 christos } 271 1.1 christos 272 1.1 christos 273 1.1 christos void 274 1.1 christos coalesce_list(range_list *list) 275 1.1 christos { 276 1.1 christos range_list *cur; 277 1.1 christos range_list *item; 278 1.1 christos 279 1.1 christos for (cur = list; cur != 0; ) { 280 1.1 christos item = cur->next; 281 1.1 christos if (item == 0) { 282 1.1 christos break; 283 1.1 christos } 284 1.1 christos if (cur->valid == item->valid 285 1.1 christos && cur->state == item->state) { 286 1.1 christos cur->end = item->end; 287 1.1 christos cur->next = item->next; 288 1.1 christos if (item->next != 0) { 289 1.1 christos item->next->prev = cur; 290 1.1 christos } 291 1.1 christos free(item); 292 1.1 christos } else { 293 1.1 christos cur = cur->next; 294 1.1 christos } 295 1.1 christos } 296 1.1 christos } 297 1.1 christos 298 1.1 christos 299 1.1 christos void 300 1.1 christos print_range_list(range_list *list) 301 1.1 christos { 302 1.1 christos range_list *cur; 303 1.1 christos int printed; 304 1.2 christos const char *s; 305 1.2 christos 306 1.2 christos s = NULL; /* XXXGCC -Wuninitialized [powerpc] */ 307 1.1 christos 308 1.1 christos if (list == 0) { 309 1.1 christos printf("Empty range list\n"); 310 1.1 christos return; 311 1.1 christos } 312 1.1 christos printf("Range list:\n"); 313 1.1 christos printed = 0; 314 1.1 christos for (cur = list; cur != 0; cur = cur->next) { 315 1.1 christos if (cur->valid) { 316 1.1 christos switch (cur->state) { 317 1.1 christos case kUnallocated: 318 1.1 christos s = "unallocated"; 319 1.1 christos break; 320 1.1 christos case kAllocated: 321 1.1 christos continue; 322 1.1 christos //s = "allocated"; 323 1.1 christos //break; 324 1.1 christos case kMultiplyAllocated: 325 1.1 christos s = "multiply allocated"; 326 1.1 christos break; 327 1.1 christos } 328 1.1 christos printed = 1; 329 1.2 christos printf("\t%"PRIu32":%"PRIu32" %s\n", cur->start, cur->end, s); 330 1.1 christos } else { 331 1.1 christos switch (cur->state) { 332 1.1 christos case kUnallocated: 333 1.1 christos continue; 334 1.1 christos //s = "unallocated"; 335 1.1 christos //break; 336 1.1 christos case kAllocated: 337 1.1 christos s = "allocated"; 338 1.1 christos break; 339 1.1 christos case kMultiplyAllocated: 340 1.1 christos s = "multiply allocated"; 341 1.1 christos break; 342 1.1 christos } 343 1.1 christos printed = 1; 344 1.2 christos printf("\t%"PRIu32":%"PRIu32" out of range, but %s\n", cur->start, cur->end, s); 345 1.1 christos } 346 1.1 christos } 347 1.1 christos if (printed == 0) { 348 1.1 christos printf("\tokay\n"); 349 1.1 christos } 350 1.1 christos } 351 1.1 christos 352 1.1 christos 353 1.1 christos void 354 1.1 christos validate_map(partition_map_header *map) 355 1.1 christos { 356 1.1 christos range_list *list; 357 1.1 christos char *name; 358 1.2 christos uint32_t i; 359 1.2 christos uint32_t limit; 360 1.1 christos int printed; 361 1.1 christos 362 1.1 christos //printf("Validation not implemented yet.\n"); 363 1.1 christos 364 1.1 christos if (map == NULL) { 365 1.1 christos the_map = 0; 366 1.1 christos if (get_string_argument("Name of device: ", &name, 1) == 0) { 367 1.1 christos bad_input("Bad name"); 368 1.1 christos return; 369 1.1 christos } 370 1.1 christos the_media = open_pathname_as_media(name, O_RDONLY); 371 1.1 christos if (the_media == 0) { 372 1.1 christos error(errno, "can't open file '%s'", name); 373 1.1 christos free(name); 374 1.1 christos return; 375 1.1 christos } 376 1.1 christos g = media_granularity(the_media); 377 1.1 christos if (g < PBLOCK_SIZE) { 378 1.1 christos g = PBLOCK_SIZE; 379 1.1 christos } 380 1.1 christos the_media = open_deblock_media(PBLOCK_SIZE, the_media); 381 1.1 christos 382 1.1 christos buffer = malloc(PBLOCK_SIZE); 383 1.1 christos if (buffer == NULL) { 384 1.1 christos error(errno, "can't allocate memory for disk buffer"); 385 1.1 christos goto done; 386 1.1 christos } 387 1.1 christos 388 1.1 christos } else { 389 1.1 christos name = 0; 390 1.1 christos the_map = map; 391 1.1 christos g = map->logical_block; 392 1.1 christos } 393 1.1 christos 394 1.1 christos initialize_list(&list); 395 1.1 christos 396 1.1 christos // get block 0 397 1.1 christos if (get_block_zero() == 0) { 398 1.1 christos printf("unable to read block 0\n"); 399 1.1 christos goto check_map; 400 1.1 christos } 401 1.1 christos // XXX signature valid 402 1.1 christos // XXX size & count match DeviceCapacity 403 1.1 christos // XXX number of descriptors matches array size 404 1.1 christos // XXX each descriptor wholly contained in a partition 405 1.1 christos // XXX the range below here is in physical blocks but the map is in logical blocks!!! 406 1.1 christos add_range(&list, 1, b0->sbBlkCount-1, 0); /* subtract one since args are base & len */ 407 1.1 christos 408 1.1 christos check_map: 409 1.1 christos // compute size of map 410 1.1 christos if (map != NULL) { 411 1.1 christos limit = the_map->blocks_in_map; 412 1.1 christos } else { 413 1.1 christos if (get_block_n(1) == 0) { 414 1.1 christos printf("unable to get first block\n"); 415 1.1 christos goto done; 416 1.1 christos } else { 417 1.1 christos if (mb->dpme_signature != DPME_SIGNATURE) { 418 1.1 christos limit = -1; 419 1.1 christos } else { 420 1.1 christos limit = mb->dpme_map_entries; 421 1.1 christos } 422 1.1 christos } 423 1.1 christos } 424 1.1 christos 425 1.1 christos // for each entry 426 1.1 christos for (i = 1; ; i++) { 427 1.2 christos #if 0 428 1.1 christos if (limit < 0) { 429 1.1 christos /* XXX what to use for end of list? */ 430 1.1 christos if (i > 5) { 431 1.1 christos break; 432 1.1 christos } 433 1.2 christos } else 434 1.2 christos #endif 435 1.2 christos if (i > limit) { 436 1.1 christos break; 437 1.1 christos } 438 1.1 christos 439 1.1 christos printf("block %d:\n", i); 440 1.1 christos 441 1.1 christos // get entry 442 1.1 christos if (get_block_n(i) == 0) { 443 1.1 christos printf("\tunable to get\n"); 444 1.1 christos goto post_processing; 445 1.1 christos } 446 1.1 christos printed = 0; 447 1.1 christos 448 1.1 christos // signature matches 449 1.1 christos if (mb->dpme_signature != DPME_SIGNATURE) { 450 1.1 christos printed = 1; 451 1.1 christos printf("\tsignature is 0x%x, should be 0x%x\n", mb->dpme_signature, DPME_SIGNATURE); 452 1.1 christos } 453 1.1 christos // reserved1 == 0 454 1.1 christos if (mb->dpme_reserved_1 != 0) { 455 1.1 christos printed = 1; 456 1.1 christos printf("\treserved word is 0x%x, should be 0\n", mb->dpme_reserved_1); 457 1.1 christos } 458 1.1 christos // entry count matches 459 1.2 christos #if 0 460 1.1 christos if (limit < 0) { 461 1.1 christos printed = 1; 462 1.2 christos printf("\tentry count is 0x%"PRIx32", real value unknown\n", mb->dpme_map_entries); 463 1.2 christos } else 464 1.2 christos #endif 465 1.2 christos if (mb->dpme_map_entries != limit) { 466 1.1 christos printed = 1; 467 1.2 christos printf("\tentry count is 0x%"PRIx32", should be %"PRId32"\n", mb->dpme_map_entries, limit); 468 1.1 christos } 469 1.1 christos // lblocks contained within physical 470 1.1 christos if (mb->dpme_lblock_start >= mb->dpme_pblocks 471 1.1 christos || mb->dpme_lblocks > mb->dpme_pblocks - mb->dpme_lblock_start) { 472 1.1 christos printed = 1; 473 1.2 christos printf("\tlogical blocks (%"PRId32" for %"PRId32") not within physical size (%"PRId32")\n", 474 1.1 christos mb->dpme_lblock_start, mb->dpme_lblocks, mb->dpme_pblocks); 475 1.1 christos } 476 1.1 christos // remember stuff for post processing 477 1.1 christos add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1); 478 1.1 christos 479 1.1 christos // XXX type is known type? 480 1.1 christos // XXX no unknown flags? 481 1.1 christos // XXX boot blocks either within or outside of logical 482 1.1 christos // XXX checksum matches contents 483 1.1 christos // XXX other fields zero if boot_bytes is zero 484 1.1 christos // XXX processor id is known value? 485 1.1 christos // XXX no data in reserved3 486 1.1 christos if (printed == 0) { 487 1.1 christos printf("\tokay\n"); 488 1.1 christos } 489 1.1 christos } 490 1.1 christos 491 1.1 christos post_processing: 492 1.1 christos // properties of whole map 493 1.1 christos 494 1.1 christos // every block on disk in one & only one partition 495 1.1 christos coalesce_list(list); 496 1.1 christos print_range_list(list); 497 1.1 christos // there is a partition for the map 498 1.1 christos // map fits within partition that contains it 499 1.1 christos 500 1.1 christos // try to detect 512/2048 mixed partition map? 501 1.1 christos 502 1.1 christos done: 503 1.1 christos if (map == NULL) { 504 1.1 christos close_media(the_media); 505 1.1 christos free(buffer); 506 1.1 christos free(name); 507 1.1 christos } 508 1.1 christos } 509