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