Add HAMMER support to the installer
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / lib / libinstaller / diskutil.c
CommitLineData
337ad0df
DH
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
bc3d4063
SW
45#include "libaura/mem.h"
46#include "libaura/fspred.h"
47#include "libaura/popen.h"
337ad0df 48
bc3d4063
SW
49#include "libdfui/dfui.h"
50#include "libdfui/dump.h"
337ad0df
DH
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
61static int disk_description_is_better(const char *, const char *);
62
63/** STORAGE DESCRIPTORS **/
64
65struct storage *
66storage_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
81int
82storage_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
99void
100storage_free(struct storage *s)
101{
102 disks_free(s);
103 AURA_FREE(s, storage);
104}
105
106void
107storage_set_memsize(struct storage *s, unsigned long memsize)
108{
109 s->ram = memsize;
110}
111
112unsigned long
113storage_get_memsize(const struct storage *s)
114{
115 return(s->ram);
116}
117
118struct disk *
119storage_disk_first(const struct storage *s)
120{
121 return(s->disk_head);
122}
123
124void
125storage_set_selected_disk(struct storage *s, struct disk *d)
126{
127 s->selected_disk = d;
128}
129
130struct disk *
131storage_get_selected_disk(const struct storage *s)
132{
133 return(s->selected_disk);
134}
135
136void
137storage_set_selected_slice(struct storage *s, struct slice *sl)
138{
139 s->selected_slice = sl;
140}
141
142struct slice *
143storage_get_selected_slice(const struct storage *s)
144{
145 return(s->selected_slice);
146}
147
148/*
149 * Create a new disk description structure.
150 */
151struct disk *
152disk_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
187static int
188disk_description_is_better(const char *existing, const char *new_desc __unused)
189{
190 if (existing == NULL)
191 return(1);
192 return(0);
193}
194
195const char *
196disk_get_desc(const struct disk *d)
197{
198 return(d->desc);
199}
200
201void
202disk_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 */
230const char *
231disk_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 */
252const char *
253disk_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 */
277struct disk *
278disk_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
291struct disk *
292disk_next(const struct disk *d)
293{
294 return(d->next);
295}
296
297struct slice *
298disk_slice_first(const struct disk *d)
299{
300 return(d->slice_head);
301}
302
303void
304disk_set_formatted(struct disk *d, int formatted)
305{
306 d->we_formatted = formatted;
307}
308
309int
310disk_get_formatted(const struct disk *d)
311{
312 return(d->we_formatted);
313}
314
315void
316disk_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
323void
324disk_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 */
334void
335disks_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 */
355struct slice *
356slice_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 */
413struct slice *
414slice_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
427struct slice *
428slice_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 */
438const char *
439slice_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 */
462const char *
463slice_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
479int
480slice_get_number(const struct slice *s)
481{
482 return(s->number);
483}
484
485const char *
486slice_get_desc(const struct slice *s)
487{
488 return(s->desc);
489}
490
491unsigned long
492slice_get_capacity(const struct slice *s)
493{
494 return(s->capacity);
495}
496
497unsigned long
498slice_get_start(const struct slice *s)
499{
500 return(s->start);
501}
502
503unsigned long
504slice_get_size(const struct slice *s)
505{
506 return(s->size);
507}
508
509int
510slice_get_type(const struct slice *s)
511{
512 return(s->type);
513}
514
515int
516slice_get_flags(const struct slice *s)
517{
518 return(s->flags);
519}
520
521struct subpartition *
522slice_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 */
530void
531slices_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
971d1cca
MS
544struct subpartition *
545subpartition_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
337ad0df
DH
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 */
605struct subpartition *
606subpartition_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;
971d1cca 633 sp->type = FS_UFS;
337ad0df
DH
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 */
684struct subpartition *
685subpartition_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 */
713struct subpartition *
714subpartition_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
740struct subpartition *
741subpartition_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
754struct subpartition *
755subpartition_next(const struct subpartition *sp)
756{
757 return(sp->next);
758}
759
971d1cca
MS
760int
761subpartition_get_pfs(const struct subpartition *sp)
762{
763 return(sp->pfs);
764}
765
337ad0df
DH
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 */
772const char *
773subpartition_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 */
793const char *
794subpartition_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
811const char *
812subpartition_get_mountpoint(const struct subpartition *sp)
813{
814 return(sp->mountpoint);
815}
816
817char
818subpartition_get_letter(const struct subpartition *sp)
819{
820 return(sp->letter);
821}
822
823unsigned long
824subpartition_get_fsize(const struct subpartition *sp)
825{
826 return(sp->fsize);
827}
828
829unsigned long
830subpartition_get_bsize(const struct subpartition *sp)
831{
832 return(sp->bsize);
833}
834
835unsigned long
836subpartition_get_capacity(const struct subpartition *sp)
837{
838 return(sp->capacity);
839}
840
841int
842subpartition_is_swap(const struct subpartition *sp)
843{
844 return(sp->is_swap);
845}
846
847int
848subpartition_is_softupdated(const struct subpartition *sp)
849{
850 return(sp->softupdates);
851}
852int
853subpartition_is_mfsbacked(const struct subpartition *sp)
854{
855 return(sp->mfsbacked);
856}
857
858int
859subpartition_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
872void
873subpartitions_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
888long
889measure_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
912long
913measure_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
943long
944measure_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}