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