Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / pdisk / validate.c
blob44ffcde5ec5ebe16ce89c9ad15a2ec79c416998e
1 //
2 // validate.c -
3 //
4 // Written by Eryk Vershen
5 //
7 /*
8 * Copyright 1997,1998 by Apple Computer, Inc.
9 * All Rights Reserved
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.
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.
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.
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>
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"
51 // Defines
56 // Types
58 enum range_state {
59 kUnallocated,
60 kAllocated,
61 kMultiplyAllocated
64 struct 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;
72 typedef struct range_list range_list;
76 // Global Constants
81 // Global Variables
83 static char *buffer;
84 static Block0 *b0;
85 static DPME *mb;
86 static partition_map_header *the_map;
87 static MEDIA the_media;
88 static int g;
92 // Forward declarations
94 int get_block_zero(void);
95 int get_block_n(int n);
96 range_list *new_range_list_item(enum range_state state, int valid, u32 low, u32 high);
97 void initialize_list(range_list **list);
98 void add_range(range_list **list, u32 base, u32 len, int allocate);
99 void print_range_list(range_list *list);
100 void delete_list(range_list *list);
101 void coalesce_list(range_list *list);
105 // Routines
108 get_block_zero(void)
110 int rtn_value;
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;
124 return rtn_value;
129 get_block_n(int n)
131 partition_map * entry;
132 int rtn_value;
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;
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;
151 return rtn_value;
155 range_list *
156 new_range_list_item(enum range_state state, int valid, u32 low, u32 high)
158 range_list *item;
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;
171 void
172 initialize_list(range_list **list)
174 range_list *item;
176 item = new_range_list_item(kUnallocated, 0, 0, 0xFFFFFFFF);
177 *list = item;
181 void
182 delete_list(range_list *list)
184 range_list *item;
185 range_list *cur;
187 for (cur = list; cur != 0; ) {
188 item = cur;
189 cur = cur->next;
190 free(item);
195 void
196 add_range(range_list **list, u32 base, u32 len, int allocate)
198 range_list *item;
199 range_list *cur;
200 u32 low;
201 u32 high;
203 if (list == 0 || *list == 0) {
204 /* XXX initialized list will always have one element */
205 return;
208 low = base;
209 high = base + len - 1;
210 if (len == 0 || high < len - 1) {
211 /* XXX wrapped around */
212 return;
215 cur = *list;
216 while (low <= high) {
217 if (cur == 0) {
218 /* XXX should never occur */
219 break;
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;
232 cur->prev = item;
233 item->next = cur;
235 cur->start = low;
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;
246 cur->next = item;
247 item->prev = cur;
249 cur->end = high;
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;
262 } else {
263 cur->valid = 1;
265 low = cur->end + 1;
267 cur = cur->next;
272 void
273 coalesce_list(range_list *list)
275 range_list *cur;
276 range_list *item;
278 for (cur = list; cur != 0; ) {
279 item = cur->next;
280 if (item == 0) {
281 break;
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;
290 free(item);
291 } else {
292 cur = cur->next;
298 void
299 print_range_list(range_list *list)
301 range_list *cur;
302 int printed;
303 const char *s;
305 s = NULL; /* XXXGCC -Wuninitialized [powerpc] */
307 if (list == 0) {
308 printf("Empty range list\n");
309 return;
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;
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;
342 printed = 1;
343 printf("\t%lu:%lu out of range, but %s\n", cur->start, cur->end, s);
346 if (printed == 0) {
347 printf("\tokay\n");
352 void
353 validate_map(partition_map_header *map)
355 range_list *list;
356 char *name;
357 unsigned int i;
358 u32 limit;
359 int printed;
361 //printf("Validation not implemented yet.\n");
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;
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;
375 g = media_granularity(the_media);
376 if (g < PBLOCK_SIZE) {
377 g = PBLOCK_SIZE;
379 the_media = open_deblock_media(PBLOCK_SIZE, the_media);
381 buffer = malloc(PBLOCK_SIZE);
382 if (buffer == NULL) {
383 error(errno, "can't allocate memory for disk buffer");
384 goto done;
387 } else {
388 name = 0;
389 the_map = map;
390 g = map->logical_block;
393 initialize_list(&list);
395 // get block 0
396 if (get_block_zero() == 0) {
397 printf("unable to read block 0\n");
398 goto check_map;
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 */
407 check_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;
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;
432 } else
433 #endif
434 if (i > limit) {
435 break;
438 printf("block %d:\n", i);
440 // get entry
441 if (get_block_n(i) == 0) {
442 printf("\tunable to get\n");
443 goto post_processing;
445 printed = 0;
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);
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);
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);
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);
475 // remember stuff for post processing
476 add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1);
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");
490 post_processing:
491 // properties of whole map
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
499 // try to detect 512/2048 mixed partition map?
501 done:
502 if (map == NULL) {
503 close_media(the_media);
504 free(buffer);
505 free(name);