19428323dSchristos //
29428323dSchristos // validate.c -
39428323dSchristos //
49428323dSchristos // Written by Eryk Vershen
59428323dSchristos //
69428323dSchristos
79428323dSchristos /*
89428323dSchristos * Copyright 1997,1998 by Apple Computer, Inc.
99428323dSchristos * All Rights Reserved
109428323dSchristos *
119428323dSchristos * Permission to use, copy, modify, and distribute this software and
129428323dSchristos * its documentation for any purpose and without fee is hereby granted,
139428323dSchristos * provided that the above copyright notice appears in all copies and
149428323dSchristos * that both the copyright notice and this permission notice appear in
159428323dSchristos * supporting documentation.
169428323dSchristos *
179428323dSchristos * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
189428323dSchristos * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
199428323dSchristos * FOR A PARTICULAR PURPOSE.
209428323dSchristos *
219428323dSchristos * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
229428323dSchristos * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
239428323dSchristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
249428323dSchristos * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
259428323dSchristos * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
269428323dSchristos */
279428323dSchristos
289428323dSchristos
299428323dSchristos // for *printf()
309428323dSchristos #include <stdio.h>
319428323dSchristos // for malloc(), free()
329428323dSchristos #ifndef __linux__
339428323dSchristos #include <stdlib.h>
349428323dSchristos #else
359428323dSchristos #include <malloc.h>
369428323dSchristos #endif
379428323dSchristos // for O_RDONLY
389428323dSchristos #include <fcntl.h>
399428323dSchristos // for errno
409428323dSchristos #include <errno.h>
41*48a628aeSchristos #include <inttypes.h>
429428323dSchristos
439428323dSchristos #include "validate.h"
449428323dSchristos #include "deblock_media.h"
459428323dSchristos #include "pathname.h"
469428323dSchristos #include "convert.h"
479428323dSchristos #include "io.h"
489428323dSchristos #include "errors.h"
499428323dSchristos
509428323dSchristos
519428323dSchristos //
529428323dSchristos // Defines
539428323dSchristos //
549428323dSchristos
559428323dSchristos
569428323dSchristos //
579428323dSchristos // Types
589428323dSchristos //
599428323dSchristos enum range_state {
609428323dSchristos kUnallocated,
619428323dSchristos kAllocated,
629428323dSchristos kMultiplyAllocated
639428323dSchristos };
649428323dSchristos
659428323dSchristos struct range_list {
669428323dSchristos struct range_list *next;
679428323dSchristos struct range_list *prev;
689428323dSchristos enum range_state state;
699428323dSchristos int valid;
70*48a628aeSchristos uint32_t start;
71*48a628aeSchristos uint32_t end;
729428323dSchristos };
739428323dSchristos typedef struct range_list range_list;
749428323dSchristos
759428323dSchristos
769428323dSchristos //
779428323dSchristos // Global Constants
789428323dSchristos //
799428323dSchristos
809428323dSchristos
819428323dSchristos //
829428323dSchristos // Global Variables
839428323dSchristos //
849428323dSchristos static char *buffer;
859428323dSchristos static Block0 *b0;
869428323dSchristos static DPME *mb;
879428323dSchristos static partition_map_header *the_map;
889428323dSchristos static MEDIA the_media;
899428323dSchristos static int g;
909428323dSchristos
919428323dSchristos
929428323dSchristos //
939428323dSchristos // Forward declarations
949428323dSchristos //
959428323dSchristos int get_block_zero(void);
969428323dSchristos int get_block_n(int n);
97*48a628aeSchristos range_list *new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high);
989428323dSchristos void initialize_list(range_list **list);
99*48a628aeSchristos void add_range(range_list **list, uint32_t base, uint32_t len, int allocate);
1009428323dSchristos void print_range_list(range_list *list);
1019428323dSchristos void delete_list(range_list *list);
1029428323dSchristos void coalesce_list(range_list *list);
1039428323dSchristos
1049428323dSchristos
1059428323dSchristos //
1069428323dSchristos // Routines
1079428323dSchristos //
1089428323dSchristos int
get_block_zero(void)1099428323dSchristos get_block_zero(void)
1109428323dSchristos {
1119428323dSchristos int rtn_value;
1129428323dSchristos
1139428323dSchristos if (the_map != NULL) {
1149428323dSchristos b0 = the_map->misc;
1159428323dSchristos rtn_value = 1;
1169428323dSchristos } else {
1179428323dSchristos if (read_media(the_media, (long long) 0, PBLOCK_SIZE, buffer) == 0) {
1189428323dSchristos rtn_value = 0;
1199428323dSchristos } else {
1209428323dSchristos b0 = (Block0 *) buffer;
1219428323dSchristos convert_block0(b0, 1);
1229428323dSchristos rtn_value = 1;
1239428323dSchristos }
1249428323dSchristos }
1259428323dSchristos return rtn_value;
1269428323dSchristos }
1279428323dSchristos
1289428323dSchristos
1299428323dSchristos int
get_block_n(int n)1309428323dSchristos get_block_n(int n)
1319428323dSchristos {
1329428323dSchristos partition_map * entry;
1339428323dSchristos int rtn_value;
1349428323dSchristos
1359428323dSchristos if (the_map != NULL) {
1369428323dSchristos entry = find_entry_by_disk_address(n, the_map);
1379428323dSchristos if (entry != 0) {
1389428323dSchristos mb = entry->data;
1399428323dSchristos rtn_value = 1;
1409428323dSchristos } else {
1419428323dSchristos rtn_value = 0;
1429428323dSchristos }
1439428323dSchristos } else {
1449428323dSchristos if (read_media(the_media, ((long long) n) * g, PBLOCK_SIZE, (void *)buffer) == 0) {
1459428323dSchristos rtn_value = 0;
1469428323dSchristos } else {
1479428323dSchristos mb = (DPME *) buffer;
1489428323dSchristos convert_dpme(mb, 1);
1499428323dSchristos rtn_value = 1;
1509428323dSchristos }
1519428323dSchristos }
1529428323dSchristos return rtn_value;
1539428323dSchristos }
1549428323dSchristos
1559428323dSchristos
1569428323dSchristos range_list *
new_range_list_item(enum range_state state,int valid,uint32_t low,uint32_t high)157*48a628aeSchristos new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high)
1589428323dSchristos {
1599428323dSchristos range_list *item;
1609428323dSchristos
1619428323dSchristos item = (range_list *) malloc(sizeof(struct range_list));
1629428323dSchristos item->next = 0;
1639428323dSchristos item->prev = 0;
1649428323dSchristos item->state = state;
1659428323dSchristos item->valid = valid;
1669428323dSchristos item->start = low;
1679428323dSchristos item->end = high;
1689428323dSchristos return item;
1699428323dSchristos }
1709428323dSchristos
1719428323dSchristos
1729428323dSchristos void
initialize_list(range_list ** list)1739428323dSchristos initialize_list(range_list **list)
1749428323dSchristos {
1759428323dSchristos range_list *item;
1769428323dSchristos
1779428323dSchristos item = new_range_list_item(kUnallocated, 0, 0, 0xFFFFFFFF);
1789428323dSchristos *list = item;
1799428323dSchristos }
1809428323dSchristos
1819428323dSchristos
1829428323dSchristos void
delete_list(range_list * list)1839428323dSchristos delete_list(range_list *list)
1849428323dSchristos {
1859428323dSchristos range_list *item;
1869428323dSchristos range_list *cur;
1879428323dSchristos
1889428323dSchristos for (cur = list; cur != 0; ) {
1899428323dSchristos item = cur;
1909428323dSchristos cur = cur->next;
1919428323dSchristos free(item);
1929428323dSchristos }
1939428323dSchristos }
1949428323dSchristos
1959428323dSchristos
1969428323dSchristos void
add_range(range_list ** list,uint32_t base,uint32_t len,int allocate)197*48a628aeSchristos add_range(range_list **list, uint32_t base, uint32_t len, int allocate)
1989428323dSchristos {
1999428323dSchristos range_list *item;
2009428323dSchristos range_list *cur;
201*48a628aeSchristos uint32_t low;
202*48a628aeSchristos uint32_t high;
2039428323dSchristos
2049428323dSchristos if (list == 0 || *list == 0) {
2059428323dSchristos /* XXX initialized list will always have one element */
2069428323dSchristos return;
2079428323dSchristos }
2089428323dSchristos
2099428323dSchristos low = base;
2109428323dSchristos high = base + len - 1;
2119428323dSchristos if (len == 0 || high < len - 1) {
2129428323dSchristos /* XXX wrapped around */
2139428323dSchristos return;
2149428323dSchristos }
2159428323dSchristos
2169428323dSchristos cur = *list;
2179428323dSchristos while (low <= high) {
2189428323dSchristos if (cur == 0) {
2199428323dSchristos /* XXX should never occur */
2209428323dSchristos break;
2219428323dSchristos }
2229428323dSchristos if (low <= cur->end) {
2239428323dSchristos if (cur->start < low) {
2249428323dSchristos item = new_range_list_item(cur->state, cur->valid, cur->start, low-1);
2259428323dSchristos /* insert before here */
2269428323dSchristos if (cur->prev == 0) {
2279428323dSchristos item->prev = 0;
2289428323dSchristos *list = item;
2299428323dSchristos } else {
2309428323dSchristos item->prev = cur->prev;
2319428323dSchristos item->prev->next = item;
2329428323dSchristos }
2339428323dSchristos cur->prev = item;
2349428323dSchristos item->next = cur;
2359428323dSchristos
2369428323dSchristos cur->start = low;
2379428323dSchristos }
2389428323dSchristos if (high < cur->end) {
2399428323dSchristos item = new_range_list_item(cur->state, cur->valid, high+1, cur->end);
2409428323dSchristos /* insert after here */
2419428323dSchristos if (cur->next == 0) {
2429428323dSchristos item->next = 0;
2439428323dSchristos } else {
2449428323dSchristos item->next = cur->next;
2459428323dSchristos item->next->prev = item;
2469428323dSchristos }
2479428323dSchristos cur->next = item;
2489428323dSchristos item->prev = cur;
2499428323dSchristos
2509428323dSchristos cur->end = high;
2519428323dSchristos }
2529428323dSchristos
2539428323dSchristos if (allocate) {
2549428323dSchristos switch (cur->state) {
2559428323dSchristos case kUnallocated:
2569428323dSchristos cur->state = kAllocated;
2579428323dSchristos break;
2589428323dSchristos case kAllocated:
2599428323dSchristos case kMultiplyAllocated:
2609428323dSchristos cur->state = kMultiplyAllocated;
2619428323dSchristos break;
2629428323dSchristos }
2639428323dSchristos } else {
2649428323dSchristos cur->valid = 1;
2659428323dSchristos }
2669428323dSchristos low = cur->end + 1;
2679428323dSchristos }
2689428323dSchristos cur = cur->next;
2699428323dSchristos }
2709428323dSchristos }
2719428323dSchristos
2729428323dSchristos
2739428323dSchristos void
coalesce_list(range_list * list)2749428323dSchristos coalesce_list(range_list *list)
2759428323dSchristos {
2769428323dSchristos range_list *cur;
2779428323dSchristos range_list *item;
2789428323dSchristos
2799428323dSchristos for (cur = list; cur != 0; ) {
2809428323dSchristos item = cur->next;
2819428323dSchristos if (item == 0) {
2829428323dSchristos break;
2839428323dSchristos }
2849428323dSchristos if (cur->valid == item->valid
2859428323dSchristos && cur->state == item->state) {
2869428323dSchristos cur->end = item->end;
2879428323dSchristos cur->next = item->next;
2889428323dSchristos if (item->next != 0) {
2899428323dSchristos item->next->prev = cur;
2909428323dSchristos }
2919428323dSchristos free(item);
2929428323dSchristos } else {
2939428323dSchristos cur = cur->next;
2949428323dSchristos }
2959428323dSchristos }
2969428323dSchristos }
2979428323dSchristos
2989428323dSchristos
2999428323dSchristos void
print_range_list(range_list * list)3009428323dSchristos print_range_list(range_list *list)
3019428323dSchristos {
3029428323dSchristos range_list *cur;
3039428323dSchristos int printed;
304*48a628aeSchristos const char *s;
305*48a628aeSchristos
306*48a628aeSchristos s = NULL; /* XXXGCC -Wuninitialized [powerpc] */
3079428323dSchristos
3089428323dSchristos if (list == 0) {
3099428323dSchristos printf("Empty range list\n");
3109428323dSchristos return;
3119428323dSchristos }
3129428323dSchristos printf("Range list:\n");
3139428323dSchristos printed = 0;
3149428323dSchristos for (cur = list; cur != 0; cur = cur->next) {
3159428323dSchristos if (cur->valid) {
3169428323dSchristos switch (cur->state) {
3179428323dSchristos case kUnallocated:
3189428323dSchristos s = "unallocated";
3199428323dSchristos break;
3209428323dSchristos case kAllocated:
3219428323dSchristos continue;
3229428323dSchristos //s = "allocated";
3239428323dSchristos //break;
3249428323dSchristos case kMultiplyAllocated:
3259428323dSchristos s = "multiply allocated";
3269428323dSchristos break;
3279428323dSchristos }
3289428323dSchristos printed = 1;
329*48a628aeSchristos printf("\t%"PRIu32":%"PRIu32" %s\n", cur->start, cur->end, s);
3309428323dSchristos } else {
3319428323dSchristos switch (cur->state) {
3329428323dSchristos case kUnallocated:
3339428323dSchristos continue;
3349428323dSchristos //s = "unallocated";
3359428323dSchristos //break;
3369428323dSchristos case kAllocated:
3379428323dSchristos s = "allocated";
3389428323dSchristos break;
3399428323dSchristos case kMultiplyAllocated:
3409428323dSchristos s = "multiply allocated";
3419428323dSchristos break;
3429428323dSchristos }
3439428323dSchristos printed = 1;
344*48a628aeSchristos printf("\t%"PRIu32":%"PRIu32" out of range, but %s\n", cur->start, cur->end, s);
3459428323dSchristos }
3469428323dSchristos }
3479428323dSchristos if (printed == 0) {
3489428323dSchristos printf("\tokay\n");
3499428323dSchristos }
3509428323dSchristos }
3519428323dSchristos
3529428323dSchristos
3539428323dSchristos void
validate_map(partition_map_header * map)3549428323dSchristos validate_map(partition_map_header *map)
3559428323dSchristos {
3569428323dSchristos range_list *list;
3579428323dSchristos char *name;
358*48a628aeSchristos uint32_t i;
359*48a628aeSchristos uint32_t limit;
3609428323dSchristos int printed;
3619428323dSchristos
3629428323dSchristos //printf("Validation not implemented yet.\n");
3639428323dSchristos
3649428323dSchristos if (map == NULL) {
3659428323dSchristos the_map = 0;
3669428323dSchristos if (get_string_argument("Name of device: ", &name, 1) == 0) {
3679428323dSchristos bad_input("Bad name");
3689428323dSchristos return;
3699428323dSchristos }
3709428323dSchristos the_media = open_pathname_as_media(name, O_RDONLY);
3719428323dSchristos if (the_media == 0) {
3729428323dSchristos error(errno, "can't open file '%s'", name);
3739428323dSchristos free(name);
3749428323dSchristos return;
3759428323dSchristos }
3769428323dSchristos g = media_granularity(the_media);
3779428323dSchristos if (g < PBLOCK_SIZE) {
3789428323dSchristos g = PBLOCK_SIZE;
3799428323dSchristos }
3809428323dSchristos the_media = open_deblock_media(PBLOCK_SIZE, the_media);
3819428323dSchristos
3829428323dSchristos buffer = malloc(PBLOCK_SIZE);
3839428323dSchristos if (buffer == NULL) {
3849428323dSchristos error(errno, "can't allocate memory for disk buffer");
3859428323dSchristos goto done;
3869428323dSchristos }
3879428323dSchristos
3889428323dSchristos } else {
3899428323dSchristos name = 0;
3909428323dSchristos the_map = map;
3919428323dSchristos g = map->logical_block;
3929428323dSchristos }
3939428323dSchristos
3949428323dSchristos initialize_list(&list);
3959428323dSchristos
3969428323dSchristos // get block 0
3979428323dSchristos if (get_block_zero() == 0) {
3989428323dSchristos printf("unable to read block 0\n");
3999428323dSchristos goto check_map;
4009428323dSchristos }
4019428323dSchristos // XXX signature valid
4029428323dSchristos // XXX size & count match DeviceCapacity
4039428323dSchristos // XXX number of descriptors matches array size
4049428323dSchristos // XXX each descriptor wholly contained in a partition
4059428323dSchristos // XXX the range below here is in physical blocks but the map is in logical blocks!!!
4069428323dSchristos add_range(&list, 1, b0->sbBlkCount-1, 0); /* subtract one since args are base & len */
4079428323dSchristos
4089428323dSchristos check_map:
4099428323dSchristos // compute size of map
4109428323dSchristos if (map != NULL) {
4119428323dSchristos limit = the_map->blocks_in_map;
4129428323dSchristos } else {
4139428323dSchristos if (get_block_n(1) == 0) {
4149428323dSchristos printf("unable to get first block\n");
4159428323dSchristos goto done;
4169428323dSchristos } else {
4179428323dSchristos if (mb->dpme_signature != DPME_SIGNATURE) {
4189428323dSchristos limit = -1;
4199428323dSchristos } else {
4209428323dSchristos limit = mb->dpme_map_entries;
4219428323dSchristos }
4229428323dSchristos }
4239428323dSchristos }
4249428323dSchristos
4259428323dSchristos // for each entry
4269428323dSchristos for (i = 1; ; i++) {
427*48a628aeSchristos #if 0
4289428323dSchristos if (limit < 0) {
4299428323dSchristos /* XXX what to use for end of list? */
4309428323dSchristos if (i > 5) {
4319428323dSchristos break;
4329428323dSchristos }
433*48a628aeSchristos } else
434*48a628aeSchristos #endif
435*48a628aeSchristos if (i > limit) {
4369428323dSchristos break;
4379428323dSchristos }
4389428323dSchristos
4399428323dSchristos printf("block %d:\n", i);
4409428323dSchristos
4419428323dSchristos // get entry
4429428323dSchristos if (get_block_n(i) == 0) {
4439428323dSchristos printf("\tunable to get\n");
4449428323dSchristos goto post_processing;
4459428323dSchristos }
4469428323dSchristos printed = 0;
4479428323dSchristos
4489428323dSchristos // signature matches
4499428323dSchristos if (mb->dpme_signature != DPME_SIGNATURE) {
4509428323dSchristos printed = 1;
4519428323dSchristos printf("\tsignature is 0x%x, should be 0x%x\n", mb->dpme_signature, DPME_SIGNATURE);
4529428323dSchristos }
4539428323dSchristos // reserved1 == 0
4549428323dSchristos if (mb->dpme_reserved_1 != 0) {
4559428323dSchristos printed = 1;
4569428323dSchristos printf("\treserved word is 0x%x, should be 0\n", mb->dpme_reserved_1);
4579428323dSchristos }
4589428323dSchristos // entry count matches
459*48a628aeSchristos #if 0
4609428323dSchristos if (limit < 0) {
4619428323dSchristos printed = 1;
462*48a628aeSchristos printf("\tentry count is 0x%"PRIx32", real value unknown\n", mb->dpme_map_entries);
463*48a628aeSchristos } else
464*48a628aeSchristos #endif
465*48a628aeSchristos if (mb->dpme_map_entries != limit) {
4669428323dSchristos printed = 1;
467*48a628aeSchristos printf("\tentry count is 0x%"PRIx32", should be %"PRId32"\n", mb->dpme_map_entries, limit);
4689428323dSchristos }
4699428323dSchristos // lblocks contained within physical
4709428323dSchristos if (mb->dpme_lblock_start >= mb->dpme_pblocks
4719428323dSchristos || mb->dpme_lblocks > mb->dpme_pblocks - mb->dpme_lblock_start) {
4729428323dSchristos printed = 1;
473*48a628aeSchristos printf("\tlogical blocks (%"PRId32" for %"PRId32") not within physical size (%"PRId32")\n",
4749428323dSchristos mb->dpme_lblock_start, mb->dpme_lblocks, mb->dpme_pblocks);
4759428323dSchristos }
4769428323dSchristos // remember stuff for post processing
4779428323dSchristos add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1);
4789428323dSchristos
4799428323dSchristos // XXX type is known type?
4809428323dSchristos // XXX no unknown flags?
4819428323dSchristos // XXX boot blocks either within or outside of logical
4829428323dSchristos // XXX checksum matches contents
4839428323dSchristos // XXX other fields zero if boot_bytes is zero
4849428323dSchristos // XXX processor id is known value?
4859428323dSchristos // XXX no data in reserved3
4869428323dSchristos if (printed == 0) {
4879428323dSchristos printf("\tokay\n");
4889428323dSchristos }
4899428323dSchristos }
4909428323dSchristos
4919428323dSchristos post_processing:
4929428323dSchristos // properties of whole map
4939428323dSchristos
4949428323dSchristos // every block on disk in one & only one partition
4959428323dSchristos coalesce_list(list);
4969428323dSchristos print_range_list(list);
4979428323dSchristos // there is a partition for the map
4989428323dSchristos // map fits within partition that contains it
4999428323dSchristos
5009428323dSchristos // try to detect 512/2048 mixed partition map?
5019428323dSchristos
5029428323dSchristos done:
5039428323dSchristos if (map == NULL) {
5049428323dSchristos close_media(the_media);
5059428323dSchristos free(buffer);
5069428323dSchristos free(name);
5079428323dSchristos }
5089428323dSchristos }
509