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