1//
2// dump.c - dumping partition maps
3//
4// Written by Eryk Vershen
5//
6
7/*
8 * Copyright 1996,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// for *printf()
29#include <stdio.h>
30
31// for malloc() & free()
32#ifndef __linux__
33#include <stdlib.h>
34//#include <unistd.h>
35#else
36#include <malloc.h>
37#endif
38
39// for strcmp()
40#include <string.h>
41// for O_RDONLY
42#include <fcntl.h>
43// for errno
44#include <errno.h>
45
46#include "dump.h"
47#include "pathname.h"
48#include "io.h"
49#include "errors.h"
50
51#ifdef __APPLE__
52#include <CoreFoundation/CoreFoundation.h>
53#include <IOKit/IOBSD.h>
54#include <IOKit/IOKitLib.h>
55#include <IOKit/storage/IOMedia.h>
56#endif
57
58//
59// Defines
60//
61#if DPISTRLEN != 32
62#error Change in strlen in partition entries! Fix constants
63#endif
64
65#define get_align_long(x)	(*(x))
66
67
68//
69// Types
70//
71typedef struct names {
72    const char *abbr;
73    const char *full;
74} NAMES;
75
76typedef struct PatchDescriptor {
77    unsigned long	patchSig;
78    unsigned short	majorVers;
79    unsigned short	minorVers;
80    unsigned long	flags;
81    unsigned long	patchOffset;
82    unsigned long	patchSize;
83    unsigned long	patchCRC;
84    unsigned long	patchDescriptorLen;
85    unsigned char	patchName[33];
86    unsigned char	patchVendor[1];
87} PatchDescriptor;
88typedef PatchDescriptor * PatchDescriptorPtr;
89
90typedef struct PatchList {
91    unsigned short numPatchBlocks;	// number of disk blocks to hold the patch list
92    unsigned short numPatches;		// number of patches in list
93    PatchDescriptor thePatch[1];
94} PatchList;
95typedef PatchList *PatchListPtr;
96
97
98//
99// Global Constants
100//
101NAMES plist[] = {
102    {"Drvr", "Apple_Driver"},
103    {"Drv4", "Apple_Driver43"},
104    {"Free", "Apple_Free"},
105    {"Patc", "Apple_Patches"},
106    {" HFS", "Apple_HFS"},
107    {" MFS", "Apple_MFS"},
108    {"PDOS", "Apple_PRODOS"},
109    {"junk", "Apple_Scratch"},
110    {"unix", "Apple_UNIX_SVR2"},
111    {" map", "Apple_partition_map"},
112    {0,	0},
113};
114
115const char * kStringEmpty	= "";
116const char * kStringNot		= " not";
117
118
119//
120// Global Variables
121//
122int aflag = AFLAG_DEFAULT;	/* abbreviate partition types */
123int pflag = PFLAG_DEFAULT;	/* show physical limits of partition */
124int fflag = FFLAG_DEFAULT;	/* show HFS volume names */
125
126
127//
128// Forward declarations
129//
130void adjust_value_and_compute_prefix(double *value, int *prefix);
131void dump_block_zero(partition_map_header *map);
132void dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits);
133int get_max_base_or_length(partition_map_header *map);
134int get_max_name_string_length(partition_map_header *map);
135int get_max_type_string_length(partition_map_header *map);
136
137
138//
139// Routines
140//
141int
142dump(char *name)
143{
144    partition_map_header *map;
145    int junk;
146
147    map = open_partition_map(name, &junk, 0, O_RDONLY);
148    if (map == NULL) {
149	//error(-1, "No partition map in '%s'", name);
150	return 0;
151    }
152
153    dump_partition_map(map, 1);
154
155    close_partition_map(map);
156
157    return 1;
158}
159
160
161void
162dump_block_zero(partition_map_header *map)
163{
164    Block0 *p;
165    DDMap *m;
166    int i;
167    double value;
168    int prefix;
169    long t;
170
171    p = map->misc;
172    if (p->sbSig != BLOCK0_SIGNATURE) {
173	return;
174    }
175
176    value = ((double)p->sbBlkCount) * p->sbBlkSize;
177    adjust_value_and_compute_prefix(&value, &prefix);
178    printf("\nDevice block size=%u, Number of Blocks=%u (%1.1f%c)\n",
179	    p->sbBlkSize, p->sbBlkCount, value, prefix);
180
181    printf("DeviceType=0x%x, DeviceId=0x%x\n",
182	    p->sbDevType, p->sbDevId);
183    if (p->sbDrvrCount > 0) {
184	printf("Drivers-\n");
185	m = (DDMap *) p->sbMap;
186	for (i = 0; i < p->sbDrvrCount; i++) {
187	    printf("%u: %3u @ %u, ", i+1,
188		    m[i].ddSize, get_align_long(&m[i].ddBlock));
189	    if (map->logical_block != p->sbBlkSize) {
190		t = (m[i].ddSize * p->sbBlkSize) / map->logical_block;
191		printf("(%lu@", t);
192		t = (get_align_long(&m[i].ddBlock) * p->sbBlkSize)
193			/ map->logical_block;
194		printf("%lu)  ", t);
195	    }
196	    printf("type=0x%x\n", m[i].ddType);
197	}
198    }
199    printf("\n");
200}
201
202
203void
204dump_partition_map(partition_map_header *map, int disk_order)
205{
206    partition_map * entry;
207    int max_type_length;
208    int max_name_length;
209    int digits;
210    char *alternate;
211
212    if (map == NULL) {
213	bad_input("No partition map exists");
214	return;
215    }
216    alternate = get_linux_name(map->name);
217    if (alternate) {
218	printf("\nPartition map (with %d byte blocks) on '%s' (%s)\n",
219		map->logical_block, map->name, alternate);
220	free(alternate);
221    } else {
222	printf("\nPartition map (with %d byte blocks) on '%s'\n",
223		map->logical_block, map->name);
224    }
225
226    digits = number_of_digits(get_max_base_or_length(map));
227    if (digits < 6) {
228	digits = 6;
229    }
230    if (aflag) {
231	max_type_length = 4;
232    } else {
233	max_type_length = get_max_type_string_length(map);
234	if (max_type_length < 4) {
235	    max_type_length = 4;
236	}
237    }
238    max_name_length = get_max_name_string_length(map);
239    if (max_name_length < 6) {
240	max_name_length = 6;
241    }
242    printf(" #: %*s %-*s %*s   %-*s ( size )\n",
243	    max_type_length, "type",
244	    max_name_length, "name",
245	    digits, "length", digits, "base");
246
247    if (disk_order) {
248	for (entry = map->disk_order; entry != NULL;
249		entry = entry->next_on_disk) {
250
251	    dump_partition_entry(entry, max_type_length, max_name_length, digits);
252	}
253    } else {
254	for (entry = map->base_order; entry != NULL;
255		entry = entry->next_by_base) {
256
257	    dump_partition_entry(entry, max_type_length, max_name_length, digits);
258	}
259    }
260    dump_block_zero(map);
261}
262
263
264void
265dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits)
266{
267    partition_map_header *map;
268    int j;
269    DPME *p;
270    const char *s;
271    u32 size;
272    double bytes;
273    int driver;
274    // int kind;
275    char *buf;
276#if 1
277    BZB *bp;
278#endif
279
280    map = entry->the_map;
281    p = entry->data;
282    driver = entry->contains_driver? '*': ' ';
283    if (aflag) {
284	s = "????";
285	for (j = 0; plist[j].abbr != 0; j++) {
286	    if (strcmp(p->dpme_type, plist[j].full) == 0) {
287		s = plist[j].abbr;
288		break;
289	    }
290	}
291	printf("%2ld: %.4s", entry->disk_address, s);
292    } else {
293	printf("%2ld: %*.32s", entry->disk_address, type_length, p->dpme_type);
294    }
295
296    buf = (char *) malloc(name_length+1);
297    if (entry->HFS_name == NULL || fflag == 0) {
298	strncpy(buf, p->dpme_name, name_length);
299	buf[name_length] = 0;
300    } else {
301	snprintf(buf, name_length + 1, "\"%s\"", entry->HFS_name);
302    }
303    printf("%c%-*.32s ", driver, name_length, buf);
304    free(buf);
305    /*
306    switch (entry->HFS_kind) {
307    case kHFS_std:	kind = 'h'; break;
308    case kHFS_embed:	kind = 'e'; break;
309    case kHFS_plus:	kind = '+'; break;
310    default:
311    case kHFS_not:	kind = ' '; break;
312    }
313    printf("%c ", kind);
314    */
315
316    if (pflag) {
317	printf("%*u ", digits, p->dpme_pblocks);
318	size = p->dpme_pblocks;
319    } else if (p->dpme_lblocks + p->dpme_lblock_start != p->dpme_pblocks) {
320	printf("%*u+", digits, p->dpme_lblocks);
321	size = p->dpme_lblocks;
322    } else if (p->dpme_lblock_start != 0) {
323	printf("%*u ", digits, p->dpme_lblocks);
324	size = p->dpme_lblocks;
325    } else {
326	printf("%*u ", digits, p->dpme_pblocks);
327	size = p->dpme_pblocks;
328    }
329    if (pflag || p->dpme_lblock_start == 0) {
330	printf("@ %-*u", digits, p->dpme_pblock_start);
331    } else {
332	printf("@~%-*u", digits, p->dpme_pblock_start + p->dpme_lblock_start);
333    }
334
335    bytes = ((double)size) * map->logical_block;
336    adjust_value_and_compute_prefix(&bytes, &j);
337    if (j != ' ' && j != 'K') {
338	printf(" (%#5.1f%c)", bytes, j);
339    }
340
341#if 1
342    // Old A/UX fields that no one pays attention to anymore.
343    bp = (BZB *) (p->dpme_bzb);
344    j = -1;
345    if (bp->bzb_magic == BZBMAGIC) {
346	switch (bp->bzb_type) {
347	case FSTEFS:
348	    s = "EFS";
349	    break;
350	case FSTSFS:
351	    s = "SFS";
352	    j = 1;
353	    break;
354	case FST:
355	default:
356	    if (bzb_root_get(bp) != 0) {
357		if (bzb_usr_get(bp) != 0) {
358		    s = "RUFS";
359		} else {
360		    s = "RFS";
361		}
362		j = 0;
363	    } else if (bzb_usr_get(bp) != 0) {
364		s = "UFS";
365		j = 2;
366	    } else {
367		s = "FS";
368	    }
369	    break;
370	}
371	if (bzb_slice_get(bp) != 0) {
372	    printf(" s%1d %4s", bzb_slice_get(bp)-1, s);
373	} else if (j >= 0) {
374	    printf(" S%1d %4s", j, s);
375	} else {
376	    printf("    %4s", s);
377	}
378	if (bzb_crit_get(bp) != 0) {
379	    printf(" K%1d", bp->bzb_cluster);
380	} else if (j < 0) {
381	    printf("   ");
382	} else {
383	    printf(" k%1d", bp->bzb_cluster);
384	}
385	if (bp->bzb_mount_point[0] != 0) {
386	    printf("  %.64s", bp->bzb_mount_point);
387	}
388    }
389#endif
390    printf("\n");
391}
392
393
394void
395list_all_disks()
396{
397#ifdef __APPLE__
398  char name[20] = "/dev/r";
399    MEDIA m;
400    DPME * data;
401    CFMutableDictionaryRef matching = NULL;
402    kern_return_t ret;
403    io_iterator_t iterator;
404    io_service_t media;
405
406    data = (DPME *) malloc(PBLOCK_SIZE);
407    if (data == NULL) {
408	error(errno, "can't allocate memory for try buffer");
409	return;
410    }
411
412    matching = IOServiceMatching(kIOMediaClass);
413    CFDictionaryAddValue(matching, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
414
415    ret = IOServiceGetMatchingServices(kIOMasterPortDefault,
416				       matching,
417				       &iterator);
418
419    if(ret != KERN_SUCCESS) {
420      free(data);
421      return;
422    }
423
424    while((media = IOIteratorNext(iterator))) {
425      CFStringRef blockdev;
426
427      blockdev = IORegistryEntryCreateCFProperty(media,
428						 CFSTR(kIOBSDNameKey),
429						 kCFAllocatorDefault,
430						 0);
431      if(blockdev) {
432
433	if(CFStringGetCString(blockdev, name+sizeof("/dev/r")-1,
434			      sizeof(name)-sizeof("/dev/r")+1,
435			      kCFStringEncodingUTF8)) {
436
437	  if ((m = open_pathname_as_media(name, O_RDONLY)) == 0) {
438	    error(errno, "can't open file '%s'", name);
439	  } else {
440	    close_media(m);
441	  }
442	  dump(name);
443	}
444	CFRelease(blockdev);
445      }
446      IOObjectRelease(media);
447    }
448
449    IOObjectRelease(iterator);
450
451    free(data);
452#else
453    MEDIA_ITERATOR iter;
454    MEDIA m;
455    DPME * data;
456    char *name;
457    long mark;
458
459    data = (DPME *) malloc(PBLOCK_SIZE);
460    if (data == NULL) {
461	error(errno, "can't allocate memory for try buffer");
462	return;
463    }
464
465    for (iter = first_media_kind(&mark); iter != 0; iter = next_media_kind(&mark)) {
466
467    	while ((name = step_media_iterator(iter)) != 0) {
468
469	    if ((m = open_pathname_as_media(name, O_RDONLY)) == 0) {
470#if defined(__linux__) || defined(__unix__)
471		error(errno, "can't open file '%s'", name);
472#endif
473	    } else {
474		close_media(m);
475
476		dump(name);
477	    }
478	    free(name);
479	}
480
481	delete_media_iterator(iter);
482    }
483
484    free(data);
485#endif
486}
487
488
489void
490show_data_structures(partition_map_header *map)
491{
492    Block0 *zp;
493    DDMap *m;
494    int i;
495    int j;
496    partition_map * entry;
497    DPME *p;
498    BZB *bp;
499    const char *s;
500
501    if (map == NULL) {
502	printf("No partition map exists\n");
503	return;
504    }
505    printf("Header:\n");
506    printf("map %d blocks out of %d,  media %lu blocks (%d byte blocks)\n",
507	    map->blocks_in_map, map->maximum_in_map,
508	    map->media_size, map->logical_block);
509    printf("Map is%s writable", (map->writable)?kStringEmpty:kStringNot);
510    printf(", but%s changed", (map->changed)?kStringEmpty:kStringNot);
511    printf(" and has%s been written\n", (map->written)?kStringEmpty:kStringNot);
512    printf("\n");
513
514    if (map->misc == NULL) {
515	printf("No block zero\n");
516    } else {
517	zp = map->misc;
518
519	printf("Block0:\n");
520	printf("signature 0x%x", zp->sbSig);
521	if (zp->sbSig == BLOCK0_SIGNATURE) {
522	    printf("\n");
523	} else {
524	    printf(" should be 0x%x\n", BLOCK0_SIGNATURE);
525	}
526	printf("Block size=%u, Number of Blocks=%u\n",
527		zp->sbBlkSize, zp->sbBlkCount);
528	printf("DeviceType=0x%x, DeviceId=0x%x, sbData=0x%x\n",
529		zp->sbDevType, zp->sbDevId, zp->sbData);
530	if (zp->sbDrvrCount == 0) {
531	    printf("No drivers\n");
532	} else {
533	    printf("%u driver%s-\n", zp->sbDrvrCount,
534		    (zp->sbDrvrCount>1)?"s":kStringEmpty);
535	    m = (DDMap *) zp->sbMap;
536	    for (i = 0; i < zp->sbDrvrCount; i++) {
537            printf("%u: @ %u for %u, type=0x%x\n", i+1,
538		   get_align_long(&m[i].ddBlock),
539		   m[i].ddSize, m[i].ddType);
540	    }
541	}
542    }
543    printf("\n");
544
545/*
546u32     dpme_boot_args[32]      ;
547u32     dpme_reserved_3[62]     ;
548*/
549    printf(" #:                 type  length   base    "
550	    "flags        (logical)\n");
551    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
552	p = entry->data;
553	printf("%2ld: %20.32s ",
554		entry->disk_address, p->dpme_type);
555	printf("%7u @ %-7u ", p->dpme_pblocks, p->dpme_pblock_start);
556	printf("%c%c%c%c%c%c%c%c%c%c%c%c ",
557		(dpme_valid_get(p))?'V':'.',
558		(dpme_allocated_get(p))?'A':'.',
559		(dpme_in_use_get(p))?'I':'.',
560		(dpme_bootable_get(p))?'B':'.',
561		(dpme_readable_get(p))?'R':'.',
562		(dpme_writable_get(p))?'W':'.',
563		(dpme_os_pic_code_get(p))?'P':'.',
564		(dpme_os_specific_2_get(p))?'2':'.',
565		(dpme_chainable_get(p))?'C':'.',
566		(dpme_diskdriver_get(p))?'D':'.',
567		(bitfield_get(p->dpme_flags, 30, 1))?'M':'.',
568		(bitfield_get(p->dpme_flags, 31, 1))?'X':'.');
569	if (p->dpme_lblock_start != 0 || p->dpme_pblocks != p->dpme_lblocks) {
570	    printf("(%u @ %u)", p->dpme_lblocks, p->dpme_lblock_start);
571	}
572	printf("\n");
573    }
574    printf("\n");
575    printf(" #:  booter   bytes      load_address      "
576	    "goto_address checksum processor\n");
577    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
578	p = entry->data;
579	printf("%2ld: ", entry->disk_address);
580	printf("%7u ", p->dpme_boot_block);
581	printf("%7u ", p->dpme_boot_bytes);
582	printf("%8x ", (u32)p->dpme_load_addr);
583	printf("%8x ", (u32)p->dpme_load_addr_2);
584	printf("%8x ", (u32)p->dpme_goto_addr);
585	printf("%8x ", (u32)p->dpme_goto_addr_2);
586	printf("%8x ", p->dpme_checksum);
587	printf("%.32s", p->dpme_process_id);
588	printf("\n");
589    }
590    printf("\n");
591/*
592xx: cccc RU *dd s...
593*/
594    printf(" #: type RU *slice mount_point (A/UX only fields)\n");
595    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
596	p = entry->data;
597	printf("%2ld: ", entry->disk_address);
598
599	bp = (BZB *) (p->dpme_bzb);
600	j = -1;
601	if (bp->bzb_magic == BZBMAGIC) {
602	    switch (bp->bzb_type) {
603	    case FSTEFS:
604		s = "esch";
605		break;
606	    case FSTSFS:
607		s = "swap";
608		j = 1;
609		break;
610	    case FST:
611	    default:
612		s = "fsys";
613		if (bzb_root_get(bp) != 0) {
614		    j = 0;
615		} else if (bzb_usr_get(bp) != 0) {
616		    j = 2;
617		}
618		break;
619	    }
620	    printf("%4s ", s);
621	    printf("%c%c ",
622		    (bzb_root_get(bp))?'R':' ',
623		    (bzb_usr_get(bp))?'U':' ');
624	    if (bzb_slice_get(bp) != 0) {
625		printf("  %2d", bzb_slice_get(bp)-1);
626	    } else if (j >= 0) {
627		printf(" *%2d", j);
628	    } else {
629		printf("    ");
630	    }
631	    if (bp->bzb_mount_point[0] != 0) {
632		printf(" %.64s", bp->bzb_mount_point);
633	    }
634	}
635	printf("\n");
636    }
637}
638
639
640void
641full_dump_partition_entry(partition_map_header *map, int ix)
642{
643    partition_map * cur;
644    DPME *p;
645    int i;
646    u32 t;
647
648    cur = find_entry_by_disk_address(ix, map);
649    if (cur == NULL) {
650	printf("No such partition\n");
651	return;
652    }
653
654    p = cur->data;
655    printf("             signature: 0x%x\n", p->dpme_signature);
656    printf("             reserved1: 0x%x\n", p->dpme_reserved_1);
657    printf(" number of map entries: %d\n", p->dpme_map_entries);
658    printf("        physical start: %10u  length: %10u\n", p->dpme_pblock_start, p->dpme_pblocks);
659    printf("         logical start: %10u  length: %10u\n", p->dpme_lblock_start, p->dpme_lblocks);
660
661    printf("                 flags: 0x%x\n", (u32)p->dpme_flags);
662    printf("                        ");
663    if (dpme_valid_get(p)) printf("valid ");
664    if (dpme_allocated_get(p)) printf("alloc ");
665    if (dpme_in_use_get(p)) printf("in-use ");
666    if (dpme_bootable_get(p)) printf("boot ");
667    if (dpme_readable_get(p)) printf("read ");
668    if (dpme_writable_get(p)) printf("write ");
669    if (dpme_os_pic_code_get(p)) printf("pic ");
670    t = p->dpme_flags >> 7;
671    for (i = 7; i <= 31; i++) {
672    	if (t & 0x1) {
673    	    printf("%d ", i);
674    	}
675    	t = t >> 1;
676    }
677    printf("\n");
678
679    printf("                  name: '%.32s'\n", p->dpme_name);
680    printf("                  type: '%.32s'\n", p->dpme_type);
681
682    printf("      boot start block: %10u\n", p->dpme_boot_block);
683    printf("boot length (in bytes): %10u\n", p->dpme_boot_bytes);
684    printf("          load address: 0x%08x  0x%08x\n",
685		(u32)p->dpme_load_addr, (u32)p->dpme_load_addr_2);
686    printf("         start address: 0x%08x  0x%08x\n",
687		(u32)p->dpme_goto_addr, (u32)p->dpme_goto_addr_2);
688    printf("              checksum: 0x%08x\n", p->dpme_checksum);
689    printf("             processor: '%.32s'\n", p->dpme_process_id);
690    printf("boot args field -");
691    dump_block((unsigned char *)p->dpme_boot_args, 32*4);
692    printf("dpme_reserved_3 -");
693    dump_block((unsigned char *)p->dpme_reserved_3, 62*4);
694}
695
696
697void
698dump_block(unsigned char *addr, int len)
699{
700    int i;
701    int j;
702    int limit1;
703    int limit;
704#define LINE_LEN 16
705#define UNIT_LEN  4
706#define OTHER_LEN  8
707
708    for (i = 0; i < len; i = limit) {
709    	limit1 = i + LINE_LEN;
710    	if (limit1 > len) {
711    	    limit = len;
712    	} else {
713    	    limit = limit1;
714    	}
715	printf("\n%03x: ", i);
716    	for (j = i; j < limit1; j++) {
717	    if (j % UNIT_LEN == 0) {
718		printf(" ");
719	    }
720	    if (j < limit) {
721		printf("%02x", addr[j]);
722	    } else {
723		printf("  ");
724	    }
725    	}
726	printf(" ");
727    	for (j = i; j < limit; j++) {
728	    if (j % OTHER_LEN == 0) {
729		printf(" ");
730	    }
731    	    if (addr[j] < ' ') {
732    	    	printf(".");
733    	    } else {
734    	    	printf("%c", addr[j]);
735    	    }
736    	}
737    }
738    printf("\n");
739}
740
741void
742full_dump_block_zero(partition_map_header *map)
743{
744    Block0 *zp;
745    DDMap *m;
746    int i;
747
748    if (map == NULL) {
749	printf("No partition map exists\n");
750	return;
751    }
752
753    if (map->misc == NULL) {
754	printf("No block zero\n");
755	return;
756    }
757    zp = map->misc;
758
759    printf("             signature: 0x%x\n", zp->sbSig);
760    printf("       size of a block: %d\n", zp->sbBlkSize);
761    printf("      number of blocks: %d\n", zp->sbBlkCount);
762    printf("           device type: 0x%x\n", zp->sbDevType);
763    printf("             device id: 0x%x\n", zp->sbDevId);
764    printf("                  data: 0x%x\n", zp->sbData);
765    printf("          driver count: %d\n", zp->sbDrvrCount);
766    m = (DDMap *) zp->sbMap;
767    for (i = 0; &m[i].ddType < &zp->sbMap[247]; i++) {
768    	if (m[i].ddBlock == 0 && m[i].ddSize == 0 && m[i].ddType == 0) {
769    	    break;
770    	}
771	printf("      driver %3u block: %d\n", i+1, m[i].ddBlock);
772	printf("        size in blocks: %d\n", m[i].ddSize);
773	printf("           driver type: 0x%x\n", m[i].ddType);
774    }
775    printf("remainder of block -");
776    dump_block((unsigned char *)(void *)&m[i].ddBlock, (&zp->sbMap[247]-((unsigned short *)(void *)&m[i].ddBlock))*2);
777}
778
779
780void
781display_patches(partition_map *entry)
782{
783    long long offset;
784    MEDIA m;
785    static unsigned char *patch_block;
786    PatchListPtr p;
787    PatchDescriptorPtr q;
788    unsigned char *next;
789    unsigned char *s;
790    int i;
791
792    offset = entry->data->dpme_pblock_start;
793    m = entry->the_map->m;
794    offset = ((long long) entry->data->dpme_pblock_start) * entry->the_map->logical_block;
795    if (patch_block == NULL) {
796	patch_block = (unsigned char *) malloc(PBLOCK_SIZE);
797	if (patch_block == NULL) {
798	    error(errno, "can't allocate memory for patch block buffer");
799	    return;
800	}
801    }
802    if (read_media(m, (long long)offset, PBLOCK_SIZE, (char *)patch_block) == 0) {
803	error(errno, "Can't read patch block");
804	return;
805    }
806    p = (PatchListPtr) patch_block;
807    if (p->numPatchBlocks != 1) {
808	i = p->numPatchBlocks;
809	free(patch_block);
810	patch_block = (unsigned char *) malloc(PBLOCK_SIZE*i);
811	if (patch_block == NULL) {
812	    error(errno, "can't allocate memory for patch blocks buffer");
813	    return;
814	}
815	s = patch_block + PBLOCK_SIZE*i;
816	while (i > 0) {
817	    s -= PBLOCK_SIZE;
818	    i -= 1;
819	    if (read_media(m, offset+i, PBLOCK_SIZE, (char *)s) == 0) {
820		error(errno, "Can't read patch block %d", i);
821		return;
822	    }
823	}
824	p = (PatchListPtr) patch_block;
825    }
826    printf("Patch list (%d entries)\n", p->numPatches);
827    q = p->thePatch;
828    for (i = 0; i < p->numPatches; i++) {
829	printf("%2d signature: '%.4s'\n", i+1, (char *)&q->patchSig);
830	printf("     version: %d.%d\n", q->majorVers, q->minorVers);
831	printf("       flags: 0x%lx\n", q->flags);
832	printf("      offset: %ld\n", q->patchOffset);
833	printf("        size: %ld\n", q->patchSize);
834	printf("         CRC: 0x%lx\n", q->patchCRC);
835	printf("        name: '%.*s'\n", q->patchName[0], &q->patchName[1]);
836	printf("      vendor: '%.*s'\n", q->patchVendor[0], &q->patchVendor[1]);
837	next = ((unsigned char *)q) + q->patchDescriptorLen;
838	s = &q->patchVendor[q->patchVendor[0]+1];
839	if (next > s) {
840	    printf("remainder of entry -");
841	    dump_block(s, next-s);
842	}
843	q = (PatchDescriptorPtr)next;
844    }
845}
846
847int
848get_max_type_string_length(partition_map_header *map)
849{
850    partition_map * entry;
851    int max;
852    int length;
853
854    if (map == NULL) {
855	return 0;
856    }
857
858    max = 0;
859
860    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
861	length = strnlen(entry->data->dpme_type, DPISTRLEN);
862	if (length > max) {
863	    max = length;
864	}
865    }
866
867    return max;
868}
869
870int
871get_max_name_string_length(partition_map_header *map)
872{
873    partition_map * entry;
874    int max;
875    int length;
876
877    if (map == NULL) {
878	return 0;
879    }
880
881    max = 0;
882
883    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
884	length = strnlen(entry->data->dpme_name, DPISTRLEN);
885	if (length > max) {
886	    max = length;
887	}
888
889	if (fflag) {
890		if (entry->HFS_name == NULL) {
891		    length = 0;
892		} else {
893		    length = strlen(entry->HFS_name) + 2;
894		}
895		if (length > max) {
896		    max = length;
897		}
898	}
899    }
900
901    return max;
902}
903
904int
905get_max_base_or_length(partition_map_header *map)
906{
907    partition_map * entry;
908    unsigned int max;
909
910    if (map == NULL) {
911	return 0;
912    }
913
914    max = 0;
915
916    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
917	if (entry->data->dpme_pblock_start > max) {
918	    max = entry->data->dpme_pblock_start;
919	}
920	if (entry->data->dpme_pblocks > max) {
921	    max = entry->data->dpme_pblocks;
922	}
923	if (entry->data->dpme_lblock_start > max) {
924	    max = entry->data->dpme_lblock_start;
925	}
926	if (entry->data->dpme_lblocks > max) {
927	    max = entry->data->dpme_lblocks;
928	}
929    }
930
931    return max;
932}
933
934void
935adjust_value_and_compute_prefix(double *value, int *prefix)
936{
937    double bytes;
938    int multiplier;
939
940    bytes = *value;
941    if (bytes < 1024.0) {
942	multiplier = ' ';
943    } else {
944	bytes = bytes / 1024.0;
945	if (bytes < 1024.0) {
946	    multiplier = 'K';
947	} else {
948	    bytes = bytes / 1024.0;
949	    if (bytes < 1024.0) {
950		multiplier = 'M';
951	    } else {
952		bytes = bytes / 1024.0;
953		if (bytes < 1024.0) {
954		    multiplier = 'G';
955		} else {
956		    bytes = bytes / 1024.0;
957		    multiplier = 'T';
958		}
959	    }
960	}
961    }
962    *value = bytes;
963    *prefix = multiplier;
964}
965