1 /* 2 * Copyright (c)2004,2015 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * Neither the name of the DragonFly Project nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * diskutil.c 36 * Disk utility functions for installer. 37 * $Id: diskutil.c,v 1.44 2005/02/07 06:41:42 cpressey Exp $ 38 */ 39 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #include "libaura/mem.h" 46 #include "libaura/fspred.h" 47 #include "libaura/popen.h" 48 49 #include "libdfui/dfui.h" 50 #include "libdfui/dump.h" 51 52 #define NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS 53 #include "diskutil.h" 54 #undef NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS 55 56 #include "commands.h" 57 #include "functions.h" 58 #include "sysids.h" 59 #include "uiutil.h" 60 61 static int disk_description_is_better(const char *, const char *); 62 63 /** STORAGE DESCRIPTORS **/ 64 65 struct storage * 66 storage_new(void) 67 { 68 struct storage *s; 69 70 AURA_MALLOC(s, storage); 71 72 s->disk_head = NULL; 73 s->disk_tail = NULL; 74 s->selected_disk = NULL; 75 s->selected_slice = NULL; 76 s->ram = -1; 77 78 return(s); 79 } 80 81 int 82 storage_get_tmpfs_status(const char *mountpoint, struct storage *s) 83 { 84 struct subpartition *sp; 85 sp = NULL; 86 for (sp = slice_subpartition_first(s->selected_slice); 87 sp != NULL; sp = subpartition_next(sp)) { 88 if(strcmp(subpartition_get_mountpoint(sp), mountpoint) == 0) { 89 if(subpartition_is_tmpfsbacked(sp) == 1) { 90 return 1; 91 } else { 92 return 0; 93 } 94 } 95 } 96 return 0; 97 } 98 99 void 100 storage_free(struct storage *s) 101 { 102 disks_free(s); 103 AURA_FREE(s, storage); 104 } 105 106 void 107 storage_set_memsize(struct storage *s, unsigned long memsize) 108 { 109 s->ram = memsize; 110 } 111 112 long 113 storage_get_memsize(const struct storage *s) 114 { 115 return(s->ram); 116 } 117 118 struct disk * 119 storage_disk_first(const struct storage *s) 120 { 121 return(s->disk_head); 122 } 123 124 void 125 storage_set_selected_disk(struct storage *s, struct disk *d) 126 { 127 s->selected_disk = d; 128 } 129 130 struct disk * 131 storage_get_selected_disk(const struct storage *s) 132 { 133 return(s->selected_disk); 134 } 135 136 void 137 storage_set_selected_slice(struct storage *s, struct slice *sl) 138 { 139 s->selected_slice = sl; 140 } 141 142 struct slice * 143 storage_get_selected_slice(const struct storage *s) 144 { 145 return(s->selected_slice); 146 } 147 148 /* 149 * Create a new disk description structure. 150 */ 151 struct disk * 152 disk_new(struct storage *s, const char *dev_name) 153 { 154 struct disk *d; 155 156 AURA_MALLOC(d, disk); 157 158 d->device = aura_strdup(dev_name); 159 d->desc = NULL; 160 d->serno = NULL; 161 d->we_formatted = 0; 162 d->capacity = 0; 163 164 d->cylinders = -1; /* -1 indicates "we don't know" */ 165 d->heads = -1; 166 d->sectors = -1; 167 168 d->slice_head = NULL; 169 d->slice_tail = NULL; 170 171 d->next = NULL; 172 if (s->disk_head == NULL) 173 s->disk_head = d; 174 else 175 s->disk_tail->next = d; 176 177 d->prev = s->disk_tail; 178 s->disk_tail = d; 179 180 return(d); 181 } 182 183 static int 184 disk_description_is_better(const char *existing, const char *new_desc __unused) 185 { 186 if (existing == NULL) 187 return(1); 188 return(0); 189 } 190 191 const char * 192 disk_get_desc(const struct disk *d) 193 { 194 return(d->desc); 195 } 196 197 unsigned long 198 disk_get_capacity(const struct disk *d) 199 { 200 return(d->capacity); 201 } 202 203 204 void 205 disk_set_desc(struct disk *d, const char *desc) 206 { 207 char *c; 208 209 if (!disk_description_is_better(d->desc, desc)) 210 return; 211 if (d->desc != NULL) 212 free(d->desc); 213 d->desc = aura_strdup(desc); 214 215 /* 216 * Get the disk's total capacity. 217 * XXX we should do this with C/H/S ? 218 */ 219 c = d->desc; 220 while (*c != ':' && *c != '\0') 221 c++; 222 if (*c == '\0') 223 d->capacity = 0; 224 else 225 d->capacity = strtoul(c + 1, NULL, 0); 226 } 227 228 /* 229 * Returns the name of the device node used to represent the disk. 230 * Note that the storage used for the returned string is static, 231 * and the string is overwritten each time this function is called. 232 */ 233 const char * 234 disk_get_device_name(const struct disk *d) 235 { 236 static char tmp_dev_name[256]; 237 238 snprintf(tmp_dev_name, 256, "%s", d->device); 239 return(tmp_dev_name); 240 } 241 242 const char * 243 disk_get_serno(const struct disk *d) 244 { 245 return(d->serno); 246 } 247 248 void 249 disk_set_serno(struct disk *d, const char *serno) 250 { 251 d->serno = aura_strdup(serno); 252 } 253 254 int 255 disk_get_number(const struct disk *d) 256 { 257 return(d->number); 258 } 259 260 void 261 disk_set_number(struct disk *d, const int number) 262 { 263 d->number = number; 264 } 265 266 /* 267 * Find the first disk description structure in the given 268 * storage description which matches the given device name 269 * prefix. Note that this means that if a storage 270 * description s contains disks named "ad0" and "ad1", 271 * disk_find(s, "ad0s1c") will return a pointer to the disk 272 * structure for "ad0". 273 */ 274 struct disk * 275 disk_find(const struct storage *s, const char *device) 276 { 277 struct disk *d = s->disk_head; 278 279 while (d != NULL) { 280 if (strncmp(device, d->device, strlen(d->device)) == 0 && 281 strlen(device) == strlen(d->device)) 282 return(d); 283 d = d->next; 284 } 285 286 return(NULL); 287 } 288 289 struct disk * 290 disk_next(const struct disk *d) 291 { 292 return(d->next); 293 } 294 295 struct slice * 296 disk_slice_first(const struct disk *d) 297 { 298 return(d->slice_head); 299 } 300 301 void 302 disk_set_formatted(struct disk *d, int formatted) 303 { 304 d->we_formatted = formatted; 305 } 306 307 int 308 disk_get_formatted(const struct disk *d) 309 { 310 return(d->we_formatted); 311 } 312 313 void 314 disk_set_geometry(struct disk *d, int cyl, int hd, int sec) 315 { 316 d->cylinders = cyl; 317 d->heads = hd; 318 d->sectors = sec; 319 } 320 321 void 322 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec) 323 { 324 *cyl = d->cylinders; 325 *hd = d->heads; 326 *sec = d->sectors; 327 } 328 329 /* 330 * Free the memory allocated to hold the set of disk descriptions. 331 */ 332 void 333 disks_free(struct storage *s) 334 { 335 struct disk *d = s->disk_head, *next; 336 337 while (d != NULL) { 338 next = d->next; 339 slices_free(d->slice_head); 340 free(d->desc); 341 free(d->device); 342 AURA_FREE(d, disk); 343 d = next; 344 } 345 346 s->disk_head = NULL; 347 s->disk_tail = NULL; 348 } 349 350 /* 351 * Create a new slice description and add it to a disk description. 352 */ 353 struct slice * 354 slice_new(struct disk *d, int number, int type, int flags, 355 unsigned long start, unsigned long size) 356 { 357 struct slice *s; 358 const char *sysid_desc = NULL; 359 char unknown[256]; 360 int i; 361 362 dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) " 363 "to disk %s\n", number, start, size, type, d->device); 364 365 AURA_MALLOC(s, slice); 366 367 s->parent = d; 368 369 s->subpartition_head = NULL; 370 s->subpartition_tail = NULL; 371 s->number = number; 372 373 s->type = type; 374 s->flags = flags; 375 s->start = start; 376 s->size = size; 377 378 for (i = 0; ; i++) { 379 if (part_types[i].type == type) { 380 sysid_desc = part_types[i].name; 381 break; 382 } 383 if (part_types[i].type == 255) 384 break; 385 } 386 if (sysid_desc == NULL) { 387 snprintf(unknown, 256, "??? Unknown, sysid = %d", type); 388 sysid_desc = unknown; 389 } 390 391 asprintf(&s->desc, "%ldM - %ldM: %s", 392 start / 2048, (start + size) / 2048, sysid_desc); 393 s->capacity = size / 2048; 394 395 s->next = NULL; 396 if (d->slice_head == NULL) 397 d->slice_head = s; 398 else 399 d->slice_tail->next = s; 400 401 s->prev = d->slice_tail; 402 d->slice_tail = s; 403 404 return(s); 405 } 406 407 /* 408 * Find a slice description on a given disk description given the 409 * slice number. 410 */ 411 struct slice * 412 slice_find(const struct disk *d, int number) 413 { 414 struct slice *s = d->slice_head; 415 416 while (s != NULL) { 417 if (s->number == number) 418 return(s); 419 s = s->next; 420 } 421 422 return(NULL); 423 } 424 425 struct slice * 426 slice_next(const struct slice *s) 427 { 428 return(s->next); 429 } 430 431 /* 432 * Returns the name of the device node used to represent the slice. 433 * Note that the storage used for the returned string is static, 434 * and the string is overwritten each time this function is called. 435 */ 436 const char * 437 slice_get_device_name(const struct slice *s) 438 { 439 static char tmp_dev_name[256]; 440 441 snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number); 442 return(tmp_dev_name); 443 } 444 445 int 446 slice_get_number(const struct slice *s) 447 { 448 return(s->number); 449 } 450 451 const char * 452 slice_get_desc(const struct slice *s) 453 { 454 return(s->desc); 455 } 456 457 unsigned long 458 slice_get_capacity(const struct slice *s) 459 { 460 return(s->capacity); 461 } 462 463 unsigned long 464 slice_get_start(const struct slice *s) 465 { 466 return(s->start); 467 } 468 469 unsigned long 470 slice_get_size(const struct slice *s) 471 { 472 return(s->size); 473 } 474 475 int 476 slice_get_type(const struct slice *s) 477 { 478 return(s->type); 479 } 480 481 int 482 slice_get_flags(const struct slice *s) 483 { 484 return(s->flags); 485 } 486 487 struct subpartition * 488 slice_subpartition_first(const struct slice *s) 489 { 490 return(s->subpartition_head); 491 } 492 493 /* 494 * Free all memory for a list of slice descriptions. 495 */ 496 void 497 slices_free(struct slice *head) 498 { 499 struct slice *next; 500 501 while (head != NULL) { 502 next = head->next; 503 subpartitions_free(head); 504 free(head->desc); 505 AURA_FREE(head, slice); 506 head = next; 507 } 508 } 509 510 struct subpartition * 511 subpartition_new_hammer(struct slice *s, const char *mountpoint, long capacity, 512 int encrypted) 513 { 514 struct subpartition *sp; 515 struct subpartition *last = s->subpartition_tail; 516 517 AURA_MALLOC(sp, subpartition); 518 519 sp->parent = s; 520 521 if (last == NULL) { 522 sp->letter = 'a'; 523 } else if (last->letter == 'b') { 524 sp->letter = 'd'; 525 } else { 526 sp->letter = (char)(last->letter + 1); 527 } 528 if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0) 529 sp->letter = 'd'; 530 531 sp->mountpoint = aura_strdup(mountpoint); 532 sp->capacity = capacity; 533 sp->encrypted = encrypted; 534 sp->type = FS_HAMMER; 535 536 /* 537 * We need this here, because a UFS /boot needs valid values 538 */ 539 if (sp->capacity < 1024) 540 sp->fsize = 1024; 541 else 542 sp->fsize = 2048; 543 544 if (sp->capacity < 1024) 545 sp->bsize = 8192; 546 else 547 sp->bsize = 16384; 548 549 sp->is_swap = 0; 550 #if 0 551 sp->pfs = 0; 552 #endif 553 if (strcasecmp(mountpoint, "swap") == 0) 554 sp->is_swap = 1; 555 #if 0 556 if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 && 557 strcmp(mountpoint, "swap") != 0) 558 sp->pfs = 1; 559 #endif 560 561 sp->next = NULL; 562 if (s->subpartition_head == NULL) 563 s->subpartition_head = sp; 564 else 565 s->subpartition_tail->next = sp; 566 567 sp->prev = s->subpartition_tail; 568 s->subpartition_tail = sp; 569 570 return(sp); 571 } 572 573 /* 574 * NOTE: arguments to this function are not checked for sanity. 575 * 576 * fsize and/or bsize may both be -1, indicating 577 * "choose a reasonable default." 578 */ 579 struct subpartition * 580 subpartition_new_ufs(struct slice *s, const char *mountpoint, long capacity, 581 int encrypted, int softupdates, long fsize, long bsize, int tmpfsbacked) 582 { 583 struct subpartition *sp; 584 struct subpartition *last = s->subpartition_tail; 585 586 AURA_MALLOC(sp, subpartition); 587 588 if (tmpfsbacked) { 589 sp->letter = '@'; 590 } else { 591 while (last && last->letter == '@') 592 last = last->prev; 593 if (last == NULL) { 594 sp->letter = 'a'; 595 } else if (last->letter == 'b') { 596 sp->letter = 'd'; 597 } else { 598 sp->letter = (char)(last->letter + 1); 599 } 600 if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0) 601 sp->letter = 'd'; 602 } 603 604 sp->parent = s; 605 606 sp->mountpoint = aura_strdup(mountpoint); 607 sp->capacity = capacity; 608 sp->encrypted = encrypted; 609 sp->type = FS_UFS; 610 611 if (fsize == -1) { 612 if (sp->capacity < 1024) 613 sp->fsize = 1024; 614 else 615 sp->fsize = 2048; 616 } else { 617 sp->fsize = fsize; 618 } 619 620 if (bsize == -1) { 621 if (sp->capacity < 1024) 622 sp->bsize = 8192; 623 else 624 sp->bsize = 16384; 625 } else { 626 sp->bsize = bsize; 627 } 628 629 if (softupdates == -1) { 630 if (strcmp(mountpoint, "/") == 0) 631 sp->softupdates = 0; 632 else 633 sp->softupdates = 1; 634 } else { 635 sp->softupdates = softupdates; 636 } 637 638 sp->tmpfsbacked = tmpfsbacked; 639 640 sp->is_swap = 0; 641 if (strcasecmp(mountpoint, "swap") == 0) 642 sp->is_swap = 1; 643 644 /* 645 * install 646 */ 647 sp->next = NULL; 648 if (s->subpartition_head == NULL) 649 s->subpartition_head = sp; 650 else 651 s->subpartition_tail->next = sp; 652 653 sp->prev = s->subpartition_tail; 654 s->subpartition_tail = sp; 655 656 #if 0 657 658 for (sptmp = s->subpartition_head; sptmp != NULL; 659 sptmp = sptmp->next) { 660 if (sptmp->tmpfsbacked) 661 sptmp->letter = '@'; 662 else if (strcmp(sptmp->mountpoint, "/") == 0 || 663 strcmp(sptmp->mountpoint, "/dummy") == 0) 664 sptmp->letter = 'a'; 665 else if (strcasecmp(sptmp->mountpoint, "swap") == 0) 666 sptmp->letter = 'b'; 667 else 668 sptmp->letter = letter++; 669 } 670 #endif 671 672 return(sp); 673 } 674 675 /* 676 * Find the subpartition description in the given storage 677 * description whose mountpoint matches the given string exactly. 678 */ 679 struct subpartition * 680 subpartition_find(const struct slice *s, const char *fmt, ...) 681 { 682 struct subpartition *sp = s->subpartition_head; 683 char *mountpoint; 684 va_list args; 685 686 va_start(args, fmt); 687 vasprintf(&mountpoint, fmt, args); 688 va_end(args); 689 690 while (sp != NULL) { 691 if (strcmp(mountpoint, sp->mountpoint) == 0) { 692 free(mountpoint); 693 return(sp); 694 } 695 sp = sp->next; 696 } 697 698 free(mountpoint); 699 return(NULL); 700 } 701 702 /* 703 * Find the subpartition description in the given storage 704 * description where the given filename would presumably 705 * reside. This is the subpartition whose mountpoint is 706 * the longest match for the given filename. 707 */ 708 struct subpartition * 709 subpartition_of(const struct slice *s, const char *fmt, ...) 710 { 711 struct subpartition *sp = s->subpartition_head; 712 struct subpartition *csp = NULL; 713 size_t len = 0; 714 char *filename; 715 va_list args; 716 717 va_start(args, fmt); 718 vasprintf(&filename, fmt, args); 719 va_end(args); 720 721 while (sp != NULL) { 722 if (strlen(sp->mountpoint) > len && 723 strlen(sp->mountpoint) <= strlen(filename) && 724 strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) { 725 csp = sp; 726 len = strlen(csp->mountpoint); 727 } 728 sp = sp->next; 729 } 730 731 free(filename); 732 return(csp); 733 } 734 735 struct subpartition * 736 subpartition_find_capacity(const struct slice *s, long capacity) 737 { 738 struct subpartition *sp = s->subpartition_head; 739 740 while (sp != NULL) { 741 if (sp->capacity == capacity) 742 return(sp); 743 sp = sp->next; 744 } 745 746 return(NULL); 747 } 748 749 struct subpartition * 750 subpartition_next(const struct subpartition *sp) 751 { 752 return(sp->next); 753 } 754 755 int 756 subpartition_get_pfs(const struct subpartition *sp) 757 { 758 return(sp->pfs); 759 } 760 761 /* 762 * Returns the name of the device node used to represent 763 * the subpartition, either by serial number or traditional style. 764 * Note that the storage used for the returned string is static, 765 * and the string is overwritten each time this function is called. 766 */ 767 const char * 768 subpartition_get_device_name(const struct subpartition *sp) 769 { 770 static char tmp_dev_name[256]; 771 772 if (sp->parent->parent->serno != NULL) 773 snprintf(tmp_dev_name, 256, "serno/%s.s%d%c", 774 sp->parent->parent->serno, sp->parent->number, sp->letter); 775 else 776 snprintf(tmp_dev_name, 256, "%ss%d%c", 777 sp->parent->parent->device, sp->parent->number, sp->letter); 778 return(tmp_dev_name); 779 } 780 781 /* 782 * /dev/mapper/ 783 * 784 * (result is persistant until next call) 785 */ 786 const char * 787 subpartition_get_mapper_name(const struct subpartition *sp, int withdev) 788 { 789 const char *src; 790 static char *save; 791 792 src = strrchr(sp->mountpoint, '/'); 793 if (src == NULL || src[1] == 0) 794 src = "root"; 795 else 796 ++src; 797 798 if (save) 799 free(save); 800 switch(withdev) { 801 case -1: 802 asprintf(&save, "%s", src); 803 break; 804 case 0: 805 asprintf(&save, "mapper/%s", src); 806 break; 807 case 1: 808 default: 809 asprintf(&save, "/dev/mapper/%s", src); 810 break; 811 } 812 return save; 813 } 814 815 const char * 816 subpartition_get_mountpoint(const struct subpartition *sp) 817 { 818 return(sp->mountpoint); 819 } 820 821 char 822 subpartition_get_letter(const struct subpartition *sp) 823 { 824 return(sp->letter); 825 } 826 827 unsigned long 828 subpartition_get_fsize(const struct subpartition *sp) 829 { 830 return(sp->fsize); 831 } 832 833 unsigned long 834 subpartition_get_bsize(const struct subpartition *sp) 835 { 836 return(sp->bsize); 837 } 838 839 long 840 subpartition_get_capacity(const struct subpartition *sp) 841 { 842 return(sp->capacity); 843 } 844 845 void 846 subpartition_clr_encrypted(struct subpartition *sp) 847 { 848 sp->encrypted = 0; 849 } 850 851 int 852 subpartition_is_encrypted(const struct subpartition *sp) 853 { 854 return(sp->encrypted); 855 } 856 857 int 858 subpartition_is_swap(const struct subpartition *sp) 859 { 860 return(sp->is_swap); 861 } 862 863 int 864 subpartition_is_softupdated(const struct subpartition *sp) 865 { 866 return(sp->softupdates); 867 } 868 int 869 subpartition_is_tmpfsbacked(const struct subpartition *sp) 870 { 871 return(sp->tmpfsbacked); 872 } 873 874 int 875 subpartition_count(const struct slice *s) 876 { 877 struct subpartition *sp = s->subpartition_head; 878 int count = 0; 879 880 while (sp != NULL) { 881 count++; 882 sp = sp->next; 883 } 884 885 return(count); 886 } 887 888 void 889 subpartitions_free(struct slice *s) 890 { 891 struct subpartition *sp = s->subpartition_head, *next; 892 893 while (sp != NULL) { 894 next = sp->next; 895 free(sp->mountpoint); 896 AURA_FREE(sp, subpartition); 897 sp = next; 898 } 899 900 s->subpartition_head = NULL; 901 s->subpartition_tail = NULL; 902 } 903 904 long 905 measure_activated_swap(const struct i_fn_args *a) 906 { 907 FILE *p; 908 char line[256]; 909 char *word; 910 long swap = 0; 911 912 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL) 913 return(0); 914 while (fgets(line, 255, p) != NULL) { 915 if ((word = strtok(line, " \t")) == NULL) 916 continue; 917 if (strcmp(word, "Device") == 0) 918 continue; 919 if ((word = strtok(NULL, " \t")) == NULL) 920 continue; 921 swap += atol(word); 922 } 923 aura_pclose(p); 924 925 return(swap / 1024); 926 } 927 928 long 929 measure_activated_swap_from_slice(const struct i_fn_args *a, 930 const struct disk *d, const struct slice *s) 931 { 932 FILE *p; 933 char *dev, *word; 934 char line[256]; 935 long swap = 0; 936 937 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL) 938 return(0); 939 940 asprintf(&dev, "/dev/%ss%d", d->device, s->number); 941 942 while (fgets(line, 255, p) != NULL) { 943 if ((word = strtok(line, " \t")) == NULL) 944 continue; 945 if (strcmp(word, "Device") == 0) 946 continue; 947 if (strstr(word, dev) != word) 948 continue; 949 if ((word = strtok(NULL, " \t")) == NULL) 950 continue; 951 swap += atol(word); 952 } 953 aura_pclose(p); 954 free(dev); 955 956 return(swap / 1024); 957 } 958 959 long 960 measure_activated_swap_from_disk(const struct i_fn_args *a, 961 const struct disk *d) 962 { 963 struct slice *s; 964 long swap = 0; 965 966 for (s = d->slice_head; s != NULL; s = s->next) 967 swap += measure_activated_swap_from_slice(a, d, s); 968 969 return(swap); 970 } 971 972 void * 973 swapoff_all(const struct i_fn_args *a) 974 { 975 FILE *p; 976 977 if ((p = aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r", 978 a->os_root, cmd_name(a, "DUMPON"), 979 a->os_root, cmd_name(a, "SWAPINFO"), 980 a->os_root, cmd_name(a, "GREP"), 981 a->os_root, cmd_name(a, "AWK"), 982 a->os_root, cmd_name(a, "XARGS"), 983 a->os_root, cmd_name(a, "SWAPOFF"))) != NULL) 984 aura_pclose(p); 985 986 return(p); 987 } 988 989 void * 990 remove_all_mappings(const struct i_fn_args *a) 991 { 992 FILE *p; 993 994 if ((p = aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r", 995 a->os_root, cmd_name(a, "LS"), 996 a->os_root, cmd_name(a, "GREP"), 997 a->os_root, cmd_name(a, "XARGS"), 998 a->os_root, cmd_name(a, "CRYPTSETUP"))) != NULL) 999 aura_pclose(p); 1000 1001 return(p); 1002 } 1003