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