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