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