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, long capacity,
512     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 /*
574  * NOTE: arguments to this function are not checked for sanity.
575  *
576  * fsize and/or bsize may both be -1, indicating
577  * "choose a reasonable default."
578  */
579 struct subpartition *
580 subpartition_new_ufs(struct slice *s, const char *mountpoint, long capacity,
581     int encrypted, int softupdates, long fsize, long bsize, int tmpfsbacked)
582 {
583 	struct subpartition *sp;
584 	struct subpartition *last = s->subpartition_tail;
585 
586 	AURA_MALLOC(sp, subpartition);
587 
588 	if (tmpfsbacked) {
589 		sp->letter = '@';
590 	} else {
591 		while (last && last->letter == '@')
592 			last = last->prev;
593 		if (last == NULL) {
594 			sp->letter = 'a';
595 		} else if (last->letter == 'b') {
596 			sp->letter = 'd';
597 		} else {
598 			sp->letter = (char)(last->letter + 1);
599 		}
600 		if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
601 			sp->letter = 'd';
602 	}
603 
604 	sp->parent = s;
605 
606 	sp->mountpoint = aura_strdup(mountpoint);
607 	sp->capacity = capacity;
608 	sp->encrypted = encrypted;
609 	sp->type = FS_UFS;
610 
611 	if (fsize == -1) {
612 		if (sp->capacity < 1024)
613 			sp->fsize = 1024;
614 		else
615 			sp->fsize = 2048;
616 	} else {
617 		sp->fsize = fsize;
618 	}
619 
620 	if (bsize == -1) {
621 		if (sp->capacity < 1024)
622 			sp->bsize = 8192;
623 		else
624 			sp->bsize = 16384;
625 	} else {
626 		sp->bsize = bsize;
627 	}
628 
629 	if (softupdates == -1) {
630 		if (strcmp(mountpoint, "/") == 0)
631 			sp->softupdates = 0;
632 		else
633 			sp->softupdates = 1;
634 	} else {
635 		sp->softupdates = softupdates;
636 	}
637 
638 	sp->tmpfsbacked = tmpfsbacked;
639 
640 	sp->is_swap = 0;
641 	if (strcasecmp(mountpoint, "swap") == 0)
642 		sp->is_swap = 1;
643 
644 	/*
645 	 * install
646 	 */
647 	sp->next = NULL;
648 	if (s->subpartition_head == NULL)
649 		s->subpartition_head = sp;
650 	else
651 		s->subpartition_tail->next = sp;
652 
653 	sp->prev = s->subpartition_tail;
654 	s->subpartition_tail = sp;
655 
656 #if 0
657 
658 	for (sptmp = s->subpartition_head; sptmp != NULL;
659 	     sptmp = sptmp->next) {
660 		if (sptmp->tmpfsbacked)
661 			sptmp->letter = '@';
662 		else if (strcmp(sptmp->mountpoint, "/") == 0 ||
663 			 strcmp(sptmp->mountpoint, "/dummy") == 0)
664 			sptmp->letter = 'a';
665 		else if (strcasecmp(sptmp->mountpoint, "swap") == 0)
666 			sptmp->letter = 'b';
667 		else
668 			sptmp->letter = letter++;
669 	}
670 #endif
671 
672 	return(sp);
673 }
674 
675 /*
676  * Find the subpartition description in the given storage
677  * description whose mountpoint matches the given string exactly.
678  */
679 struct subpartition *
680 subpartition_find(const struct slice *s, const char *fmt, ...)
681 {
682 	struct subpartition *sp = s->subpartition_head;
683 	char *mountpoint;
684 	va_list args;
685 
686 	va_start(args, fmt);
687 	vasprintf(&mountpoint, fmt, args);
688 	va_end(args);
689 
690 	while (sp != NULL) {
691 		if (strcmp(mountpoint, sp->mountpoint) == 0) {
692 			free(mountpoint);
693 			return(sp);
694 		}
695 		sp = sp->next;
696 	}
697 
698 	free(mountpoint);
699 	return(NULL);
700 }
701 
702 /*
703  * Find the subpartition description in the given storage
704  * description where the given filename would presumably
705  * reside.  This is the subpartition whose mountpoint is
706  * the longest match for the given filename.
707  */
708 struct subpartition *
709 subpartition_of(const struct slice *s, const char *fmt, ...)
710 {
711 	struct subpartition *sp = s->subpartition_head;
712 	struct subpartition *csp = NULL;
713 	size_t len = 0;
714 	char *filename;
715 	va_list args;
716 
717 	va_start(args, fmt);
718 	vasprintf(&filename, fmt, args);
719 	va_end(args);
720 
721 	while (sp != NULL) {
722 		if (strlen(sp->mountpoint) > len &&
723 		    strlen(sp->mountpoint) <= strlen(filename) &&
724 		    strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
725 				csp = sp;
726 				len = strlen(csp->mountpoint);
727 		}
728 		sp = sp->next;
729 	}
730 
731 	free(filename);
732 	return(csp);
733 }
734 
735 struct subpartition *
736 subpartition_find_capacity(const struct slice *s, long capacity)
737 {
738 	struct subpartition *sp = s->subpartition_head;
739 
740 	while (sp != NULL) {
741 		if (sp->capacity == capacity)
742 			return(sp);
743 		sp = sp->next;
744 	}
745 
746 	return(NULL);
747 }
748 
749 struct subpartition *
750 subpartition_next(const struct subpartition *sp)
751 {
752 	return(sp->next);
753 }
754 
755 int
756 subpartition_get_pfs(const struct subpartition *sp)
757 {
758 	return(sp->pfs);
759 }
760 
761 /*
762  * Returns the name of the device node used to represent
763  * the subpartition, either by serial number or traditional style.
764  * Note that the storage used for the returned string is static,
765  * and the string is overwritten each time this function is called.
766  */
767 const char *
768 subpartition_get_device_name(const struct subpartition *sp)
769 {
770 	static char tmp_dev_name[256];
771 
772 	if (sp->parent->parent->serno != NULL)
773 		snprintf(tmp_dev_name, 256, "serno/%s.s%d%c",
774 		    sp->parent->parent->serno, sp->parent->number, sp->letter);
775 	else
776 		snprintf(tmp_dev_name, 256, "%ss%d%c",
777 		    sp->parent->parent->device, sp->parent->number, sp->letter);
778 	return(tmp_dev_name);
779 }
780 
781 /*
782  * /dev/mapper/
783  *
784  * (result is persistant until next call)
785  */
786 const char *
787 subpartition_get_mapper_name(const struct subpartition *sp, int withdev)
788 {
789 	const char *src;
790 	static char *save;
791 
792 	src = strrchr(sp->mountpoint, '/');
793 	if (src == NULL || src[1] == 0)
794 		src = "root";
795 	else
796 		++src;
797 
798 	if (save)
799 		free(save);
800 	switch(withdev) {
801 	case -1:
802 		asprintf(&save, "%s", src);
803 		break;
804 	case 0:
805 		asprintf(&save, "mapper/%s", src);
806 		break;
807 	case 1:
808 	default:
809 		asprintf(&save, "/dev/mapper/%s", src);
810 		break;
811 	}
812 	return save;
813 }
814 
815 const char *
816 subpartition_get_mountpoint(const struct subpartition *sp)
817 {
818 	return(sp->mountpoint);
819 }
820 
821 char
822 subpartition_get_letter(const struct subpartition *sp)
823 {
824 	return(sp->letter);
825 }
826 
827 unsigned long
828 subpartition_get_fsize(const struct subpartition *sp)
829 {
830 	return(sp->fsize);
831 }
832 
833 unsigned long
834 subpartition_get_bsize(const struct subpartition *sp)
835 {
836 	return(sp->bsize);
837 }
838 
839 long
840 subpartition_get_capacity(const struct subpartition *sp)
841 {
842 	return(sp->capacity);
843 }
844 
845 void
846 subpartition_clr_encrypted(struct subpartition *sp)
847 {
848 	sp->encrypted = 0;
849 }
850 
851 int
852 subpartition_is_encrypted(const struct subpartition *sp)
853 {
854 	return(sp->encrypted);
855 }
856 
857 int
858 subpartition_is_swap(const struct subpartition *sp)
859 {
860 	return(sp->is_swap);
861 }
862 
863 int
864 subpartition_is_softupdated(const struct subpartition *sp)
865 {
866 	return(sp->softupdates);
867 }
868 int
869 subpartition_is_tmpfsbacked(const struct subpartition *sp)
870 {
871 	return(sp->tmpfsbacked);
872 }
873 
874 int
875 subpartition_count(const struct slice *s)
876 {
877 	struct subpartition *sp = s->subpartition_head;
878 	int count = 0;
879 
880 	while (sp != NULL) {
881 		count++;
882 		sp = sp->next;
883 	}
884 
885 	return(count);
886 }
887 
888 void
889 subpartitions_free(struct slice *s)
890 {
891 	struct subpartition *sp = s->subpartition_head, *next;
892 
893 	while (sp != NULL) {
894 		next = sp->next;
895 		free(sp->mountpoint);
896 		AURA_FREE(sp, subpartition);
897 		sp = next;
898 	}
899 
900 	s->subpartition_head = NULL;
901 	s->subpartition_tail = NULL;
902 }
903 
904 long
905 measure_activated_swap(const struct i_fn_args *a)
906 {
907 	FILE *p;
908 	char line[256];
909 	char *word;
910 	long swap = 0;
911 
912 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
913 		return(0);
914 	while (fgets(line, 255, p) != NULL) {
915 		if ((word = strtok(line, " \t")) == NULL)
916 			continue;
917 		if (strcmp(word, "Device") == 0)
918 			continue;
919 		if ((word = strtok(NULL, " \t")) == NULL)
920 			continue;
921 		swap += atol(word);
922 	}
923 	aura_pclose(p);
924 
925 	return(swap / 1024);
926 }
927 
928 long
929 measure_activated_swap_from_slice(const struct i_fn_args *a,
930     const struct disk *d, const struct slice *s)
931 {
932 	FILE *p;
933 	char *dev, *word;
934 	char line[256];
935 	long swap = 0;
936 
937 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
938 		return(0);
939 
940 	asprintf(&dev, "/dev/%ss%d", d->device, s->number);
941 
942 	while (fgets(line, 255, p) != NULL) {
943 		if ((word = strtok(line, " \t")) == NULL)
944 			continue;
945 		if (strcmp(word, "Device") == 0)
946 			continue;
947 		if (strstr(word, dev) != word)
948 			continue;
949 		if ((word = strtok(NULL, " \t")) == NULL)
950 			continue;
951 		swap += atol(word);
952 	}
953 	aura_pclose(p);
954 	free(dev);
955 
956 	return(swap / 1024);
957 }
958 
959 long
960 measure_activated_swap_from_disk(const struct i_fn_args *a,
961 				 const struct disk *d)
962 {
963 	struct slice *s;
964 	long swap = 0;
965 
966 	for (s = d->slice_head; s != NULL; s = s->next)
967 		swap += measure_activated_swap_from_slice(a, d, s);
968 
969 	return(swap);
970 }
971 
972 void *
973 swapoff_all(const struct i_fn_args *a)
974 {
975 	FILE *p;
976 
977 	if ((p = aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r",
978 		    a->os_root, cmd_name(a, "DUMPON"),
979 		    a->os_root, cmd_name(a, "SWAPINFO"),
980 		    a->os_root, cmd_name(a, "GREP"),
981 		    a->os_root, cmd_name(a, "AWK"),
982 		    a->os_root, cmd_name(a, "XARGS"),
983 		    a->os_root, cmd_name(a, "SWAPOFF"))) != NULL)
984 		aura_pclose(p);
985 
986 	return(p);
987 }
988 
989 void *
990 remove_all_mappings(const struct i_fn_args *a)
991 {
992 	FILE *p;
993 
994 	if ((p = aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r",
995 		    a->os_root, cmd_name(a, "LS"),
996 		    a->os_root, cmd_name(a, "GREP"),
997 		    a->os_root, cmd_name(a, "XARGS"),
998 		    a->os_root, cmd_name(a, "CRYPTSETUP"))) != NULL)
999 		aura_pclose(p);
1000 
1001 	return(p);
1002 }
1003