Add HAMMER support to the installer
[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;
610
611         AURA_MALLOC(sp, subpartition);
612
613         sp->parent = s;
614
615         if (mfsbacked) {
616                 sp->letter = '@';
617         } else {
618                 struct subpartition *last = s->subpartition_tail;
619                 while (last != NULL && last->mfsbacked) {
620                         last = last->prev;
621                 }
622                 if (last == NULL) {
623                         sp->letter = 'a';
624                 } else if (last->letter == 'b') {
625                         sp->letter = 'd';
626                 } else {
627                         sp->letter = (char)(last->letter + 1);
628                 }
629         }
630
631         sp->mountpoint = aura_strdup(mountpoint);
632         sp->capacity = capacity;
633         sp->type = FS_UFS;
634
635         if (fsize == -1) {
636                 if (sp->capacity < 1024)
637                         sp->fsize = 1024;
638                 else
639                         sp->fsize = 2048;
640         } else {
641                 sp->fsize = fsize;
642         }
643
644         if (bsize == -1) {
645                 if (sp->capacity < 1024)
646                         sp->bsize = 8192;
647                 else
648                         sp->bsize = 16384;
649         } else {
650                 sp->bsize = bsize;
651         }
652
653         if (softupdates == -1) {
654                 if (strcmp(mountpoint, "/") == 0)
655                         sp->softupdates = 0;
656                 else
657                         sp->softupdates = 1;
658         } else {
659                 sp->softupdates = softupdates;
660         }
661
662         sp->mfsbacked = mfsbacked;
663
664         sp->is_swap = 0;
665         if (strcasecmp(mountpoint, "swap") == 0)
666                 sp->is_swap = 1;
667
668         sp->next = NULL;
669         if (s->subpartition_head == NULL)
670                 s->subpartition_head = sp;
671         else
672                 s->subpartition_tail->next = sp;
673
674         sp->prev = s->subpartition_tail;
675         s->subpartition_tail = sp;
676
677         return(sp);
678 }
679
680 /*
681  * Find the subpartition description in the given storage
682  * description whose mountpoint matches the given string exactly.
683  */
684 struct subpartition *
685 subpartition_find(const struct slice *s, const char *fmt, ...)
686 {
687         struct subpartition *sp = s->subpartition_head;
688         char *mountpoint;
689         va_list args;
690
691         va_start(args, fmt);
692         vasprintf(&mountpoint, fmt, args);
693         va_end(args);
694
695         while (sp != NULL) {
696                 if (strcmp(mountpoint, sp->mountpoint) == 0) {
697                         free(mountpoint);
698                         return(sp);
699                 }
700                 sp = sp->next;
701         }
702
703         free(mountpoint);
704         return(NULL);
705 }
706
707 /*
708  * Find the subpartition description in the given storage
709  * description where the given filename would presumably
710  * reside.  This is the subpartition whose mountpoint is
711  * the longest match for the given filename.
712  */
713 struct subpartition *
714 subpartition_of(const struct slice *s, const char *fmt, ...)
715 {
716         struct subpartition *sp = s->subpartition_head;
717         struct subpartition *csp = NULL;
718         size_t len = 0;
719         char *filename;
720         va_list args;
721
722         va_start(args, fmt);
723         vasprintf(&filename, fmt, args);
724         va_end(args);
725
726         while (sp != NULL) {
727                 if (strlen(sp->mountpoint) > len &&
728                     strlen(sp->mountpoint) <= strlen(filename) &&
729                     strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
730                                 csp = sp;
731                                 len = strlen(csp->mountpoint);
732                 }
733                 sp = sp->next;
734         }
735
736         free(filename);
737         return(csp);
738 }
739
740 struct subpartition *
741 subpartition_find_capacity(const struct slice *s, long capacity)
742 {
743         struct subpartition *sp = s->subpartition_head;
744
745         while (sp != NULL) {
746                 if (sp->capacity == capacity)
747                         return(sp);
748                 sp = sp->next;
749         }
750
751         return(NULL);
752 }
753
754 struct subpartition *
755 subpartition_next(const struct subpartition *sp)
756 {
757         return(sp->next);
758 }
759
760 int
761 subpartition_get_pfs(const struct subpartition *sp)
762 {
763         return(sp->pfs);
764 }
765
766 /*
767  * Returns the name of the device node used to represent
768  * the subpartition.
769  * Note that the storage used for the returned string is static,
770  * and the string is overwritten each time this function is called.
771  */
772 const char *
773 subpartition_get_device_name(const struct subpartition *sp)
774 {
775         static char tmp_dev_name[256];
776
777 #ifdef __OpenBSD__
778         snprintf(tmp_dev_name, 256, "%s%c", sp->parent->parent->device,
779             sp->letter);
780 #else
781         snprintf(tmp_dev_name, 256, "%ss%d%c", sp->parent->parent->device,
782             sp->parent->number, sp->letter);
783 #endif
784         return(tmp_dev_name);
785 }
786
787 /*
788  * Returns the name of the device node used to represent
789  * the raw subpartition.
790  * Note that the storage used for the returned string is static,
791  * and the string is overwritten each time this function is called.
792  */
793 const char *
794 subpartition_get_raw_device_name(const struct subpartition *sp)
795 {
796         static char tmp_dev_name[256];
797
798         /*
799          * for OpenBSD, this has an "r" prepended to it.
800          */
801 #ifdef __OpenBSD__
802         snprintf(tmp_dev_name, 256, "r%s%c", sp->parent->parent->device,
803             sp->letter);
804 #else
805         snprintf(tmp_dev_name, 256, "r%ss%d%c", sp->parent->parent->device,
806             sp->parent->number, sp->letter);
807 #endif
808         return(tmp_dev_name);
809 }
810
811 const char *
812 subpartition_get_mountpoint(const struct subpartition *sp)
813 {
814         return(sp->mountpoint);
815 }
816
817 char
818 subpartition_get_letter(const struct subpartition *sp)
819 {
820         return(sp->letter);
821 }
822
823 unsigned long
824 subpartition_get_fsize(const struct subpartition *sp)
825 {
826         return(sp->fsize);
827 }
828
829 unsigned long
830 subpartition_get_bsize(const struct subpartition *sp)
831 {
832         return(sp->bsize);
833 }
834
835 unsigned long
836 subpartition_get_capacity(const struct subpartition *sp)
837 {
838         return(sp->capacity);
839 }
840
841 int
842 subpartition_is_swap(const struct subpartition *sp)
843 {
844         return(sp->is_swap);
845 }
846
847 int
848 subpartition_is_softupdated(const struct subpartition *sp)
849 {
850         return(sp->softupdates);
851 }
852 int 
853 subpartition_is_mfsbacked(const struct subpartition *sp)
854 {
855         return(sp->mfsbacked);
856 }
857
858 int
859 subpartition_count(const struct slice *s)
860 {
861         struct subpartition *sp = s->subpartition_head;
862         int count = 0;
863
864         while (sp != NULL) {
865                 count++;
866                 sp = sp->next;
867         }
868
869         return(count);
870 }
871
872 void
873 subpartitions_free(struct slice *s)
874 {
875         struct subpartition *sp = s->subpartition_head, *next;
876
877         while (sp != NULL) {
878                 next = sp->next;
879                 free(sp->mountpoint);
880                 AURA_FREE(sp, subpartition);
881                 sp = next;
882         }
883
884         s->subpartition_head = NULL;
885         s->subpartition_tail = NULL;
886 }
887
888 long
889 measure_activated_swap(const struct i_fn_args *a)
890 {
891         FILE *p;
892         char line[256];
893         char *word;
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         while (fgets(line, 255, p) != NULL) {
899                 if ((word = strtok(line, " \t")) == NULL)
900                         continue;
901                 if (strcmp(word, "Device") == 0)
902                         continue;
903                 if ((word = strtok(NULL, " \t")) == NULL)
904                         continue;
905                 swap += atol(word);
906         }
907         aura_pclose(p);
908
909         return(swap / 1024);
910 }
911
912 long
913 measure_activated_swap_from_slice(const struct i_fn_args *a,
914     const struct disk *d, const struct slice *s)
915 {
916         FILE *p;
917         char *dev, *word;
918         char line[256];
919         long swap = 0;
920
921         if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
922                 return(0);
923
924         asprintf(&dev, "/dev/%ss%d", d->device, s->number);
925
926         while (fgets(line, 255, p) != NULL) {
927                 if ((word = strtok(line, " \t")) == NULL)
928                         continue;
929                 if (strcmp(word, "Device") == 0)
930                         continue;
931                 if (strstr(word, dev) != word)
932                         continue;
933                 if ((word = strtok(NULL, " \t")) == NULL)
934                         continue;
935                 swap += atol(word);
936         }
937         aura_pclose(p);
938         free(dev);
939
940         return(swap / 1024);
941 }
942
943 long
944 measure_activated_swap_from_disk(const struct i_fn_args *a,
945                                  const struct disk *d)
946 {
947         struct slice *s;
948         long swap = 0;
949
950         for (s = d->slice_head; s != NULL; s = s->next)
951                 swap += measure_activated_swap_from_slice(a, d, s);
952
953         return(swap);
954 }