xref: /openbsd/sbin/pdisk/partition_map.c (revision ddc1a6c2)
1 /*	$OpenBSD: partition_map.c,v 1.99 2019/07/31 00:14:10 krw Exp $	*/
2 
3 /*
4  * partition_map.c - partition map routines
5  *
6  * Written by Eryk Vershen
7  */
8 
9 /*
10  * Copyright 1996,1997,1998 by Apple Computer, Inc.
11  *              All Rights Reserved
12  *
13  * Permission to use, copy, modify, and distribute this software and
14  * its documentation for any purpose and without fee is hereby granted,
15  * provided that the above copyright notice appears in all copies and
16  * that both the copyright notice and this permission notice appear in
17  * supporting documentation.
18  *
19  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
20  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE.
22  *
23  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
26  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
27  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 #include <sys/queue.h>
31 #include <sys/stdint.h>
32 
33 #include <err.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "partition_map.h"
39 #include "io.h"
40 #include "file_media.h"
41 
42 #define APPLE_HFS_FLAGS_VALUE	0x4000037f
43 
44 const char     *kFreeType = "Apple_Free";
45 const char     *kMapType = "Apple_partition_map";
46 const char     *kUnixType = "OpenBSD";
47 const char     *kHFSType = "Apple_HFS";
48 
49 void		combine_entry(struct entry *);
50 struct entry   *create_entry(struct partition_map *, long, const char *,
51     const char *, uint32_t, uint32_t);
52 void		delete_entry(struct entry *);
53 void		insert_in_base_order(struct entry *);
54 void		insert_in_disk_order(struct entry *);
55 int		read_partition_map(struct partition_map *);
56 void		remove_driver(struct entry *);
57 void		renumber_disk_addresses(struct partition_map *);
58 
59 struct partition_map *
open_partition_map(int fd,char * name,uint64_t mediasz,uint32_t sectorsz)60 open_partition_map(int fd, char *name, uint64_t mediasz, uint32_t sectorsz)
61 {
62 	struct partition_map *map;
63 	int ok;
64 
65 	map = malloc(sizeof(struct partition_map));
66 	if (map == NULL)
67 		errx(1, "No memory to open partition map");
68 
69 	map->fd = fd;
70 	map->name = name;
71 
72 	map->changed = 0;
73 	LIST_INIT(&map->disk_order);
74 	LIST_INIT(&map->base_order);
75 	map->blocks_in_map = 0;
76 	map->maximum_in_map = -1;
77 
78 	if (mediasz > UINT32_MAX)
79 		map->media_size = UINT32_MAX;
80 	else
81 		map->media_size = mediasz;
82 
83 	if (read_block0(map->fd, map) == 0) {
84 		warnx("Can't read block 0 from '%s'", name);
85 		free_partition_map(map);
86 		return NULL;
87 	}
88 	if (map->sbSig == BLOCK0_SIGNATURE &&
89 	    map->sbBlkSize == sectorsz &&
90 	    map->sbBlkCount <= mediasz) {
91 		if (read_partition_map(map) == 0)
92 			return map;
93 	} else {
94 		if (map->sbSig != BLOCK0_SIGNATURE)
95 			warnx("Block 0 signature: Expected 0x%04x, "
96 			    "got 0x%04x", BLOCK0_SIGNATURE,
97 			    map->sbSig);
98 		else if (map->sbBlkSize != sectorsz)
99 			warnx("Block 0 sbBlkSize (%u) != sector size (%u)",
100 			    map->sbBlkSize, sectorsz);
101 		else if (map->sbBlkCount > mediasz)
102 			warnx("Block 0 sbBlkCount (%u) > media size (%llu)",
103 			    map->sbBlkCount,
104 			    (unsigned long long)mediasz);
105 	}
106 
107 	if (!lflag) {
108 		my_ungetch('\n');
109 		printf("No valid partition map found on '%s'.\n", name);
110 		ok = get_okay("Create default map? [n/y]: ", 0);
111 		flush_to_newline(0);
112 		if (ok == 1) {
113 			free_partition_map(map);
114 			map = create_partition_map(fd, name, mediasz, sectorsz);
115 			if (map)
116 				return map;
117 		}
118 	}
119 
120 	free_partition_map(map);
121 	return NULL;
122 }
123 
124 
125 void
free_partition_map(struct partition_map * map)126 free_partition_map(struct partition_map *map)
127 {
128 	struct entry *entry;
129 
130 	if (map == NULL)
131 		return;
132 
133 	while (!LIST_EMPTY(&map->disk_order)) {
134 		entry = LIST_FIRST(&map->disk_order);
135 		LIST_REMOVE(entry, disk_entry);
136 		free(entry);
137 	}
138 
139 	free(map);
140 }
141 
142 int
read_partition_map(struct partition_map * map)143 read_partition_map(struct partition_map *map)
144 {
145 	struct entry *cur, *nextcur;
146 	struct entry *entry;
147 	int ix;
148 	uint32_t limit, base, next, nextbase;
149 
150 	limit = 1; /* There has to be at least one, which has the real limit. */
151 	for (ix = 1; ix <= limit; ix++) {
152 		entry = malloc(sizeof(struct entry));
153 		if (entry == NULL)
154 			errx(1, "No memory for partition entry");
155 		if (read_dpme(map->fd, ix, entry) == 0) {
156 			warnx("Can't read block %u from '%s'", ix, map->name);
157 			free(entry);
158 			return 1;
159 		}
160 		if (entry->dpme_signature != DPME_SIGNATURE) {
161 			warnx("Invalid signature on block %d. Expected %x, "
162 			    "got %x", ix, DPME_SIGNATURE,
163 			    entry->dpme_signature);
164 			free(entry);
165 			return 1;
166 		}
167 		if (ix == 1) {
168 			if (entry->dpme_map_entries > entry->dpme_pblocks) {
169 				warnx("Map entry count (%u) > # of physical "
170 				    "blocks (%u)", entry->dpme_map_entries,
171 				    entry->dpme_pblocks);
172 				free(entry);
173 				return 1;
174 			}
175 			if (entry->dpme_map_entries == 0) {
176 				warnx("Map entry count ==  0. Must be > 0");
177 				free(entry);
178 				return 1;
179 			}
180 			map->maximum_in_map = entry->dpme_pblocks;
181 			limit = entry->dpme_map_entries;
182 		}
183 		if (limit != entry->dpme_map_entries) {
184 			warnx("Invalid entry count on block %d. "
185 			    "Expected %d, got %d", ix, limit,
186 			    entry->dpme_map_entries);
187 			free(entry);
188 			return 1;
189 		}
190 		if (entry->dpme_lblock_start >= entry->dpme_pblocks) {
191 			warnx("\tlogical start (%u) >= block count"
192 			    "count (%u).", entry->dpme_lblock_start,
193 			    entry->dpme_pblocks);
194 			free(entry);
195 			return 1;
196 		}
197 		if (entry->dpme_lblocks > entry->dpme_pblocks -
198 			entry->dpme_lblock_start) {
199 			warnx("\tlogical blocks (%u) > available blocks (%u).",
200 			    entry->dpme_lblocks,
201 			    entry->dpme_pblocks - entry->dpme_lblock_start);
202 			free(entry);
203 			return 1;
204 		}
205 		entry->the_map = map;
206 		entry->disk_address = ix;
207 		insert_in_disk_order(entry);
208 		insert_in_base_order(entry);
209 		map->blocks_in_map++;
210 	}
211 
212 	/* Traverse base_order looking for
213 	 *
214 	 * 1) Overlapping partitions
215 	 * 2) Unmapped space
216 	 */
217 	LIST_FOREACH(cur, &map->base_order, base_entry) {
218 		base = cur->dpme_pblock_start;
219 		next = base + cur->dpme_pblocks;
220 		if (base >= map->media_size ||
221 		    next < base ||
222 		    next > map->media_size) {
223 			warnx("Partition extends past end of disk: %u -> %u",
224 			    base, next);
225 		}
226 		nextcur = LIST_NEXT(cur, base_entry);
227 		if (nextcur)
228 			nextbase = nextcur->dpme_pblock_start;
229 		else
230 			nextbase = map->media_size;
231 		if (next != nextbase)
232 			warnx("Unmapped pblocks: %u -> %u", next, nextbase);
233 		if (next > nextbase)
234 			warnx("Partition %ld overlaps next partition",
235 			    cur->disk_address);
236 	}
237 
238 	return 0;
239 }
240 
241 
242 void
write_partition_map(struct partition_map * map)243 write_partition_map(struct partition_map *map)
244 {
245 	struct entry *entry;
246 	int result;
247 
248 	result = write_block0(map->fd, map);
249 	if (result == 0)
250 		warn("Unable to write block zero");
251 
252 	LIST_FOREACH(entry, &map->disk_order, disk_entry) {
253 		result = write_dpme(map->fd, entry->disk_address, entry);
254 		if (result == 0)
255 			warn("Unable to write block %ld", entry->disk_address);
256 	}
257 }
258 
259 
260 struct partition_map *
create_partition_map(int fd,char * name,u_int64_t mediasz,uint32_t sectorsz)261 create_partition_map(int fd, char *name, u_int64_t mediasz, uint32_t sectorsz)
262 {
263 	struct partition_map *map;
264 	struct entry *entry;
265 
266 	map = malloc(sizeof(struct partition_map));
267 	if (map == NULL)
268 		errx(1, "No memory to create partition map");
269 
270 	map->name = name;
271 	map->fd = fd;
272 	map->changed = 1;
273 	LIST_INIT(&map->disk_order);
274 	LIST_INIT(&map->base_order);
275 
276 	map->blocks_in_map = 0;
277 	map->maximum_in_map = -1;
278 	map->media_size = mediasz;
279 
280 	map->sbSig = BLOCK0_SIGNATURE;
281 	map->sbBlkSize = sectorsz;
282 	map->sbBlkCount = map->media_size;
283 
284 	entry = create_entry(map, 1, "", kFreeType, 1, mediasz - 1);
285 	if (entry == NULL)
286 		errx(1, "No memory for new dpme");
287 
288 	add_partition_to_map("Apple", kMapType, 1,
289 	    (map->media_size <= 128 ? 2 : 63), map);
290 
291 	return map;
292 }
293 
294 
295 int
add_partition_to_map(const char * name,const char * dptype,uint32_t base,uint32_t length,struct partition_map * map)296 add_partition_to_map(const char *name, const char *dptype, uint32_t base,
297     uint32_t length, struct partition_map *map)
298 {
299 	struct entry *cur;
300 	int limit, new_entries;
301 	uint32_t old_base, old_length, old_address;
302 	uint32_t new_base, new_length;
303 
304 	if (map->maximum_in_map < 0)
305 		limit = map->media_size;
306 	else
307 		limit = map->maximum_in_map;
308 
309 	/* find a block of free space that starts includes base and length */
310 	LIST_FOREACH(cur, &map->base_order, base_entry) {
311 		if (strncasecmp(cur->dpme_type, kFreeType, DPISTRLEN))
312 		    continue;
313 		if (cur->dpme_pblock_start <= base &&
314 		    (base + length) <=
315 		    (cur->dpme_pblock_start + cur->dpme_pblocks))
316 			break;
317 	}
318 	if (cur == NULL) {
319 		printf("requested base and length is not "
320 		       "within an existing free partition\n");
321 		return 0;
322 	}
323 	old_base = cur->dpme_pblock_start;
324 	old_length = cur->dpme_pblocks;
325 	old_address = cur->disk_address;
326 
327 	/* Check that there is enough room in the map for the new entries! */
328 	if (base == old_base && length == old_length)
329 		new_entries = 0;
330 	else if (base == old_base)
331 		new_entries = 1;
332 	else if (base - old_base < old_length - length)
333 		new_entries = 2;
334 	else
335 		new_entries = 1;
336 	if (map->blocks_in_map + new_entries > limit) {
337 		printf("the map is not big enough\n");
338 		return 0;
339 	}
340 
341 	/*
342 	 * Delete old free entry from map and add back 1 to 3 new entries.
343 	 *
344 	 * 1) Empty space from base+len to old end.
345 	 * 2) New entry from specified base for length.
346 	 * 3) Empty space from old base to new base.
347 	 *
348 	 *  All with the same disk address, so they must be added in that
349 	 *  order!
350 	 */
351 	delete_entry(cur);
352 
353 	new_base = base + length;
354 	new_length = (old_base + old_length) - new_base;
355 	if (new_length > 0) {
356 		/* New free space entry *after* new partition. */
357 		cur = create_entry(map, old_address, "", kFreeType, new_base,
358 		    new_length);
359 		if (cur == NULL)
360 			errx(1, "No memory for new dpme");
361 	}
362 
363 	cur = create_entry(map, old_address, name, dptype, base, length);
364 	if (cur == NULL)
365 		errx(1, "No memory for new entry");
366 
367 	new_length = base - old_base;
368 	if (new_length > 0) {
369 		/* New free space entry *before* new partition. */
370 		cur = create_entry(map, old_address, "", kFreeType, old_base,
371 		    new_length);
372 		if (cur == NULL)
373 			errx(1, "No memory for new entry");
374 	}
375 
376 	renumber_disk_addresses(map);
377 	map->changed = 1;
378 	return 1;
379 }
380 
381 
382 struct entry*
create_entry(struct partition_map * map,long ix,const char * name,const char * dptype,uint32_t base,uint32_t length)383 create_entry(struct partition_map *map, long ix, const char *name,
384     const char *dptype, uint32_t base, uint32_t length)
385 {
386 	struct entry *entry;
387 
388 	entry = calloc(1, sizeof(struct entry));
389 	if (entry == NULL)
390 		errx(1, "No memory for new entry");
391 
392 	entry->dpme_signature = DPME_SIGNATURE;
393 	entry->dpme_map_entries = 1;
394 	entry->dpme_pblock_start = base;
395 	entry->dpme_pblocks = length;
396 	strlcpy(entry->dpme_name, name, sizeof(entry->dpme_name));
397 	strlcpy(entry->dpme_type, dptype, sizeof(entry->dpme_type));
398 	if (strncasecmp(dptype, kFreeType, DPISTRLEN)) {
399 		/* Only non-kFreeType entries get lblock info != 0. */
400 		entry->dpme_lblocks = entry->dpme_pblocks;
401 	}
402 	dpme_init_flags(entry);
403 
404 	entry->disk_address = ix;
405 	entry->the_map = map;
406 
407 	insert_in_disk_order(entry);
408 	insert_in_base_order(entry);
409 
410 	map->blocks_in_map++;
411 	if (map->maximum_in_map < 0) {
412 		if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0)
413 			map->maximum_in_map = entry->dpme_pblocks;
414 	}
415 
416 	return entry;
417 }
418 
419 void
dpme_init_flags(struct entry * entry)420 dpme_init_flags(struct entry *entry)
421 {
422 	if (strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) == 0)
423 		entry->dpme_flags = 0;
424 	else if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0)
425 		entry->dpme_flags = DPME_VALID | DPME_ALLOCATED;
426 	else if (strncasecmp(entry->dpme_type, kHFSType, DPISTRLEN) == 0)
427 		entry->dpme_flags = APPLE_HFS_FLAGS_VALUE;
428 	else
429 		entry->dpme_flags = DPME_VALID | DPME_ALLOCATED |
430 		    DPME_READABLE | DPME_WRITABLE;
431 }
432 
433 void
renumber_disk_addresses(struct partition_map * map)434 renumber_disk_addresses(struct partition_map *map)
435 {
436 	struct entry *cur;
437 	long ix;
438 
439 	/* reset disk addresses */
440 	ix = 1;
441 	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
442 		cur->disk_address = ix++;
443 		cur->dpme_map_entries = map->blocks_in_map;
444 	}
445 }
446 
447 void
delete_partition_from_map(struct entry * entry)448 delete_partition_from_map(struct entry *entry)
449 {
450 	struct partition_map *map;
451 	uint32_t base, length, address;
452 
453 	if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0) {
454 		printf("Can't delete entry for the map itself\n");
455 		return;
456 	}
457 	if (strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) == 0) {
458 		printf("Can't delete entry for free space\n");
459 		return;
460 	}
461 	if (contains_driver(entry)) {
462 		printf("This program can't install drivers\n");
463 		if (get_okay("are you sure you want to delete this driver? "
464 		    "[n/y]: ", 0) != 1) {
465 			return;
466 		}
467 		remove_driver(entry);	/* update block0 if necessary */
468 	}
469 
470 	map = entry->the_map;
471 	base = entry->dpme_pblock_start;
472 	length = entry->dpme_pblocks;
473 	address = entry->disk_address;
474 
475 	delete_entry(entry);
476 	entry = create_entry(map, address, "" , kFreeType, base, length);
477 	combine_entry(entry);
478 	renumber_disk_addresses(entry->the_map);
479 	entry->the_map->changed = 1;
480 }
481 
482 
483 int
contains_driver(struct entry * entry)484 contains_driver(struct entry *entry)
485 {
486 	struct partition_map *map;
487 	struct ddmap *m;
488 	int i;
489 	uint32_t start;
490 
491 	map = entry->the_map;
492 	m = map->sbDDMap;
493 	for (i = 0; i < map->sbDrvrCount; i++) {
494 		start = m[i].ddBlock;
495 		if (entry->dpme_pblock_start <= start &&
496 		    (start + m[i].ddSize) <= (entry->dpme_pblock_start +
497 		    entry->dpme_pblocks))
498 			return 1;
499 	}
500 
501 	return 0;
502 }
503 
504 
505 void
combine_entry(struct entry * entry)506 combine_entry(struct entry *entry)
507 {
508 	struct entry *p;
509 	uint32_t end;
510 
511 	if (entry == NULL ||
512 	    strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) != 0)
513 		return;
514 
515 	p = LIST_NEXT(entry, base_entry);
516 	if (p != NULL) {
517 		if (strncasecmp(p->dpme_type, kFreeType, DPISTRLEN) !=
518 		    0) {
519 			/* next is not free */
520 		} else if (entry->dpme_pblock_start +
521 		    entry->dpme_pblocks != p->dpme_pblock_start) {
522 			/* next is not contiguous (XXX this is bad) */
523 			printf("next entry is not contiguous\n");
524 			/* start is already minimum */
525 			/* new end is maximum of two ends */
526 			end = p->dpme_pblock_start + p->dpme_pblocks;
527 			if (end > entry->dpme_pblock_start +
528 			    entry->dpme_pblocks) {
529 				entry->dpme_pblocks = end -
530 				    entry->dpme_pblock_start;
531 			}
532 			delete_entry(p);
533 		} else {
534 			entry->dpme_pblocks += p->dpme_pblocks;
535 			delete_entry(p);
536 		}
537 	}
538 
539 	LIST_FOREACH(p, &entry->the_map->base_order, base_entry) {
540 		if (LIST_NEXT(p, base_entry) == entry)
541 			break;
542 	}
543 	if (p != NULL) {
544 		if (strncasecmp(p->dpme_type, kFreeType, DPISTRLEN) != 0) {
545 			/* previous is not free */
546 		} else if (p->dpme_pblock_start + p->dpme_pblocks !=
547 		    entry->dpme_pblock_start) {
548 			/* previous is not contiguous (XXX this is bad) */
549 			printf("previous entry is not contiguous\n");
550 			/* new end is maximum of two ends */
551 			end = p->dpme_pblock_start + p->dpme_pblocks;
552 			if (end < entry->dpme_pblock_start +
553 			    entry->dpme_pblocks) {
554 				end = entry->dpme_pblock_start +
555 				    entry->dpme_pblocks;
556 			}
557 			entry->dpme_pblocks = end - p->dpme_pblock_start;
558 			entry->dpme_pblock_start = p->dpme_pblock_start;
559 			delete_entry(p);
560 		} else {
561 			entry->dpme_pblock_start = p->dpme_pblock_start;
562 			entry->dpme_pblocks += p->dpme_pblocks;
563 			delete_entry(p);
564 		}
565 	}
566 }
567 
568 
569 void
delete_entry(struct entry * entry)570 delete_entry(struct entry *entry)
571 {
572 	struct partition_map *map;
573 
574 	map = entry->the_map;
575 	map->blocks_in_map--;
576 
577 	LIST_REMOVE(entry, disk_entry);
578 	LIST_REMOVE(entry, base_entry);
579 
580 	free(entry);
581 }
582 
583 
584 struct entry *
find_entry_by_disk_address(long ix,struct partition_map * map)585 find_entry_by_disk_address(long ix, struct partition_map *map)
586 {
587 	struct entry *cur;
588 
589 	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
590 		if (cur->disk_address == ix)
591 			break;
592 	}
593 	return cur;
594 }
595 
596 
597 struct entry *
find_entry_by_type(const char * type_name,struct partition_map * map)598 find_entry_by_type(const char *type_name, struct partition_map *map)
599 {
600 	struct entry *cur;
601 
602 	LIST_FOREACH(cur, &map->base_order, base_entry) {
603 		if (strncasecmp(cur->dpme_type, type_name, DPISTRLEN) == 0)
604 			break;
605 	}
606 	return cur;
607 }
608 
609 struct entry *
find_entry_by_base(uint32_t base,struct partition_map * map)610 find_entry_by_base(uint32_t base, struct partition_map *map)
611 {
612 	struct entry *cur;
613 
614 	LIST_FOREACH(cur, &map->base_order, base_entry) {
615 		if (cur->dpme_pblock_start == base)
616 			break;
617 	}
618 	return cur;
619 }
620 
621 
622 void
move_entry_in_map(long index1,long index2,struct partition_map * map)623 move_entry_in_map(long index1, long index2, struct partition_map *map)
624 {
625 	struct entry *p1, *p2;
626 
627 	if (index1 == index2)
628 		return;
629 
630 	if (index1 == 1 || index2 == 1) {
631 		printf("Partition #1 cannot be moved\n");
632 		return;
633 	}
634 	p1 = find_entry_by_disk_address(index1, map);
635 	if (p1 == NULL) {
636 		printf("Partition #%ld not found\n", index1);
637 		return;
638 	}
639 	p2 = find_entry_by_disk_address(index2, map);
640 	if (p2 == NULL) {
641 		printf("Partition #%ld not found\n", index2);
642 		return;
643 	}
644 
645 	LIST_REMOVE(p1, disk_entry);
646 	LIST_REMOVE(p2, disk_entry);
647 
648 	p1->disk_address = index2;
649 	p2->disk_address = index1;
650 
651 	insert_in_disk_order(p1);
652 	insert_in_disk_order(p2);
653 
654 	renumber_disk_addresses(map);
655 	map->changed = 1;
656 }
657 
658 
659 void
insert_in_disk_order(struct entry * entry)660 insert_in_disk_order(struct entry *entry)
661 {
662 	struct partition_map *map;
663 	struct entry *cur;
664 
665 	/* find position in disk list & insert */
666 	map = entry->the_map;
667 	if (LIST_EMPTY(&map->disk_order)) {
668 		LIST_INSERT_HEAD(&map->disk_order, entry, disk_entry);
669 		return;
670 	}
671 
672 	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
673 		if (cur->disk_address >= entry->disk_address) {
674 			LIST_INSERT_BEFORE(cur, entry, disk_entry);
675 			return;
676 		}
677 		if (LIST_NEXT(cur, disk_entry) == NULL) {
678 			LIST_INSERT_AFTER(cur, entry, disk_entry);
679 			return;
680 		}
681 	}
682 }
683 
684 
685 void
insert_in_base_order(struct entry * entry)686 insert_in_base_order(struct entry *entry)
687 {
688 	struct partition_map *map;
689 	struct entry *cur;
690 	uint32_t start;
691 
692 	/* find position in base list & insert */
693 	map = entry->the_map;
694 	if (LIST_EMPTY(&map->base_order)) {
695 		LIST_INSERT_HEAD(&map->base_order, entry, base_entry);
696 		return;
697 	}
698 
699 	start = entry->dpme_pblock_start;
700 	LIST_FOREACH(cur, &map->base_order, base_entry) {
701 		if (start <= cur->dpme_pblock_start) {
702 			LIST_INSERT_BEFORE(cur, entry, base_entry);
703 			return;
704 		}
705 		if (LIST_NEXT(cur, base_entry) == NULL) {
706 			LIST_INSERT_AFTER(cur, entry, base_entry);
707 			return;
708 		}
709 	}
710 }
711 
712 
713 void
resize_map(long new_size,struct partition_map * map)714 resize_map(long new_size, struct partition_map *map)
715 {
716 	struct entry *entry;
717 	struct entry *next;
718 	int incr;
719 
720 	entry = find_entry_by_type(kMapType, map);
721 
722 	if (entry == NULL) {
723 		printf("Couldn't find entry for map!\n");
724 		return;
725 	}
726 	if (new_size == entry->dpme_pblocks)
727 		return;
728 
729 	next = LIST_NEXT(entry, base_entry);
730 
731 	if (new_size < entry->dpme_pblocks) {
732 		/* make it smaller */
733 		if (next == NULL ||
734 		    strncasecmp(next->dpme_type, kFreeType, DPISTRLEN) != 0)
735 			incr = 1;
736 		else
737 			incr = 0;
738 		if (new_size < map->blocks_in_map + incr) {
739 			printf("New size would be too small\n");
740 			return;
741 		}
742 		goto doit;
743 	}
744 	/* make it larger */
745 	if (next == NULL ||
746 	    strncasecmp(next->dpme_type, kFreeType, DPISTRLEN) != 0) {
747 		printf("No free space to expand into\n");
748 		return;
749 	}
750 	if (entry->dpme_pblock_start + entry->dpme_pblocks
751 	    != next->dpme_pblock_start) {
752 		printf("No contiguous free space to expand into\n");
753 		return;
754 	}
755 	if (new_size > entry->dpme_pblocks + next->dpme_pblocks) {
756 		printf("No enough free space\n");
757 		return;
758 	}
759 doit:
760 	entry->dpme_type[0] = 0;
761 	delete_partition_from_map(entry);
762 	add_partition_to_map("Apple", kMapType, 1, new_size, map);
763 	map->maximum_in_map = new_size;
764 }
765 
766 
767 void
remove_driver(struct entry * entry)768 remove_driver(struct entry *entry)
769 {
770 	struct partition_map *map;
771 	struct ddmap *m;
772 	int i, j;
773 	uint32_t start;
774 
775 	/*
776 	 * compute the factor to convert the block numbers in block0
777 	 * into partition map block numbers.
778 	 */
779 	map = entry->the_map;
780 	m = map->sbDDMap;
781 	for (i = 0; i < map->sbDrvrCount; i++) {
782 		start = m[i].ddBlock;
783 		/*
784 		 * zap the driver if it is wholly contained in the
785 		 * partition
786 		 */
787 		if (entry->dpme_pblock_start <= start && (start +
788 		    m[i].ddSize) <= (entry->dpme_pblock_start +
789 		    entry->dpme_pblocks)) {
790 			/*
791 			 * Delete this driver by copying down later ones and
792 			 * zapping the last one.
793 			 */
794 			for (j = i + 1; j < map->sbDrvrCount; j++, i++) {
795 				m[i].ddBlock = m[i].ddBlock;
796 				m[i].ddSize = m[j].ddSize;
797 				m[i].ddType = m[j].ddType;
798 			}
799 			m[i].ddBlock = 0;
800 			m[i].ddSize = 0;
801 			m[i].ddType = 0;
802 			map->sbDrvrCount -= 1;
803 			return;	/* XXX if we continue we will delete
804 				 * other drivers? */
805 		}
806 	}
807 }
808