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