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