// // validate.c - // // Written by Eryk Vershen // /* * Copyright 1997,1998 by Apple Computer, Inc. * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ // for *printf() #include // for malloc(), free() #ifndef __linux__ #include #else #include #endif // for O_RDONLY #include // for errno #include #include #include "validate.h" #include "deblock_media.h" #include "pathname.h" #include "convert.h" #include "io.h" #include "errors.h" // // Defines // // // Types // enum range_state { kUnallocated, kAllocated, kMultiplyAllocated }; struct range_list { struct range_list *next; struct range_list *prev; enum range_state state; int valid; uint32_t start; uint32_t end; }; typedef struct range_list range_list; // // Global Constants // // // Global Variables // static char *buffer; static Block0 *b0; static DPME *mb; static partition_map_header *the_map; static MEDIA the_media; static int g; // // Forward declarations // int get_block_zero(void); int get_block_n(int n); range_list *new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high); void initialize_list(range_list **list); void add_range(range_list **list, uint32_t base, uint32_t len, int allocate); void print_range_list(range_list *list); void delete_list(range_list *list); void coalesce_list(range_list *list); // // Routines // int get_block_zero(void) { int rtn_value; if (the_map != NULL) { b0 = the_map->misc; rtn_value = 1; } else { if (read_media(the_media, (long long) 0, PBLOCK_SIZE, buffer) == 0) { rtn_value = 0; } else { b0 = (Block0 *) buffer; convert_block0(b0, 1); rtn_value = 1; } } return rtn_value; } int get_block_n(int n) { partition_map * entry; int rtn_value; if (the_map != NULL) { entry = find_entry_by_disk_address(n, the_map); if (entry != 0) { mb = entry->data; rtn_value = 1; } else { rtn_value = 0; } } else { if (read_media(the_media, ((long long) n) * g, PBLOCK_SIZE, (void *)buffer) == 0) { rtn_value = 0; } else { mb = (DPME *) buffer; convert_dpme(mb, 1); rtn_value = 1; } } return rtn_value; } range_list * new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high) { range_list *item; item = (range_list *) malloc(sizeof(struct range_list)); item->next = 0; item->prev = 0; item->state = state; item->valid = valid; item->start = low; item->end = high; return item; } void initialize_list(range_list **list) { range_list *item; item = new_range_list_item(kUnallocated, 0, 0, 0xFFFFFFFF); *list = item; } void delete_list(range_list *list) { range_list *item; range_list *cur; for (cur = list; cur != 0; ) { item = cur; cur = cur->next; free(item); } } void add_range(range_list **list, uint32_t base, uint32_t len, int allocate) { range_list *item; range_list *cur; uint32_t low; uint32_t high; if (list == 0 || *list == 0) { /* XXX initialized list will always have one element */ return; } low = base; high = base + len - 1; if (len == 0 || high < len - 1) { /* XXX wrapped around */ return; } cur = *list; while (low <= high) { if (cur == 0) { /* XXX should never occur */ break; } if (low <= cur->end) { if (cur->start < low) { item = new_range_list_item(cur->state, cur->valid, cur->start, low-1); /* insert before here */ if (cur->prev == 0) { item->prev = 0; *list = item; } else { item->prev = cur->prev; item->prev->next = item; } cur->prev = item; item->next = cur; cur->start = low; } if (high < cur->end) { item = new_range_list_item(cur->state, cur->valid, high+1, cur->end); /* insert after here */ if (cur->next == 0) { item->next = 0; } else { item->next = cur->next; item->next->prev = item; } cur->next = item; item->prev = cur; cur->end = high; } if (allocate) { switch (cur->state) { case kUnallocated: cur->state = kAllocated; break; case kAllocated: case kMultiplyAllocated: cur->state = kMultiplyAllocated; break; } } else { cur->valid = 1; } low = cur->end + 1; } cur = cur->next; } } void coalesce_list(range_list *list) { range_list *cur; range_list *item; for (cur = list; cur != 0; ) { item = cur->next; if (item == 0) { break; } if (cur->valid == item->valid && cur->state == item->state) { cur->end = item->end; cur->next = item->next; if (item->next != 0) { item->next->prev = cur; } free(item); } else { cur = cur->next; } } } void print_range_list(range_list *list) { range_list *cur; int printed; const char *s; s = NULL; /* XXXGCC -Wuninitialized [powerpc] */ if (list == 0) { printf("Empty range list\n"); return; } printf("Range list:\n"); printed = 0; for (cur = list; cur != 0; cur = cur->next) { if (cur->valid) { switch (cur->state) { case kUnallocated: s = "unallocated"; break; case kAllocated: continue; //s = "allocated"; //break; case kMultiplyAllocated: s = "multiply allocated"; break; } printed = 1; printf("\t%"PRIu32":%"PRIu32" %s\n", cur->start, cur->end, s); } else { switch (cur->state) { case kUnallocated: continue; //s = "unallocated"; //break; case kAllocated: s = "allocated"; break; case kMultiplyAllocated: s = "multiply allocated"; break; } printed = 1; printf("\t%"PRIu32":%"PRIu32" out of range, but %s\n", cur->start, cur->end, s); } } if (printed == 0) { printf("\tokay\n"); } } void validate_map(partition_map_header *map) { range_list *list; char *name; uint32_t i; uint32_t limit; int printed; //printf("Validation not implemented yet.\n"); if (map == NULL) { the_map = 0; if (get_string_argument("Name of device: ", &name, 1) == 0) { bad_input("Bad name"); return; } the_media = open_pathname_as_media(name, O_RDONLY); if (the_media == 0) { error(errno, "can't open file '%s'", name); free(name); return; } g = media_granularity(the_media); if (g < PBLOCK_SIZE) { g = PBLOCK_SIZE; } the_media = open_deblock_media(PBLOCK_SIZE, the_media); buffer = malloc(PBLOCK_SIZE); if (buffer == NULL) { error(errno, "can't allocate memory for disk buffer"); goto done; } } else { name = 0; the_map = map; g = map->logical_block; } initialize_list(&list); // get block 0 if (get_block_zero() == 0) { printf("unable to read block 0\n"); goto check_map; } // XXX signature valid // XXX size & count match DeviceCapacity // XXX number of descriptors matches array size // XXX each descriptor wholly contained in a partition // XXX the range below here is in physical blocks but the map is in logical blocks!!! add_range(&list, 1, b0->sbBlkCount-1, 0); /* subtract one since args are base & len */ check_map: // compute size of map if (map != NULL) { limit = the_map->blocks_in_map; } else { if (get_block_n(1) == 0) { printf("unable to get first block\n"); goto done; } else { if (mb->dpme_signature != DPME_SIGNATURE) { limit = -1; } else { limit = mb->dpme_map_entries; } } } // for each entry for (i = 1; ; i++) { #if 0 if (limit < 0) { /* XXX what to use for end of list? */ if (i > 5) { break; } } else #endif if (i > limit) { break; } printf("block %d:\n", i); // get entry if (get_block_n(i) == 0) { printf("\tunable to get\n"); goto post_processing; } printed = 0; // signature matches if (mb->dpme_signature != DPME_SIGNATURE) { printed = 1; printf("\tsignature is 0x%x, should be 0x%x\n", mb->dpme_signature, DPME_SIGNATURE); } // reserved1 == 0 if (mb->dpme_reserved_1 != 0) { printed = 1; printf("\treserved word is 0x%x, should be 0\n", mb->dpme_reserved_1); } // entry count matches #if 0 if (limit < 0) { printed = 1; printf("\tentry count is 0x%"PRIx32", real value unknown\n", mb->dpme_map_entries); } else #endif if (mb->dpme_map_entries != limit) { printed = 1; printf("\tentry count is 0x%"PRIx32", should be %"PRId32"\n", mb->dpme_map_entries, limit); } // lblocks contained within physical if (mb->dpme_lblock_start >= mb->dpme_pblocks || mb->dpme_lblocks > mb->dpme_pblocks - mb->dpme_lblock_start) { printed = 1; printf("\tlogical blocks (%"PRId32" for %"PRId32") not within physical size (%"PRId32")\n", mb->dpme_lblock_start, mb->dpme_lblocks, mb->dpme_pblocks); } // remember stuff for post processing add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1); // XXX type is known type? // XXX no unknown flags? // XXX boot blocks either within or outside of logical // XXX checksum matches contents // XXX other fields zero if boot_bytes is zero // XXX processor id is known value? // XXX no data in reserved3 if (printed == 0) { printf("\tokay\n"); } } post_processing: // properties of whole map // every block on disk in one & only one partition coalesce_list(list); print_range_list(list); // there is a partition for the map // map fits within partition that contains it // try to detect 512/2048 mixed partition map? done: if (map == NULL) { close_media(the_media); free(buffer); free(name); } }