2 * Copyright (c)2004,2015 The DragonFly Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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
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.
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.
36 * Disk utility functions for installer.
37 * $Id: diskutil.c,v 1.44 2005/02/07 06:41:42 cpressey Exp $
45 #include "libaura/mem.h"
46 #include "libaura/fspred.h"
47 #include "libaura/popen.h"
49 #include "libdfui/dfui.h"
50 #include "libdfui/dump.h"
52 #define NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
54 #undef NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
57 #include "functions.h"
61 static int disk_description_is_better(const char *, const char *);
63 /** STORAGE DESCRIPTORS **/
70 AURA_MALLOC(s, storage);
74 s->selected_disk = NULL;
75 s->selected_slice = NULL;
82 storage_get_tmpfs_status(const char *mountpoint, struct storage *s)
84 struct subpartition *sp;
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) {
100 storage_free(struct storage *s)
103 AURA_FREE(s, storage);
107 storage_set_memsize(struct storage *s, unsigned long memsize)
113 storage_get_memsize(const struct storage *s)
119 storage_disk_first(const struct storage *s)
121 return(s->disk_head);
125 storage_set_selected_disk(struct storage *s, struct disk *d)
127 s->selected_disk = d;
131 storage_get_selected_disk(const struct storage *s)
133 return(s->selected_disk);
137 storage_set_selected_slice(struct storage *s, struct slice *sl)
139 s->selected_slice = sl;
143 storage_get_selected_slice(const struct storage *s)
145 return(s->selected_slice);
149 * Create a new disk description structure.
152 disk_new(struct storage *s, const char *dev_name)
156 AURA_MALLOC(d, disk);
158 d->device = aura_strdup(dev_name);
164 d->cylinders = -1; /* -1 indicates "we don't know" */
168 d->slice_head = NULL;
169 d->slice_tail = NULL;
172 if (s->disk_head == NULL)
175 s->disk_tail->next = d;
177 d->prev = s->disk_tail;
184 disk_description_is_better(const char *existing, const char *new_desc __unused)
186 if (existing == NULL)
192 disk_get_desc(const struct disk *d)
198 disk_get_capacity(const struct disk *d)
205 disk_set_desc(struct disk *d, const char *desc)
209 if (!disk_description_is_better(d->desc, desc))
213 d->desc = aura_strdup(desc);
216 * Get the disk's total capacity.
217 * XXX we should do this with C/H/S ?
220 while (*c != ':' && *c != '\0')
225 d->capacity = strtoul(c + 1, NULL, 0);
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.
234 disk_get_device_name(const struct disk *d)
236 static char tmp_dev_name[256];
238 snprintf(tmp_dev_name, 256, "%s", d->device);
239 return(tmp_dev_name);
243 disk_get_serno(const struct disk *d)
249 disk_set_serno(struct disk *d, const char *serno)
251 d->serno = aura_strdup(serno);
255 disk_get_number(const struct disk *d)
261 disk_set_number(struct disk *d, const int number)
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".
275 disk_find(const struct storage *s, const char *device)
277 struct disk *d = s->disk_head;
280 if (strncmp(device, d->device, strlen(d->device)) == 0 &&
281 strlen(device) == strlen(d->device))
290 disk_next(const struct disk *d)
296 disk_slice_first(const struct disk *d)
298 return(d->slice_head);
302 disk_set_formatted(struct disk *d, int formatted)
304 d->we_formatted = formatted;
308 disk_get_formatted(const struct disk *d)
310 return(d->we_formatted);
314 disk_set_geometry(struct disk *d, int cyl, int hd, int sec)
322 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec)
330 * Free the memory allocated to hold the set of disk descriptions.
333 disks_free(struct storage *s)
335 struct disk *d = s->disk_head, *next;
339 slices_free(d->slice_head);
351 * Create a new slice description and add it to a disk description.
354 slice_new(struct disk *d, int number, int type, int flags,
355 unsigned long start, unsigned long size)
358 const char *sysid_desc = NULL;
362 dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
363 "to disk %s\n", number, start, size, type, d->device);
365 AURA_MALLOC(s, slice);
369 s->subpartition_head = NULL;
370 s->subpartition_tail = NULL;
379 if (part_types[i].type == type) {
380 sysid_desc = part_types[i].name;
383 if (part_types[i].type == 255)
386 if (sysid_desc == NULL) {
387 snprintf(unknown, 256, "??? Unknown, sysid = %d", type);
388 sysid_desc = unknown;
391 asprintf(&s->desc, "%ldM - %ldM: %s",
392 start / 2048, (start + size) / 2048, sysid_desc);
393 s->capacity = size / 2048;
396 if (d->slice_head == NULL)
399 d->slice_tail->next = s;
401 s->prev = d->slice_tail;
408 * Find a slice description on a given disk description given the
412 slice_find(const struct disk *d, int number)
414 struct slice *s = d->slice_head;
417 if (s->number == number)
426 slice_next(const struct slice *s)
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.
437 slice_get_device_name(const struct slice *s)
439 static char tmp_dev_name[256];
441 snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
442 return(tmp_dev_name);
446 slice_get_number(const struct slice *s)
452 slice_get_desc(const struct slice *s)
458 slice_get_capacity(const struct slice *s)
464 slice_get_start(const struct slice *s)
470 slice_get_size(const struct slice *s)
476 slice_get_type(const struct slice *s)
482 slice_get_flags(const struct slice *s)
487 struct subpartition *
488 slice_subpartition_first(const struct slice *s)
490 return(s->subpartition_head);
494 * Free all memory for a list of slice descriptions.
497 slices_free(struct slice *head)
501 while (head != NULL) {
503 subpartitions_free(head);
505 AURA_FREE(head, slice);
510 struct subpartition *
511 subpartition_new_hammer(struct slice *s, const char *mountpoint, long capacity,
514 struct subpartition *sp;
515 struct subpartition *last = s->subpartition_tail;
517 AURA_MALLOC(sp, subpartition);
523 } else if (last->letter == 'b') {
526 sp->letter = (char)(last->letter + 1);
528 if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
531 sp->mountpoint = aura_strdup(mountpoint);
532 sp->capacity = capacity;
533 sp->encrypted = encrypted;
534 sp->type = FS_HAMMER;
537 * We need this here, because a UFS /boot needs valid values
539 if (sp->capacity < 1024)
544 if (sp->capacity < 1024)
553 if (strcasecmp(mountpoint, "swap") == 0)
556 if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 &&
557 strcmp(mountpoint, "swap") != 0)
562 if (s->subpartition_head == NULL)
563 s->subpartition_head = sp;
565 s->subpartition_tail->next = sp;
567 sp->prev = s->subpartition_tail;
568 s->subpartition_tail = sp;
574 * NOTE: arguments to this function are not checked for sanity.
576 * fsize and/or bsize may both be -1, indicating
577 * "choose a reasonable default."
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)
583 struct subpartition *sp;
584 struct subpartition *last = s->subpartition_tail;
586 AURA_MALLOC(sp, subpartition);
591 while (last && last->letter == '@')
595 } else if (last->letter == 'b') {
598 sp->letter = (char)(last->letter + 1);
600 if (sp->letter == 'b' && strcmp(mountpoint, "swap") != 0)
606 sp->mountpoint = aura_strdup(mountpoint);
607 sp->capacity = capacity;
608 sp->encrypted = encrypted;
612 if (sp->capacity < 1024)
621 if (sp->capacity < 1024)
629 if (softupdates == -1) {
630 if (strcmp(mountpoint, "/") == 0)
635 sp->softupdates = softupdates;
638 sp->tmpfsbacked = tmpfsbacked;
641 if (strcasecmp(mountpoint, "swap") == 0)
648 if (s->subpartition_head == NULL)
649 s->subpartition_head = sp;
651 s->subpartition_tail->next = sp;
653 sp->prev = s->subpartition_tail;
654 s->subpartition_tail = sp;
658 for (sptmp = s->subpartition_head; sptmp != NULL;
659 sptmp = sptmp->next) {
660 if (sptmp->tmpfsbacked)
662 else if (strcmp(sptmp->mountpoint, "/") == 0 ||
663 strcmp(sptmp->mountpoint, "/dummy") == 0)
665 else if (strcasecmp(sptmp->mountpoint, "swap") == 0)
668 sptmp->letter = letter++;
676 * Find the subpartition description in the given storage
677 * description whose mountpoint matches the given string exactly.
679 struct subpartition *
680 subpartition_find(const struct slice *s, const char *fmt, ...)
682 struct subpartition *sp = s->subpartition_head;
687 vasprintf(&mountpoint, fmt, args);
691 if (strcmp(mountpoint, sp->mountpoint) == 0) {
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.
708 struct subpartition *
709 subpartition_of(const struct slice *s, const char *fmt, ...)
711 struct subpartition *sp = s->subpartition_head;
712 struct subpartition *csp = NULL;
718 vasprintf(&filename, fmt, args);
722 if (strlen(sp->mountpoint) > len &&
723 strlen(sp->mountpoint) <= strlen(filename) &&
724 strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
726 len = strlen(csp->mountpoint);
735 struct subpartition *
736 subpartition_find_capacity(const struct slice *s, long capacity)
738 struct subpartition *sp = s->subpartition_head;
741 if (sp->capacity == capacity)
749 struct subpartition *
750 subpartition_next(const struct subpartition *sp)
756 subpartition_get_pfs(const struct subpartition *sp)
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.
768 subpartition_get_device_name(const struct subpartition *sp)
770 static char tmp_dev_name[256];
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);
776 snprintf(tmp_dev_name, 256, "%ss%d%c",
777 sp->parent->parent->device, sp->parent->number, sp->letter);
778 return(tmp_dev_name);
784 * (result is persistant until next call)
787 subpartition_get_mapper_name(const struct subpartition *sp, int withdev)
792 src = strrchr(sp->mountpoint, '/');
793 if (src == NULL || src[1] == 0)
802 asprintf(&save, "%s", src);
805 asprintf(&save, "mapper/%s", src);
809 asprintf(&save, "/dev/mapper/%s", src);
816 subpartition_get_mountpoint(const struct subpartition *sp)
818 return(sp->mountpoint);
822 subpartition_get_letter(const struct subpartition *sp)
828 subpartition_get_fsize(const struct subpartition *sp)
834 subpartition_get_bsize(const struct subpartition *sp)
840 subpartition_get_capacity(const struct subpartition *sp)
842 return(sp->capacity);
846 subpartition_clr_encrypted(struct subpartition *sp)
852 subpartition_is_encrypted(const struct subpartition *sp)
854 return(sp->encrypted);
858 subpartition_is_swap(const struct subpartition *sp)
864 subpartition_is_softupdated(const struct subpartition *sp)
866 return(sp->softupdates);
869 subpartition_is_tmpfsbacked(const struct subpartition *sp)
871 return(sp->tmpfsbacked);
875 subpartition_count(const struct slice *s)
877 struct subpartition *sp = s->subpartition_head;
889 subpartitions_free(struct slice *s)
891 struct subpartition *sp = s->subpartition_head, *next;
895 free(sp->mountpoint);
896 AURA_FREE(sp, subpartition);
900 s->subpartition_head = NULL;
901 s->subpartition_tail = NULL;
905 measure_activated_swap(const struct i_fn_args *a)
912 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
914 while (fgets(line, 255, p) != NULL) {
915 if ((word = strtok(line, " \t")) == NULL)
917 if (strcmp(word, "Device") == 0)
919 if ((word = strtok(NULL, " \t")) == NULL)
929 measure_activated_swap_from_slice(const struct i_fn_args *a,
930 const struct disk *d, const struct slice *s)
937 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
940 asprintf(&dev, "/dev/%ss%d", d->device, s->number);
942 while (fgets(line, 255, p) != NULL) {
943 if ((word = strtok(line, " \t")) == NULL)
945 if (strcmp(word, "Device") == 0)
947 if (strstr(word, dev) != word)
949 if ((word = strtok(NULL, " \t")) == NULL)
960 measure_activated_swap_from_disk(const struct i_fn_args *a,
961 const struct disk *d)
966 for (s = d->slice_head; s != NULL; s = s->next)
967 swap += measure_activated_swap_from_slice(a, d, s);
973 swapoff_all(const struct i_fn_args *a)
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)
990 remove_all_mappings(const struct i_fn_args *a)
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)