installer: Always take the root directory's /dev.
[dragonfly.git] / usr.sbin / installer / libinstaller / diskutil.c
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 }