1 /*
2  * Copyright (c)2004 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 	if (disk_find(s, dev_name) != NULL) {
157 		/* Already discovered */
158 		return(NULL);
159 	}
160 
161 	AURA_MALLOC(d, disk);
162 
163 	d->device = aura_strdup(dev_name);
164 	d->desc = NULL;
165 	d->serno = NULL;
166 	d->we_formatted = 0;
167 	d->capacity = 0;
168 
169 	d->cylinders = -1;	/* -1 indicates "we don't know" */
170 	d->heads = -1;
171 	d->sectors = -1;
172 
173 	d->slice_head = NULL;
174 	d->slice_tail = NULL;
175 
176 	d->next = NULL;
177 	if (s->disk_head == NULL)
178 		s->disk_head = d;
179 	else
180 		s->disk_tail->next = d;
181 
182 	d->prev = s->disk_tail;
183 	s->disk_tail = d;
184 
185 	return(d);
186 }
187 
188 static int
189 disk_description_is_better(const char *existing, const char *new_desc __unused)
190 {
191 	if (existing == NULL)
192 		return(1);
193 	return(0);
194 }
195 
196 const char *
197 disk_get_desc(const struct disk *d)
198 {
199 	return(d->desc);
200 }
201 
202 void
203 disk_set_desc(struct disk *d, const char *desc)
204 {
205 	char *c;
206 
207 	if (!disk_description_is_better(d->desc, desc))
208 		return;
209 	if (d->desc != NULL)
210 		free(d->desc);
211 	d->desc = aura_strdup(desc);
212 
213 	/*
214 	 * Get the disk's total capacity.
215 	 * XXX we should do this with C/H/S ?
216 	 */
217 	c = d->desc;
218 	while (*c != ':' && *c != '\0')
219 		c++;
220 	if (*c == '\0')
221 		d->capacity = 0;
222 	else
223 		d->capacity = atoi(c + 1);
224 }
225 
226 /*
227  * Returns the name of the device node used to represent the disk.
228  * Note that the storage used for the returned string is static,
229  * and the string is overwritten each time this function is called.
230  */
231 const char *
232 disk_get_device_name(const struct disk *d)
233 {
234 	static char tmp_dev_name[256];
235 
236 	snprintf(tmp_dev_name, 256, "%s", d->device);
237 	return(tmp_dev_name);
238 }
239 
240 const char *
241 disk_get_serno(const struct disk *d)
242 {
243 	return(d->serno);
244 }
245 
246 void
247 disk_set_serno(struct disk *d, const char *serno)
248 {
249 	d->serno = aura_strdup(serno);
250 }
251 
252 int
253 disk_get_number(const struct disk *d)
254 {
255 	return(d->number);
256 }
257 
258 void
259 disk_set_number(struct disk *d, const int number)
260 {
261 	d->number = number;
262 }
263 
264 /*
265  * Find the first disk description structure in the given
266  * storage description which matches the given device name
267  * prefix.  Note that this means that if a storage
268  * description s contains disks named "ad0" and "ad1",
269  * disk_find(s, "ad0s1c") will return a pointer to the disk
270  * structure for "ad0".
271  */
272 struct disk *
273 disk_find(const struct storage *s, const char *device)
274 {
275 	struct disk *d = s->disk_head;
276 
277 	while (d != NULL) {
278 		if (strncmp(device, d->device, strlen(d->device)) == 0)
279 			return(d);
280 		d = d->next;
281 	}
282 
283 	return(NULL);
284 }
285 
286 struct disk *
287 disk_next(const struct disk *d)
288 {
289 	return(d->next);
290 }
291 
292 struct slice *
293 disk_slice_first(const struct disk *d)
294 {
295 	return(d->slice_head);
296 }
297 
298 void
299 disk_set_formatted(struct disk *d, int formatted)
300 {
301 	d->we_formatted = formatted;
302 }
303 
304 int
305 disk_get_formatted(const struct disk *d)
306 {
307 	return(d->we_formatted);
308 }
309 
310 void
311 disk_set_geometry(struct disk *d, int cyl, int hd, int sec)
312 {
313 	d->cylinders = cyl;
314 	d->heads = hd;
315 	d->sectors = sec;
316 }
317 
318 void
319 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec)
320 {
321 	*cyl = d->cylinders;
322 	*hd = d->heads;
323 	*sec = d->sectors;
324 }
325 
326 /*
327  * Free the memory allocated to hold the set of disk descriptions.
328  */
329 void
330 disks_free(struct storage *s)
331 {
332 	struct disk *d = s->disk_head, *next;
333 
334 	while (d != NULL) {
335 		next = d->next;
336 		slices_free(d->slice_head);
337 		free(d->desc);
338 		free(d->device);
339 		AURA_FREE(d, disk);
340 		d = next;
341 	}
342 
343 	s->disk_head = NULL;
344 	s->disk_tail = NULL;
345 }
346 
347 /*
348  * Create a new slice description and add it to a disk description.
349  */
350 struct slice *
351 slice_new(struct disk *d, int number, int type, int flags,
352 	  unsigned long start, unsigned long size)
353 {
354 	struct slice *s;
355 	const char *sysid_desc = NULL;
356 	char unknown[256];
357 	int i;
358 
359 	dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
360 	    "to disk %s\n", number, start, size, type, d->device);
361 
362 	AURA_MALLOC(s, slice);
363 
364 	s->parent = d;
365 
366 	s->subpartition_head = NULL;
367 	s->subpartition_tail = NULL;
368 	s->number = number;
369 
370 	s->type = type;
371 	s->flags = flags;
372 	s->start = start;
373 	s->size = size;
374 
375 	for (i = 0; ; i++) {
376 		if (part_types[i].type == type) {
377 			sysid_desc = part_types[i].name;
378 			break;
379 		}
380 		if (part_types[i].type == 255)
381 			break;
382 	}
383 	if (sysid_desc == NULL) {
384 		snprintf(unknown, 256, "??? Unknown, sysid = %d", type);
385 		sysid_desc = unknown;
386 	}
387 
388 	asprintf(&s->desc, "%ldM - %ldM: %s",
389 	    start / 2048, (start + size) / 2048, sysid_desc);
390 	s->capacity = size / 2048;
391 
392 	s->next = NULL;
393 	if (d->slice_head == NULL)
394 		d->slice_head = s;
395 	else
396 		d->slice_tail->next = s;
397 
398 	s->prev = d->slice_tail;
399 	d->slice_tail = s;
400 
401 	return(s);
402 }
403 
404 /*
405  * Find a slice description on a given disk description given the
406  * slice number.
407  */
408 struct slice *
409 slice_find(const struct disk *d, int number)
410 {
411 	struct slice *s = d->slice_head;
412 
413 	while (s != NULL) {
414 		if (s->number == number)
415 			return(s);
416 		s = s->next;
417 	}
418 
419 	return(NULL);
420 }
421 
422 struct slice *
423 slice_next(const struct slice *s)
424 {
425 	return(s->next);
426 }
427 
428 /*
429  * Returns the name of the device node used to represent the slice.
430  * Note that the storage used for the returned string is static,
431  * and the string is overwritten each time this function is called.
432  */
433 const char *
434 slice_get_device_name(const struct slice *s)
435 {
436 	static char tmp_dev_name[256];
437 
438 	snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
439 	return(tmp_dev_name);
440 }
441 
442 int
443 slice_get_number(const struct slice *s)
444 {
445 	return(s->number);
446 }
447 
448 const char *
449 slice_get_desc(const struct slice *s)
450 {
451 	return(s->desc);
452 }
453 
454 unsigned long
455 slice_get_capacity(const struct slice *s)
456 {
457 	return(s->capacity);
458 }
459 
460 unsigned long
461 slice_get_start(const struct slice *s)
462 {
463 	return(s->start);
464 }
465 
466 unsigned long
467 slice_get_size(const struct slice *s)
468 {
469 	return(s->size);
470 }
471 
472 int
473 slice_get_type(const struct slice *s)
474 {
475 	return(s->type);
476 }
477 
478 int
479 slice_get_flags(const struct slice *s)
480 {
481 	return(s->flags);
482 }
483 
484 struct subpartition *
485 slice_subpartition_first(const struct slice *s)
486 {
487 	return(s->subpartition_head);
488 }
489 
490 /*
491  * Free all memory for a list of slice descriptions.
492  */
493 void
494 slices_free(struct slice *head)
495 {
496 	struct slice *next;
497 
498 	while (head != NULL) {
499 		next = head->next;
500 		subpartitions_free(head);
501 		free(head->desc);
502 		AURA_FREE(head, slice);
503 		head = next;
504 	}
505 }
506 
507 struct subpartition *
508 subpartition_new_hammer(struct slice *s, const char *mountpoint, long capacity,
509     int encrypted)
510 {
511 	struct subpartition *sp;
512 
513 	AURA_MALLOC(sp, subpartition);
514 
515 	sp->parent = s;
516 
517 	struct subpartition *last = s->subpartition_tail;
518 	if (last == NULL) {
519 		sp->letter = 'a';
520 	} else if (last->letter == 'b') {
521 		sp->letter = 'd';
522 	} else {
523 		sp->letter = (char)(last->letter + 1);
524 	}
525 
526 	sp->mountpoint = aura_strdup(mountpoint);
527 	sp->capacity = capacity;
528 	sp->encrypted = encrypted;
529 	sp->type = FS_HAMMER;
530 
531 	/*
532 	 * We need this here, because a UFS /boot needs valid values
533 	 */
534 	if (sp->capacity < 1024)
535 		sp->fsize = 1024;
536 	else
537 		sp->fsize = 2048;
538 
539 	if (sp->capacity < 1024)
540 		sp->bsize = 8192;
541 	else
542 		sp->bsize = 16384;
543 
544 	sp->is_swap = 0;
545 	sp->pfs = 0;
546 	if (strcasecmp(mountpoint, "swap") == 0)
547 		sp->is_swap = 1;
548 	if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 &&
549 	    strcmp(mountpoint, "swap") != 0)
550 		sp->pfs = 1;
551 
552 	sp->next = NULL;
553 	if (s->subpartition_head == NULL)
554 		s->subpartition_head = sp;
555 	else
556 		s->subpartition_tail->next = sp;
557 
558 	sp->prev = s->subpartition_tail;
559 	s->subpartition_tail = sp;
560 
561 	return(sp);
562 }
563 
564 /*
565  * NOTE: arguments to this function are not checked for sanity.
566  *
567  * fsize and/or bsize may both be -1, indicating
568  * "choose a reasonable default."
569  */
570 struct subpartition *
571 subpartition_new_ufs(struct slice *s, const char *mountpoint, long capacity,
572     int encrypted, int softupdates, long fsize, long bsize, int tmpfsbacked)
573 {
574 	struct subpartition *sp, *sptmp;
575 	int letter='d';
576 
577 	AURA_MALLOC(sp, subpartition);
578 
579 	sp->parent = s;
580 
581 	sp->mountpoint = aura_strdup(mountpoint);
582 	sp->capacity = capacity;
583 	sp->encrypted = encrypted;
584 	sp->type = FS_UFS;
585 
586 	if (fsize == -1) {
587 		if (sp->capacity < 1024)
588 			sp->fsize = 1024;
589 		else
590 			sp->fsize = 2048;
591 	} else {
592 		sp->fsize = fsize;
593 	}
594 
595 	if (bsize == -1) {
596 		if (sp->capacity < 1024)
597 			sp->bsize = 8192;
598 		else
599 			sp->bsize = 16384;
600 	} else {
601 		sp->bsize = bsize;
602 	}
603 
604 	if (softupdates == -1) {
605 		if (strcmp(mountpoint, "/") == 0)
606 			sp->softupdates = 0;
607 		else
608 			sp->softupdates = 1;
609 	} else {
610 		sp->softupdates = softupdates;
611 	}
612 
613 	sp->tmpfsbacked = tmpfsbacked;
614 
615 	sp->is_swap = 0;
616 	if (strcasecmp(mountpoint, "swap") == 0)
617 		sp->is_swap = 1;
618 
619 	if (s->subpartition_head == NULL) {
620 		s->subpartition_head = sp;
621 		s->subpartition_tail = sp;
622 	} else {
623 		for (sptmp = s->subpartition_head; sptmp != NULL;
624 		     sptmp = sptmp->next) {
625 			if (strcmp(sptmp->mountpoint, sp->mountpoint) > 0)
626 				break;
627 		}
628 		if (sptmp != NULL) {
629 			if (s->subpartition_head == sptmp)
630 				s->subpartition_head = sp;
631 			else
632 				sptmp->prev->next = sp;
633 			sp->next = sptmp;
634 			sp->prev = sptmp->prev;
635 			sptmp->prev = sp;
636 		} else {
637 			sp->prev = s->subpartition_tail;
638 			s->subpartition_tail->next = sp;
639 			s->subpartition_tail = sp;
640 		}
641 	}
642 
643 	for (sptmp = s->subpartition_head; sptmp != NULL;
644 	     sptmp = sptmp->next) {
645 		if (sptmp->tmpfsbacked)
646 			sptmp->letter = '@';
647 		else if (strcmp(sptmp->mountpoint, "/") == 0 ||
648 			 strcmp(sptmp->mountpoint, "/dummy") == 0)
649 			sptmp->letter = 'a';
650 		else if (strcasecmp(sptmp->mountpoint, "swap") == 0)
651 			sptmp->letter = 'b';
652 		else
653 			sptmp->letter = letter++;
654 	}
655 
656 	return(sp);
657 }
658 
659 /*
660  * Find the subpartition description in the given storage
661  * description whose mountpoint matches the given string exactly.
662  */
663 struct subpartition *
664 subpartition_find(const struct slice *s, const char *fmt, ...)
665 {
666 	struct subpartition *sp = s->subpartition_head;
667 	char *mountpoint;
668 	va_list args;
669 
670 	va_start(args, fmt);
671 	vasprintf(&mountpoint, fmt, args);
672 	va_end(args);
673 
674 	while (sp != NULL) {
675 		if (strcmp(mountpoint, sp->mountpoint) == 0) {
676 			free(mountpoint);
677 			return(sp);
678 		}
679 		sp = sp->next;
680 	}
681 
682 	free(mountpoint);
683 	return(NULL);
684 }
685 
686 /*
687  * Find the subpartition description in the given storage
688  * description where the given filename would presumably
689  * reside.  This is the subpartition whose mountpoint is
690  * the longest match for the given filename.
691  */
692 struct subpartition *
693 subpartition_of(const struct slice *s, const char *fmt, ...)
694 {
695 	struct subpartition *sp = s->subpartition_head;
696 	struct subpartition *csp = NULL;
697 	size_t len = 0;
698 	char *filename;
699 	va_list args;
700 
701 	va_start(args, fmt);
702 	vasprintf(&filename, fmt, args);
703 	va_end(args);
704 
705 	while (sp != NULL) {
706 		if (strlen(sp->mountpoint) > len &&
707 		    strlen(sp->mountpoint) <= strlen(filename) &&
708 		    strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
709 				csp = sp;
710 				len = strlen(csp->mountpoint);
711 		}
712 		sp = sp->next;
713 	}
714 
715 	free(filename);
716 	return(csp);
717 }
718 
719 struct subpartition *
720 subpartition_find_capacity(const struct slice *s, long capacity)
721 {
722 	struct subpartition *sp = s->subpartition_head;
723 
724 	while (sp != NULL) {
725 		if (sp->capacity == capacity)
726 			return(sp);
727 		sp = sp->next;
728 	}
729 
730 	return(NULL);
731 }
732 
733 struct subpartition *
734 subpartition_next(const struct subpartition *sp)
735 {
736 	return(sp->next);
737 }
738 
739 int
740 subpartition_get_pfs(const struct subpartition *sp)
741 {
742 	return(sp->pfs);
743 }
744 
745 /*
746  * Returns the name of the device node used to represent
747  * the subpartition, either by serial number or traditional style.
748  * Note that the storage used for the returned string is static,
749  * and the string is overwritten each time this function is called.
750  */
751 const char *
752 subpartition_get_device_name(const struct subpartition *sp)
753 {
754 	static char tmp_dev_name[256];
755 
756 	if (sp->parent->parent->serno != NULL)
757 		snprintf(tmp_dev_name, 256, "serno/%s.s%d%c",
758 		    sp->parent->parent->serno, sp->parent->number, sp->letter);
759 	else
760 		snprintf(tmp_dev_name, 256, "%ss%d%c",
761 		    sp->parent->parent->device, sp->parent->number, sp->letter);
762 	return(tmp_dev_name);
763 }
764 
765 const char *
766 subpartition_get_mountpoint(const struct subpartition *sp)
767 {
768 	return(sp->mountpoint);
769 }
770 
771 char
772 subpartition_get_letter(const struct subpartition *sp)
773 {
774 	return(sp->letter);
775 }
776 
777 unsigned long
778 subpartition_get_fsize(const struct subpartition *sp)
779 {
780 	return(sp->fsize);
781 }
782 
783 unsigned long
784 subpartition_get_bsize(const struct subpartition *sp)
785 {
786 	return(sp->bsize);
787 }
788 
789 long
790 subpartition_get_capacity(const struct subpartition *sp)
791 {
792 	return(sp->capacity);
793 }
794 
795 void
796 subpartition_clr_encrypted(struct subpartition *sp)
797 {
798 	sp->encrypted = 0;
799 }
800 
801 int
802 subpartition_is_encrypted(const struct subpartition *sp)
803 {
804 	return(sp->encrypted);
805 }
806 
807 int
808 subpartition_is_swap(const struct subpartition *sp)
809 {
810 	return(sp->is_swap);
811 }
812 
813 int
814 subpartition_is_softupdated(const struct subpartition *sp)
815 {
816 	return(sp->softupdates);
817 }
818 int
819 subpartition_is_tmpfsbacked(const struct subpartition *sp)
820 {
821 	return(sp->tmpfsbacked);
822 }
823 
824 int
825 subpartition_count(const struct slice *s)
826 {
827 	struct subpartition *sp = s->subpartition_head;
828 	int count = 0;
829 
830 	while (sp != NULL) {
831 		count++;
832 		sp = sp->next;
833 	}
834 
835 	return(count);
836 }
837 
838 void
839 subpartitions_free(struct slice *s)
840 {
841 	struct subpartition *sp = s->subpartition_head, *next;
842 
843 	while (sp != NULL) {
844 		next = sp->next;
845 		free(sp->mountpoint);
846 		AURA_FREE(sp, subpartition);
847 		sp = next;
848 	}
849 
850 	s->subpartition_head = NULL;
851 	s->subpartition_tail = NULL;
852 }
853 
854 long
855 measure_activated_swap(const struct i_fn_args *a)
856 {
857 	FILE *p;
858 	char line[256];
859 	char *word;
860 	long swap = 0;
861 
862 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
863 		return(0);
864 	while (fgets(line, 255, p) != NULL) {
865 		if ((word = strtok(line, " \t")) == NULL)
866 			continue;
867 		if (strcmp(word, "Device") == 0)
868 			continue;
869 		if ((word = strtok(NULL, " \t")) == NULL)
870 			continue;
871 		swap += atol(word);
872 	}
873 	aura_pclose(p);
874 
875 	return(swap / 1024);
876 }
877 
878 long
879 measure_activated_swap_from_slice(const struct i_fn_args *a,
880     const struct disk *d, const struct slice *s)
881 {
882 	FILE *p;
883 	char *dev, *word;
884 	char line[256];
885 	long swap = 0;
886 
887 	if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
888 		return(0);
889 
890 	asprintf(&dev, "/dev/%ss%d", d->device, s->number);
891 
892 	while (fgets(line, 255, p) != NULL) {
893 		if ((word = strtok(line, " \t")) == NULL)
894 			continue;
895 		if (strcmp(word, "Device") == 0)
896 			continue;
897 		if (strstr(word, dev) != word)
898 			continue;
899 		if ((word = strtok(NULL, " \t")) == NULL)
900 			continue;
901 		swap += atol(word);
902 	}
903 	aura_pclose(p);
904 	free(dev);
905 
906 	return(swap / 1024);
907 }
908 
909 long
910 measure_activated_swap_from_disk(const struct i_fn_args *a,
911 				 const struct disk *d)
912 {
913 	struct slice *s;
914 	long swap = 0;
915 
916 	for (s = d->slice_head; s != NULL; s = s->next)
917 		swap += measure_activated_swap_from_slice(a, d, s);
918 
919 	return(swap);
920 }
921 
922 void *
923 swapoff_all(const struct i_fn_args *a)
924 {
925 	FILE *p;
926 
927 	if ((p = aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r",
928 		    a->os_root, cmd_name(a, "DUMPON"),
929 		    a->os_root, cmd_name(a, "SWAPINFO"),
930 		    a->os_root, cmd_name(a, "GREP"),
931 		    a->os_root, cmd_name(a, "AWK"),
932 		    a->os_root, cmd_name(a, "XARGS"),
933 		    a->os_root, cmd_name(a, "SWAPOFF"))) != NULL)
934 		aura_pclose(p);
935 
936 	return(p);
937 }
938 
939 void *
940 remove_all_mappings(const struct i_fn_args *a)
941 {
942 	FILE *p;
943 
944 	if ((p = aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r",
945 		    a->os_root, cmd_name(a, "LS"),
946 		    a->os_root, cmd_name(a, "GREP"),
947 		    a->os_root, cmd_name(a, "XARGS"),
948 		    a->os_root, cmd_name(a, "CRYPTSETUP"))) != NULL)
949 		aura_pclose(p);
950 
951 	return(p);
952 }
953