1 /*
2  * Copyright (c)2004,2015 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of the DragonFly Project nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * diskutil.c
36  * Disk utility functions for installer.
37  * $Id: diskutil.c,v 1.44 2005/02/07 06:41:42 cpressey Exp $
38  */
39 
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include "libaura/mem.h"
46 #include "libaura/fspred.h"
47 #include "libaura/popen.h"
48 
49 #include "libdfui/dfui.h"
50 #include "libdfui/dump.h"
51 
52 #define NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
53 #include "diskutil.h"
54 #undef NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
55 
56 #include "commands.h"
57 #include "functions.h"
58 #include "sysids.h"
59 #include "uiutil.h"
60 
61 static int	disk_description_is_better(const char *, const char *);
62 
63 /** STORAGE DESCRIPTORS **/
64 
65 struct storage *
66 storage_new(void)
67 {
68 	struct storage *s;
69 
70 	AURA_MALLOC(s, storage);
71 
72 	s->disk_head = NULL;
73 	s->disk_tail = NULL;
74 	s->selected_disk = NULL;
75 	s->selected_slice = NULL;
76 	s->ram = -1;
77 
78 	return(s);
79 }
80 
81 int
82 storage_get_tmpfs_status(const char *mountpoint, struct storage *s)
83 {
84 	struct subpartition *sp;
85 	sp = NULL;
86 	for (sp = slice_subpartition_first(s->selected_slice);
87 		sp != NULL; sp = subpartition_next(sp)) {
88 		if(strcmp(subpartition_get_mountpoint(sp), mountpoint) == 0) {
89 			if(subpartition_is_tmpfsbacked(sp) == 1) {
90 				return 1;
91 			} else {
92 				return 0;
93 			}
94 		}
95 	}
96 	return 0;
97 }
98 
99 void
100 storage_free(struct storage *s)
101 {
102 	disks_free(s);
103 	AURA_FREE(s, storage);
104 }
105 
106 void
107 storage_set_memsize(struct storage *s, unsigned long memsize)
108 {
109 	s->ram = memsize;
110 }
111 
112 long
113 storage_get_memsize(const struct storage *s)
114 {
115 	return(s->ram);
116 }
117 
118 struct disk *
119 storage_disk_first(const struct storage *s)
120 {
121 	return(s->disk_head);
122 }
123 
124 void
125 storage_set_selected_disk(struct storage *s, struct disk *d)
126 {
127 	s->selected_disk = d;
128 }
129 
130 struct disk *
131 storage_get_selected_disk(const struct storage *s)
132 {
133 	return(s->selected_disk);
134 }
135 
136 void
137 storage_set_selected_slice(struct storage *s, struct slice *sl)
138 {
139 	s->selected_slice = sl;
140 }
141 
142 struct slice *
143 storage_get_selected_slice(const struct storage *s)
144 {
145 	return(s->selected_slice);
146 }
147 
148 /*
149  * Create a new disk description structure.
150  */
151 struct disk *
152 disk_new(struct storage *s, const char *dev_name)
153 {
154 	struct disk *d;
155 
156 	AURA_MALLOC(d, disk);
157 
158 	d->device = aura_strdup(dev_name);
159 	d->desc = NULL;
160 	d->serno = NULL;
161 	d->we_formatted = 0;
162 	d->capacity = 0;
163 
164 	d->cylinders = -1;	/* -1 indicates "we don't know" */
165 	d->heads = -1;
166 	d->sectors = -1;
167 
168 	d->slice_head = NULL;
169 	d->slice_tail = NULL;
170 
171 	d->next = NULL;
172 	if (s->disk_head == NULL)
173 		s->disk_head = d;
174 	else
175 		s->disk_tail->next = d;
176 
177 	d->prev = s->disk_tail;
178 	s->disk_tail = d;
179 
180 	return(d);
181 }
182 
183 static int
184 disk_description_is_better(const char *existing, const char *new_desc __unused)
185 {
186 	if (existing == NULL)
187 		return(1);
188 	return(0);
189 }
190 
191 const char *
192 disk_get_desc(const struct disk *d)
193 {
194 	return(d->desc);
195 }
196 
197 unsigned long
198 disk_get_capacity(const struct disk *d)
199 {
200 	return(d->capacity);
201 }
202 
203 
204 void
205 disk_set_desc(struct disk *d, const char *desc)
206 {
207 	char *c;
208 
209 	if (!disk_description_is_better(d->desc, desc))
210 		return;
211 	if (d->desc != NULL)
212 		free(d->desc);
213 	d->desc = aura_strdup(desc);
214 
215 	/*
216 	 * Get the disk's total capacity.
217 	 * XXX we should do this with C/H/S ?
218 	 */
219 	c = d->desc;
220 	while (*c != ':' && *c != '\0')
221 		c++;
222 	if (*c == '\0')
223 		d->capacity = 0;
224 	else
225 		d->capacity = strtoul(c + 1, NULL, 0);
226 }
227 
228 /*
229  * Returns the name of the device node used to represent the disk.
230  * Note that the storage used for the returned string is static,
231  * and the string is overwritten each time this function is called.
232  */
233 const char *
234 disk_get_device_name(const struct disk *d)
235 {
236 	static char tmp_dev_name[256];
237 
238 	snprintf(tmp_dev_name, 256, "%s", d->device);
239 	return(tmp_dev_name);
240 }
241 
242 const char *
243 disk_get_serno(const struct disk *d)
244 {
245 	return(d->serno);
246 }
247 
248 void
249 disk_set_serno(struct disk *d, const char *serno)
250 {
251 	d->serno = aura_strdup(serno);
252 }
253 
254 int
255 disk_get_number(const struct disk *d)
256 {
257 	return(d->number);
258 }
259 
260 void
261 disk_set_number(struct disk *d, const int number)
262 {
263 	d->number = number;
264 }
265 
266 /*
267  * Find the first disk description structure in the given
268  * storage description which matches the given device name
269  * prefix.  Note that this means that if a storage
270  * description s contains disks named "ad0" and "ad1",
271  * disk_find(s, "ad0s1c") will return a pointer to the disk
272  * structure for "ad0".
273  */
274 struct disk *
275 disk_find(const struct storage *s, const char *device)
276 {
277 	struct disk *d = s->disk_head;
278 
279 	while (d != NULL) {
280 		if (strncmp(device, d->device, strlen(d->device)) == 0 &&
281 		    strlen(device) == strlen(d->device))
282 			return(d);
283 		d = d->next;
284 	}
285 
286 	return(NULL);
287 }
288 
289 struct disk *
290 disk_next(const struct disk *d)
291 {
292 	return(d->next);
293 }
294 
295 struct slice *
296 disk_slice_first(const struct disk *d)
297 {
298 	return(d->slice_head);
299 }
300 
301 void
302 disk_set_formatted(struct disk *d, int formatted)
303 {
304 	d->we_formatted = formatted;
305 }
306 
307 int
308 disk_get_formatted(const struct disk *d)
309 {
310 	return(d->we_formatted);
311 }
312 
313 void
314 disk_set_geometry(struct disk *d, int cyl, int hd, int sec)
315 {
316 	d->cylinders = cyl;
317 	d->heads = hd;
318 	d->sectors = sec;
319 }
320 
321 void
322 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec)
323 {
324 	*cyl = d->cylinders;
325 	*hd = d->heads;
326 	*sec = d->sectors;
327 }
328 
329 /*
330  * Free the memory allocated to hold the set of disk descriptions.
331  */
332 void
333 disks_free(struct storage *s)
334 {
335 	struct disk *d = s->disk_head, *next;
336 
337 	while (d != NULL) {
338 		next = d->next;
339 		slices_free(d->slice_head);
340 		free(d->desc);
341 		free(d->device);
342 		AURA_FREE(d, disk);
343 		d = next;
344 	}
345 
346 	s->disk_head = NULL;
347 	s->disk_tail = NULL;
348 }
349 
350 /*
351  * Create a new slice description and add it to a disk description.
352  */
353 struct slice *
354 slice_new(struct disk *d, int number, int type, int flags,
355 	  unsigned long start, unsigned long size)
356 {
357 	struct slice *s;
358 	const char *sysid_desc = NULL;
359 	char unknown[256];
360 	int i;
361 
362 	dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
363 	    "to disk %s\n", number, start, size, type, d->device);
364 
365 	AURA_MALLOC(s, slice);
366 
367 	s->parent = d;
368 
369 	s->subpartition_head = NULL;
370 	s->subpartition_tail = NULL;
371 	s->number = number;
372 
373 	s->type = type;
374 	s->flags = flags;
375 	s->start = start;
376 	s->size = size;
377 
378 	for (i = 0; ; i++) {
379 		if (part_types[i].type == type) {
380 			sysid_desc = part_types[i].name;
381 			break;
382 		}
383 		if (part_types[i].type == 255)
384 			break;
385 	}
386 	if (sysid_desc == NULL) {
387 		snprintf(unknown, 256, "??? Unknown, sysid = %d", type);
388 		sysid_desc = unknown;
389 	}
390 
391 	asprintf(&s->desc, "%ldM - %ldM: %s",
392 	    start / 2048, (start + size) / 2048, sysid_desc);
393 	s->capacity = size / 2048;
394 
395 	s->next = NULL;
396 	if (d->slice_head == NULL)
397 		d->slice_head = s;
398 	else
399 		d->slice_tail->next = s;
400 
401 	s->prev = d->slice_tail;
402 	d->slice_tail = s;
403 
404 	return(s);
405 }
406 
407 /*
408  * Find a slice description on a given disk description given the
409  * slice number.
410  */
411 struct slice *
412 slice_find(const struct disk *d, int number)
413 {
414 	struct slice *s = d->slice_head;
415 
416 	while (s != NULL) {
417 		if (s->number == number)
418 			return(s);
419 		s = s->next;
420 	}
421 
422 	return(NULL);
423 }
424 
425 struct slice *
426 slice_next(const struct slice *s)
427 {
428 	return(s->next);
429 }
430 
431 /*
432  * Returns the name of the device node used to represent the slice.
433  * Note that the storage used for the returned string is static,
434  * and the string is overwritten each time this function is called.
435  */
436 const char *
437 slice_get_device_name(const struct slice *s)
438 {
439 	static char tmp_dev_name[256];
440 
441 	snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
442 	return(tmp_dev_name);
443 }
444 
445 int
446 slice_get_number(const struct slice *s)
447 {
448 	return(s->number);
449 }
450 
451 const char *
452 slice_get_desc(const struct slice *s)
453 {
454 	return(s->desc);
455 }
456 
457 unsigned long
458 slice_get_capacity(const struct slice *s)
459 {
460 	return(s->capacity);
461 }
462 
463 unsigned long
464 slice_get_start(const struct slice *s)
465 {
466 	return(s->start);
467 }
468 
469 unsigned long
470 slice_get_size(const struct slice *s)
471 {
472 	return(s->size);
473 }
474 
475 int
476 slice_get_type(const struct slice *s)
477 {
478 	return(s->type);
479 }
480 
481 int
482 slice_get_flags(const struct slice *s)
483 {
484 	return(s->flags);
485 }
486 
487 struct subpartition *
488 slice_subpartition_first(const struct slice *s)
489 {
490 	return(s->subpartition_head);
491 }
492 
493 /*
494  * Free all memory for a list of slice descriptions.
495  */
496 void
497 slices_free(struct slice *head)
498 {
499 	struct slice *next;
500 
501 	while (head != NULL) {
502 		next = head->next;
503 		subpartitions_free(head);
504 		free(head->desc);
505 		AURA_FREE(head, slice);
506 		head = next;
507 	}
508 }
509 
510 struct subpartition *
511 subpartition_new_hammer(struct slice *s, const char *mountpoint,
512 			long capacity, int encrypted)
513 {
514 	struct subpartition *sp;
515 	struct subpartition *last = s->subpartition_tail;
516 
517 	AURA_MALLOC(sp, subpartition);
518 
519 	sp->parent = s;
520 
521 	if (last == NULL) {
522 		sp->letter = 'a';
523 	} else if (last->letter == 'b') {
524 		sp->letter = 'd';
525 	} else {
526 		sp->letter = (char)(last->letter + 1);
527 	}
528 	if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
529 		sp->letter = 'd';
530 
531 	sp->mountpoint = aura_strdup(mountpoint);
532 	sp->capacity = capacity;
533 	sp->encrypted = encrypted;
534 	sp->type = FS_HAMMER;
535 
536 	/*
537 	 * We need this here, because a UFS /boot needs valid values
538 	 */
539 	if (sp->capacity < 1024)
540 		sp->fsize = 1024;
541 	else
542 		sp->fsize = 2048;
543 
544 	if (sp->capacity < 1024)
545 		sp->bsize = 8192;
546 	else
547 		sp->bsize = 16384;
548 
549 	sp->is_swap = 0;
550 #if 0
551 	sp->pfs = 0;
552 #endif
553 	if (strcasecmp(mountpoint, "swap") == 0)
554 		sp->is_swap = 1;
555 #if 0
556 	if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 &&
557 	    strcmp(mountpoint, "swap") != 0)
558 		sp->pfs = 1;
559 #endif
560 
561 	sp->next = NULL;
562 	if (s->subpartition_head == NULL)
563 		s->subpartition_head = sp;
564 	else
565 		s->subpartition_tail->next = sp;
566 
567 	sp->prev = s->subpartition_tail;
568 	s->subpartition_tail = sp;
569 
570 	return(sp);
571 }
572 
573 struct subpartition *
574 subpartition_new_hammer2(struct slice *s, const char *mountpoint,
575 			 long capacity, int encrypted)
576 {
577 	struct subpartition *sp;
578 	struct subpartition *last = s->subpartition_tail;
579 
580 	AURA_MALLOC(sp, subpartition);
581 
582 	sp->parent = s;
583 
584 	if (last == NULL) {
585 		sp->letter = 'a';
586 	} else if (last->letter == 'b') {
587 		sp->letter = 'd';
588 	} else {
589 		sp->letter = (char)(last->letter + 1);
590 	}
591 	if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
592 		sp->letter = 'd';
593 
594 	sp->mountpoint = aura_strdup(mountpoint);
595 	sp->capacity = capacity;
596 	sp->encrypted = encrypted;
597 	sp->type = FS_HAMMER2;
598 
599 	/*
600 	 * We need this here, because a UFS /boot needs valid values
601 	 */
602 	if (sp->capacity < 1024)
603 		sp->fsize = 1024;
604 	else
605 		sp->fsize = 2048;
606 
607 	if (sp->capacity < 1024)
608 		sp->bsize = 8192;
609 	else
610 		sp->bsize = 16384;
611 
612 	sp->is_swap = 0;
613 #if 0
614 	sp->pfs = 0;
615 #endif
616 	if (strcasecmp(mountpoint, "swap") == 0)
617 		sp->is_swap = 1;
618 #if 0
619 	if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 &&
620 	    strcmp(mountpoint, "swap") != 0)
621 		sp->pfs = 1;
622 #endif
623 
624 	sp->next = NULL;
625 	if (s->subpartition_head == NULL)
626 		s->subpartition_head = sp;
627 	else
628 		s->subpartition_tail->next = sp;
629 
630 	sp->prev = s->subpartition_tail;
631 	s->subpartition_tail = sp;
632 
633 	return(sp);
634 }
635 
636 /*
637  * NOTE: arguments to this function are not checked for sanity.
638  *
639  * fsize and/or bsize may both be -1, indicating
640  * "choose a reasonable default."
641  */
642 struct subpartition *
643 subpartition_new_ufs(struct slice *s, const char *mountpoint, long capacity,
644     int encrypted, int softupdates, long fsize, long bsize, int tmpfsbacked)
645 {
646 	struct subpartition *sp;
647 	struct subpartition *last = s->subpartition_tail;
648 
649 	AURA_MALLOC(sp, subpartition);
650 
651 	if (tmpfsbacked) {
652 		sp->letter = '@';
653 	} else {
654 		while (last && last->letter == '@')
655 			last = last->prev;
656 		if (last == NULL) {
657 			sp->letter = 'a';
658 		} else if (last->letter == 'b') {
659 			sp->letter = 'd';
660 		} else {
661 			sp->letter = (char)(last->letter + 1);
662 		}
663 		if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
664 			sp->letter = 'd';
665 	}
666 
667 	sp->parent = s;
668 
669 	sp->mountpoint = aura_strdup(mountpoint);
670 	sp->capacity = capacity;
671 	sp->encrypted = encrypted;
672 	sp->type = FS_UFS;
673 
674 	if (fsize == -1) {
675 		if (sp->capacity < 1024)
676 			sp->fsize = 1024;
677 		else
678 			sp->fsize = 2048;
679 	} else {
680 		sp->fsize = fsize;
681 	}
682 
683 	if (bsize == -1) {
684 		if (sp->capacity < 1024)
685 			sp->bsize = 8192;
686 		else
687 			sp->bsize = 16384;
688 	} else {
689 		sp->bsize = bsize;
690 	}
691 
692 	if (softupdates == -1) {
693 		if (strcmp(mountpoint, "/") == 0)
694 			sp->softupdates = 0;
695 		else
696 			sp->softupdates = 1;
697 	} else {
698 		sp->softupdates = softupdates;
699 	}
700 
701 	sp->tmpfsbacked = tmpfsbacked;
702 
703 	sp->is_swap = 0;
704 	if (strcasecmp(mountpoint, "swap") == 0)
705 		sp->is_swap = 1;
706 
707 	/*
708 	 * install
709 	 */
710 	sp->next = NULL;
711 	if (s->subpartition_head == NULL)
712 		s->subpartition_head = sp;
713 	else
714 		s->subpartition_tail->next = sp;
715 
716 	sp->prev = s->subpartition_tail;
717 	s->subpartition_tail = sp;
718 
719 #if 0
720 
721 	for (sptmp = s->subpartition_head; sptmp != NULL;
722 	     sptmp = sptmp->next) {
723 		if (sptmp->tmpfsbacked)
724 			sptmp->letter = '@';
725 		else if (strcmp(sptmp->mountpoint, "/") == 0 ||
726 			 strcmp(sptmp->mountpoint, "/dummy") == 0)
727 			sptmp->letter = 'a';
728 		else if (strcasecmp(sptmp->mountpoint, "swap") == 0)
729 			sptmp->letter = 'b';
730 		else
731 			sptmp->letter = letter++;
732 	}
733 #endif
734 
735 	return(sp);
736 }
737 
738 /*
739  * Find the subpartition description in the given storage
740  * description whose mountpoint matches the given string exactly.
741  */
742 struct subpartition *
743 subpartition_find(const struct slice *s, const char *fmt, ...)
744 {
745 	struct subpartition *sp = s->subpartition_head;
746 	char *mountpoint;
747 	va_list args;
748 
749 	va_start(args, fmt);
750 	vasprintf(&mountpoint, fmt, args);
751 	va_end(args);
752 
753 	while (sp != NULL) {
754 		if (strcmp(mountpoint, sp->mountpoint) == 0) {
755 			free(mountpoint);
756 			return(sp);
757 		}
758 		sp = sp->next;
759 	}
760 
761 	free(mountpoint);
762 	return(NULL);
763 }
764 
765 /*
766  * Find the subpartition description in the given storage
767  * description where the given filename would presumably
768  * reside.  This is the subpartition whose mountpoint is
769  * the longest match for the given filename.
770  */
771 struct subpartition *
772 subpartition_of(const struct slice *s, const char *fmt, ...)
773 {
774 	struct subpartition *sp = s->subpartition_head;
775 	struct subpartition *csp = NULL;
776 	size_t len = 0;
777 	char *filename;
778 	va_list args;
779 
780 	va_start(args, fmt);
781 	vasprintf(&filename, fmt, args);
782 	va_end(args);
783 
784 	while (sp != NULL) {
785 		if (strlen(sp->mountpoint) > len &&
786 		    strlen(sp->mountpoint) <= strlen(filename) &&
787 		    strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
788 				csp = sp;
789 				len = strlen(csp->mountpoint);
790 		}
791 		sp = sp->next;
792 	}
793 
794 	free(filename);
795 	return(csp);
796 }
797 
798 struct subpartition *
799 subpartition_find_capacity(const struct slice *s, long capacity)
800 {
801 	struct subpartition *sp = s->subpartition_head;
802 
803 	while (sp != NULL) {
804 		if (sp->capacity == capacity)
805 			return(sp);
806 		sp = sp->next;
807 	}
808 
809 	return(NULL);
810 }
811 
812 struct subpartition *
813 subpartition_next(const struct subpartition *sp)
814 {
815 	return(sp->next);
816 }
817 
818 int
819 subpartition_get_pfs(const struct subpartition *sp)
820 {
821 	return(sp->pfs);
822 }
823 
824 /*
825  * Returns the name of the device node used to represent
826  * the subpartition, either by serial number or traditional style.
827  * Note that the storage used for the returned string is static,
828  * and the string is overwritten each time this function is called.
829  */
830 const char *
831 subpartition_get_device_name(const struct subpartition *sp)
832 {
833 	static char tmp_dev_name[256];
834 
835 	if (sp->parent->parent->serno != NULL)
836 		snprintf(tmp_dev_name, 256, "serno/%s.s%d%c",
837 		    sp->parent->parent->serno, sp->parent->number, sp->letter);
838 	else
839 		snprintf(tmp_dev_name, 256, "%ss%d%c",
840 		    sp->parent->parent->device, sp->parent->number, sp->letter);
841 	return(tmp_dev_name);
842 }
843 
844 /*
845  * /dev/mapper/
846  *
847  * (result is persistant until next call)
848  */
849 const char *
850 subpartition_get_mapper_name(const struct subpartition *sp, int withdev)
851 {
852 	const char *src;
853 	static char *save;
854 
855 	src = strrchr(sp->mountpoint, '/');
856 	if (src == NULL || src[1] == 0)
857 		src = "root";
858 	else
859 		++src;
860 
861 	if (save)
862 		free(save);
863 	switch(withdev) {
864 	case -1:
865 		asprintf(&save, "%s", src);
866 		break;
867 	case 0:
868 		asprintf(&save, "mapper/%s", src);
869 		break;
870 	case 1:
871 	default:
872 		asprintf(&save, "/dev/mapper/%s", src);
873 		break;
874 	}
875 	return save;
876 }
877 
878 const char *
879 subpartition_get_mountpoint(const struct subpartition *sp)
880 {
881 	return(sp->mountpoint);
882 }
883 
884 char
885 subpartition_get_letter(const struct subpartition *sp)
886 {
887 	return(sp->letter);
888 }
889 
890 unsigned long
891 subpartition_get_fsize(const struct subpartition *sp)
892 {
893 	return(sp->fsize);
894 }
895 
896 unsigned long
897 subpartition_get_bsize(const struct subpartition *sp)
898 {
899 	return(sp->bsize);
900 }
901 
902 long
903 subpartition_get_capacity(const struct subpartition *sp)
904 {
905 	return(sp->capacity);
906 }
907 
908 void
909 subpartition_clr_encrypted(struct subpartition *sp)
910 {
911 	sp->encrypted = 0;
912 }
913 
914 int
915 subpartition_is_encrypted(const struct subpartition *sp)
916 {
917 	return(sp->encrypted);
918 }
919 
920 int
921 subpartition_is_swap(const struct subpartition *sp)
922 {
923 	return(sp->is_swap);
924 }
925 
926 int
927 subpartition_is_softupdated(const struct subpartition *sp)
928 {
929 	return(sp->softupdates);
930 }
931 int
932 subpartition_is_tmpfsbacked(const struct subpartition *sp)
933 {
934 	return(sp->tmpfsbacked);
935 }
936 
937 int
938 subpartition_count(const struct slice *s)
939 {
940 	struct subpartition *sp = s->subpartition_head;
941 	int count = 0;
942 
943 	while (sp != NULL) {
944 		count++;
945 		sp = sp->next;
946 	}
947 
948 	return(count);
949 }
950 
951 void
952 subpartitions_free(struct slice *s)
953 {
954 	struct subpartition *sp = s->subpartition_head, *next;
955 
956 	while (sp != NULL) {
957 		next = sp->next;
958 		free(sp->mountpoint);
959 		AURA_FREE(sp, subpartition);
960 		sp = next;
961 	}
962 
963 	s->subpartition_head = NULL;
964 	s->subpartition_tail = NULL;
965 }
966 
967 long
968 measure_activated_swap(const struct i_fn_args *a)
969 {
970 	FILE *p;
971 	char line[256];
972 	char *word;
973 	long swap = 0;
974 
975 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
976 		return(0);
977 	while (fgets(line, 255, p) != NULL) {
978 		if ((word = strtok(line, " \t")) == NULL)
979 			continue;
980 		if (strcmp(word, "Device") == 0)
981 			continue;
982 		if ((word = strtok(NULL, " \t")) == NULL)
983 			continue;
984 		swap += atol(word);
985 	}
986 	aura_pclose(p);
987 
988 	return(swap / 1024);
989 }
990 
991 long
992 measure_activated_swap_from_slice(const struct i_fn_args *a,
993     const struct disk *d, const struct slice *s)
994 {
995 	FILE *p;
996 	char *dev, *word;
997 	char line[256];
998 	long swap = 0;
999 
1000 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
1001 		return(0);
1002 
1003 	asprintf(&dev, "/dev/%ss%d", d->device, s->number);
1004 
1005 	while (fgets(line, 255, p) != NULL) {
1006 		if ((word = strtok(line, " \t")) == NULL)
1007 			continue;
1008 		if (strcmp(word, "Device") == 0)
1009 			continue;
1010 		if (strstr(word, dev) != word)
1011 			continue;
1012 		if ((word = strtok(NULL, " \t")) == NULL)
1013 			continue;
1014 		swap += atol(word);
1015 	}
1016 	aura_pclose(p);
1017 	free(dev);
1018 
1019 	return(swap / 1024);
1020 }
1021 
1022 long
1023 measure_activated_swap_from_disk(const struct i_fn_args *a,
1024 				 const struct disk *d)
1025 {
1026 	struct slice *s;
1027 	long swap = 0;
1028 
1029 	for (s = d->slice_head; s != NULL; s = s->next)
1030 		swap += measure_activated_swap_from_slice(a, d, s);
1031 
1032 	return(swap);
1033 }
1034 
1035 void *
1036 swapoff_all(const struct i_fn_args *a)
1037 {
1038 	FILE *p;
1039 
1040 	if ((p = aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r",
1041 		    a->os_root, cmd_name(a, "DUMPON"),
1042 		    a->os_root, cmd_name(a, "SWAPINFO"),
1043 		    a->os_root, cmd_name(a, "GREP"),
1044 		    a->os_root, cmd_name(a, "AWK"),
1045 		    a->os_root, cmd_name(a, "XARGS"),
1046 		    a->os_root, cmd_name(a, "SWAPOFF"))) != NULL)
1047 		aura_pclose(p);
1048 
1049 	return(p);
1050 }
1051 
1052 void *
1053 remove_all_mappings(const struct i_fn_args *a)
1054 {
1055 	FILE *p;
1056 
1057 	if ((p = aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r",
1058 		    a->os_root, cmd_name(a, "LS"),
1059 		    a->os_root, cmd_name(a, "GREP"),
1060 		    a->os_root, cmd_name(a, "XARGS"),
1061 		    a->os_root, cmd_name(a, "CRYPTSETUP"))) != NULL)
1062 		aura_pclose(p);
1063 
1064 	return(p);
1065 }
1066