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