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