xref: /netbsd-src/external/bsd/pdisk/dist/validate.c (revision 48a628ae0434c4247b560ad8f2eb1dc06d0dd070)
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