xref: /netbsd-src/external/bsd/pdisk/dist/validate.c (revision 48a628ae0434c4247b560ad8f2eb1dc06d0dd070)
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 //
59 enum range_state {
60     kUnallocated,
61     kAllocated,
62     kMultiplyAllocated
63 };
64 
65 struct 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 };
73 typedef struct range_list range_list;
74 
75 
76 //
77 // Global Constants
78 //
79 
80 
81 //
82 // Global Variables
83 //
84 static char *buffer;
85 static Block0 *b0;
86 static DPME *mb;
87 static partition_map_header *the_map;
88 static MEDIA the_media;
89 static int g;
90 
91 
92 //
93 // Forward declarations
94 //
95 int get_block_zero(void);
96 int get_block_n(int n);
97 range_list *new_range_list_item(enum range_state state, int valid, uint32_t low, uint32_t high);
98 void initialize_list(range_list **list);
99 void add_range(range_list **list, uint32_t base, uint32_t len, int allocate);
100 void print_range_list(range_list *list);
101 void delete_list(range_list *list);
102 void coalesce_list(range_list *list);
103 
104 
105 //
106 // Routines
107 //
108 int
get_block_zero(void)109 get_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 
129 int
get_block_n(int n)130 get_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 
156 range_list *
new_range_list_item(enum range_state state,int valid,uint32_t low,uint32_t high)157 new_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 
172 void
initialize_list(range_list ** list)173 initialize_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 
182 void
delete_list(range_list * list)183 delete_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 
196 void
add_range(range_list ** list,uint32_t base,uint32_t len,int allocate)197 add_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 
273 void
coalesce_list(range_list * list)274 coalesce_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 
299 void
print_range_list(range_list * list)300 print_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 
353 void
validate_map(partition_map_header * map)354 validate_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 
408 check_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 
491 post_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 
502 done:
503     if (map == NULL) {
504 	close_media(the_media);
505 	free(buffer);
506 	free(name);
507     }
508 }
509