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 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 509 AURA_MALLOC(sp, subpartition); 510 511 sp->parent = s; 512 513 struct subpartition *last = s->subpartition_tail; 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 522 sp->mountpoint = aura_strdup(mountpoint); 523 sp->capacity = capacity; 524 sp->encrypted = encrypted; 525 sp->type = FS_HAMMER; 526 527 /* 528 * We need this here, because a UFS /boot needs valid values 529 */ 530 if (sp->capacity < 1024) 531 sp->fsize = 1024; 532 else 533 sp->fsize = 2048; 534 535 if (sp->capacity < 1024) 536 sp->bsize = 8192; 537 else 538 sp->bsize = 16384; 539 540 sp->is_swap = 0; 541 sp->pfs = 0; 542 if (strcasecmp(mountpoint, "swap") == 0) 543 sp->is_swap = 1; 544 if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 && 545 strcmp(mountpoint, "swap") != 0) 546 sp->pfs = 1; 547 548 sp->next = NULL; 549 if (s->subpartition_head == NULL) 550 s->subpartition_head = sp; 551 else 552 s->subpartition_tail->next = sp; 553 554 sp->prev = s->subpartition_tail; 555 s->subpartition_tail = sp; 556 557 return(sp); 558 } 559 560 /* 561 * NOTE: arguments to this function are not checked for sanity. 562 * 563 * fsize and/or bsize may both be -1, indicating 564 * "choose a reasonable default." 565 */ 566 struct subpartition * 567 subpartition_new_ufs(struct slice *s, const char *mountpoint, long capacity, 568 int encrypted, int softupdates, long fsize, long bsize, int tmpfsbacked) 569 { 570 struct subpartition *sp, *sptmp; 571 int letter='d'; 572 573 AURA_MALLOC(sp, subpartition); 574 575 sp->parent = s; 576 577 sp->mountpoint = aura_strdup(mountpoint); 578 sp->capacity = capacity; 579 sp->encrypted = encrypted; 580 sp->type = FS_UFS; 581 582 if (fsize == -1) { 583 if (sp->capacity < 1024) 584 sp->fsize = 1024; 585 else 586 sp->fsize = 2048; 587 } else { 588 sp->fsize = fsize; 589 } 590 591 if (bsize == -1) { 592 if (sp->capacity < 1024) 593 sp->bsize = 8192; 594 else 595 sp->bsize = 16384; 596 } else { 597 sp->bsize = bsize; 598 } 599 600 if (softupdates == -1) { 601 if (strcmp(mountpoint, "/") == 0) 602 sp->softupdates = 0; 603 else 604 sp->softupdates = 1; 605 } else { 606 sp->softupdates = softupdates; 607 } 608 609 sp->tmpfsbacked = tmpfsbacked; 610 611 sp->is_swap = 0; 612 if (strcasecmp(mountpoint, "swap") == 0) 613 sp->is_swap = 1; 614 615 if (s->subpartition_head == NULL) { 616 s->subpartition_head = sp; 617 s->subpartition_tail = sp; 618 } else { 619 for (sptmp = s->subpartition_head; sptmp != NULL; 620 sptmp = sptmp->next) { 621 if (strcmp(sptmp->mountpoint, sp->mountpoint) > 0) 622 break; 623 } 624 if (sptmp != NULL) { 625 if (s->subpartition_head == sptmp) 626 s->subpartition_head = sp; 627 else 628 sptmp->prev->next = sp; 629 sp->next = sptmp; 630 sp->prev = sptmp->prev; 631 sptmp->prev = sp; 632 } else { 633 sp->prev = s->subpartition_tail; 634 s->subpartition_tail->next = sp; 635 s->subpartition_tail = sp; 636 } 637 } 638 639 for (sptmp = s->subpartition_head; sptmp != NULL; 640 sptmp = sptmp->next) { 641 if (sptmp->tmpfsbacked) 642 sptmp->letter = '@'; 643 else if (strcmp(sptmp->mountpoint, "/") == 0 || 644 strcmp(sptmp->mountpoint, "/dummy") == 0) 645 sptmp->letter = 'a'; 646 else if (strcasecmp(sptmp->mountpoint, "swap") == 0) 647 sptmp->letter = 'b'; 648 else 649 sptmp->letter = letter++; 650 } 651 652 return(sp); 653 } 654 655 /* 656 * Find the subpartition description in the given storage 657 * description whose mountpoint matches the given string exactly. 658 */ 659 struct subpartition * 660 subpartition_find(const struct slice *s, const char *fmt, ...) 661 { 662 struct subpartition *sp = s->subpartition_head; 663 char *mountpoint; 664 va_list args; 665 666 va_start(args, fmt); 667 vasprintf(&mountpoint, fmt, args); 668 va_end(args); 669 670 while (sp != NULL) { 671 if (strcmp(mountpoint, sp->mountpoint) == 0) { 672 free(mountpoint); 673 return(sp); 674 } 675 sp = sp->next; 676 } 677 678 free(mountpoint); 679 return(NULL); 680 } 681 682 /* 683 * Find the subpartition description in the given storage 684 * description where the given filename would presumably 685 * reside. This is the subpartition whose mountpoint is 686 * the longest match for the given filename. 687 */ 688 struct subpartition * 689 subpartition_of(const struct slice *s, const char *fmt, ...) 690 { 691 struct subpartition *sp = s->subpartition_head; 692 struct subpartition *csp = NULL; 693 size_t len = 0; 694 char *filename; 695 va_list args; 696 697 va_start(args, fmt); 698 vasprintf(&filename, fmt, args); 699 va_end(args); 700 701 while (sp != NULL) { 702 if (strlen(sp->mountpoint) > len && 703 strlen(sp->mountpoint) <= strlen(filename) && 704 strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) { 705 csp = sp; 706 len = strlen(csp->mountpoint); 707 } 708 sp = sp->next; 709 } 710 711 free(filename); 712 return(csp); 713 } 714 715 struct subpartition * 716 subpartition_find_capacity(const struct slice *s, long capacity) 717 { 718 struct subpartition *sp = s->subpartition_head; 719 720 while (sp != NULL) { 721 if (sp->capacity == capacity) 722 return(sp); 723 sp = sp->next; 724 } 725 726 return(NULL); 727 } 728 729 struct subpartition * 730 subpartition_next(const struct subpartition *sp) 731 { 732 return(sp->next); 733 } 734 735 int 736 subpartition_get_pfs(const struct subpartition *sp) 737 { 738 return(sp->pfs); 739 } 740 741 /* 742 * Returns the name of the device node used to represent 743 * the subpartition, either by serial number or traditional style. 744 * Note that the storage used for the returned string is static, 745 * and the string is overwritten each time this function is called. 746 */ 747 const char * 748 subpartition_get_device_name(const struct subpartition *sp) 749 { 750 static char tmp_dev_name[256]; 751 752 if (sp->parent->parent->serno != NULL) 753 snprintf(tmp_dev_name, 256, "serno/%s.s%d%c", 754 sp->parent->parent->serno, sp->parent->number, sp->letter); 755 else 756 snprintf(tmp_dev_name, 256, "%ss%d%c", 757 sp->parent->parent->device, sp->parent->number, sp->letter); 758 return(tmp_dev_name); 759 } 760 761 const char * 762 subpartition_get_mountpoint(const struct subpartition *sp) 763 { 764 return(sp->mountpoint); 765 } 766 767 char 768 subpartition_get_letter(const struct subpartition *sp) 769 { 770 return(sp->letter); 771 } 772 773 unsigned long 774 subpartition_get_fsize(const struct subpartition *sp) 775 { 776 return(sp->fsize); 777 } 778 779 unsigned long 780 subpartition_get_bsize(const struct subpartition *sp) 781 { 782 return(sp->bsize); 783 } 784 785 long 786 subpartition_get_capacity(const struct subpartition *sp) 787 { 788 return(sp->capacity); 789 } 790 791 void 792 subpartition_clr_encrypted(struct subpartition *sp) 793 { 794 sp->encrypted = 0; 795 } 796 797 int 798 subpartition_is_encrypted(const struct subpartition *sp) 799 { 800 return(sp->encrypted); 801 } 802 803 int 804 subpartition_is_swap(const struct subpartition *sp) 805 { 806 return(sp->is_swap); 807 } 808 809 int 810 subpartition_is_softupdated(const struct subpartition *sp) 811 { 812 return(sp->softupdates); 813 } 814 int 815 subpartition_is_tmpfsbacked(const struct subpartition *sp) 816 { 817 return(sp->tmpfsbacked); 818 } 819 820 int 821 subpartition_count(const struct slice *s) 822 { 823 struct subpartition *sp = s->subpartition_head; 824 int count = 0; 825 826 while (sp != NULL) { 827 count++; 828 sp = sp->next; 829 } 830 831 return(count); 832 } 833 834 void 835 subpartitions_free(struct slice *s) 836 { 837 struct subpartition *sp = s->subpartition_head, *next; 838 839 while (sp != NULL) { 840 next = sp->next; 841 free(sp->mountpoint); 842 AURA_FREE(sp, subpartition); 843 sp = next; 844 } 845 846 s->subpartition_head = NULL; 847 s->subpartition_tail = NULL; 848 } 849 850 long 851 measure_activated_swap(const struct i_fn_args *a) 852 { 853 FILE *p; 854 char line[256]; 855 char *word; 856 long swap = 0; 857 858 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL) 859 return(0); 860 while (fgets(line, 255, p) != NULL) { 861 if ((word = strtok(line, " \t")) == NULL) 862 continue; 863 if (strcmp(word, "Device") == 0) 864 continue; 865 if ((word = strtok(NULL, " \t")) == NULL) 866 continue; 867 swap += atol(word); 868 } 869 aura_pclose(p); 870 871 return(swap / 1024); 872 } 873 874 long 875 measure_activated_swap_from_slice(const struct i_fn_args *a, 876 const struct disk *d, const struct slice *s) 877 { 878 FILE *p; 879 char *dev, *word; 880 char line[256]; 881 long swap = 0; 882 883 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL) 884 return(0); 885 886 asprintf(&dev, "/dev/%ss%d", d->device, s->number); 887 888 while (fgets(line, 255, p) != NULL) { 889 if ((word = strtok(line, " \t")) == NULL) 890 continue; 891 if (strcmp(word, "Device") == 0) 892 continue; 893 if (strstr(word, dev) != word) 894 continue; 895 if ((word = strtok(NULL, " \t")) == NULL) 896 continue; 897 swap += atol(word); 898 } 899 aura_pclose(p); 900 free(dev); 901 902 return(swap / 1024); 903 } 904 905 long 906 measure_activated_swap_from_disk(const struct i_fn_args *a, 907 const struct disk *d) 908 { 909 struct slice *s; 910 long swap = 0; 911 912 for (s = d->slice_head; s != NULL; s = s->next) 913 swap += measure_activated_swap_from_slice(a, d, s); 914 915 return(swap); 916 } 917 918 void * 919 swapoff_all(const struct i_fn_args *a) 920 { 921 FILE *p; 922 923 if ((p = aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r", 924 a->os_root, cmd_name(a, "DUMPON"), 925 a->os_root, cmd_name(a, "SWAPINFO"), 926 a->os_root, cmd_name(a, "GREP"), 927 a->os_root, cmd_name(a, "AWK"), 928 a->os_root, cmd_name(a, "XARGS"), 929 a->os_root, cmd_name(a, "SWAPOFF"))) != NULL) 930 aura_pclose(p); 931 932 return(p); 933 } 934 935 void * 936 remove_all_mappings(const struct i_fn_args *a) 937 { 938 FILE *p; 939 940 if ((p = aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r", 941 a->os_root, cmd_name(a, "LS"), 942 a->os_root, cmd_name(a, "GREP"), 943 a->os_root, cmd_name(a, "XARGS"), 944 a->os_root, cmd_name(a, "CRYPTSETUP"))) != NULL) 945 aura_pclose(p); 946 947 return(p); 948 } 949