0ad699f47e7c897ae4173e9d8338a2aa77025efa
[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 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 }