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