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
,
512 long capacity
, int encrypted
)
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
;
573 struct subpartition
*
574 subpartition_new_hammer2(struct slice
*s
, const char *mountpoint
,
575 long capacity
, int encrypted
)
577 struct subpartition
*sp
;
578 struct subpartition
*last
= s
->subpartition_tail
;
580 AURA_MALLOC(sp
, subpartition
);
586 } else if (last
->letter
== 'b') {
589 sp
->letter
= (char)(last
->letter
+ 1);
591 if (sp
->letter
== 'b' && strcmp(mountpoint
, "swap") != 0)
594 sp
->mountpoint
= aura_strdup(mountpoint
);
595 sp
->capacity
= capacity
;
596 sp
->encrypted
= encrypted
;
597 sp
->type
= FS_HAMMER2
;
600 * We need this here, because a UFS /boot needs valid values
602 if (sp
->capacity
< 1024)
607 if (sp
->capacity
< 1024)
616 if (strcasecmp(mountpoint
, "swap") == 0)
619 if (strcmp(mountpoint
, "/") != 0 && strcmp(mountpoint
, "/boot") != 0 &&
620 strcmp(mountpoint
, "swap") != 0)
625 if (s
->subpartition_head
== NULL
)
626 s
->subpartition_head
= sp
;
628 s
->subpartition_tail
->next
= sp
;
630 sp
->prev
= s
->subpartition_tail
;
631 s
->subpartition_tail
= sp
;
637 * NOTE: arguments to this function are not checked for sanity.
639 * fsize and/or bsize may both be -1, indicating
640 * "choose a reasonable default."
642 struct subpartition
*
643 subpartition_new_ufs(struct slice
*s
, const char *mountpoint
, long capacity
,
644 int encrypted
, int softupdates
, long fsize
, long bsize
, int tmpfsbacked
)
646 struct subpartition
*sp
;
647 struct subpartition
*last
= s
->subpartition_tail
;
649 AURA_MALLOC(sp
, subpartition
);
654 while (last
&& last
->letter
== '@')
658 } else if (last
->letter
== 'b') {
661 sp
->letter
= (char)(last
->letter
+ 1);
663 if (sp
->letter
== 'b' && strcmp(mountpoint
, "swap") != 0)
669 sp
->mountpoint
= aura_strdup(mountpoint
);
670 sp
->capacity
= capacity
;
671 sp
->encrypted
= encrypted
;
675 if (sp
->capacity
< 1024)
684 if (sp
->capacity
< 1024)
692 if (softupdates
== -1) {
693 if (strcmp(mountpoint
, "/") == 0)
698 sp
->softupdates
= softupdates
;
701 sp
->tmpfsbacked
= tmpfsbacked
;
704 if (strcasecmp(mountpoint
, "swap") == 0)
711 if (s
->subpartition_head
== NULL
)
712 s
->subpartition_head
= sp
;
714 s
->subpartition_tail
->next
= sp
;
716 sp
->prev
= s
->subpartition_tail
;
717 s
->subpartition_tail
= sp
;
721 for (sptmp
= s
->subpartition_head
; sptmp
!= NULL
;
722 sptmp
= sptmp
->next
) {
723 if (sptmp
->tmpfsbacked
)
725 else if (strcmp(sptmp
->mountpoint
, "/") == 0 ||
726 strcmp(sptmp
->mountpoint
, "/dummy") == 0)
728 else if (strcasecmp(sptmp
->mountpoint
, "swap") == 0)
731 sptmp
->letter
= letter
++;
739 * Find the subpartition description in the given storage
740 * description whose mountpoint matches the given string exactly.
742 struct subpartition
*
743 subpartition_find(const struct slice
*s
, const char *fmt
, ...)
745 struct subpartition
*sp
= s
->subpartition_head
;
750 vasprintf(&mountpoint
, fmt
, args
);
754 if (strcmp(mountpoint
, sp
->mountpoint
) == 0) {
766 * Find the subpartition description in the given storage
767 * description where the given filename would presumably
768 * reside. This is the subpartition whose mountpoint is
769 * the longest match for the given filename.
771 struct subpartition
*
772 subpartition_of(const struct slice
*s
, const char *fmt
, ...)
774 struct subpartition
*sp
= s
->subpartition_head
;
775 struct subpartition
*csp
= NULL
;
781 vasprintf(&filename
, fmt
, args
);
785 if (strlen(sp
->mountpoint
) > len
&&
786 strlen(sp
->mountpoint
) <= strlen(filename
) &&
787 strncmp(filename
, sp
->mountpoint
, strlen(sp
->mountpoint
)) == 0) {
789 len
= strlen(csp
->mountpoint
);
798 struct subpartition
*
799 subpartition_find_capacity(const struct slice
*s
, long capacity
)
801 struct subpartition
*sp
= s
->subpartition_head
;
804 if (sp
->capacity
== capacity
)
812 struct subpartition
*
813 subpartition_next(const struct subpartition
*sp
)
819 subpartition_get_pfs(const struct subpartition
*sp
)
825 * Returns the name of the device node used to represent
826 * the subpartition, either by serial number or traditional style.
827 * Note that the storage used for the returned string is static,
828 * and the string is overwritten each time this function is called.
831 subpartition_get_device_name(const struct subpartition
*sp
)
833 static char tmp_dev_name
[256];
835 if (sp
->parent
->parent
->serno
!= NULL
)
836 snprintf(tmp_dev_name
, 256, "serno/%s.s%d%c",
837 sp
->parent
->parent
->serno
, sp
->parent
->number
, sp
->letter
);
839 snprintf(tmp_dev_name
, 256, "%ss%d%c",
840 sp
->parent
->parent
->device
, sp
->parent
->number
, sp
->letter
);
841 return(tmp_dev_name
);
847 * (result is persistant until next call)
850 subpartition_get_mapper_name(const struct subpartition
*sp
, int withdev
)
855 src
= strrchr(sp
->mountpoint
, '/');
856 if (src
== NULL
|| src
[1] == 0)
865 asprintf(&save
, "%s", src
);
868 asprintf(&save
, "mapper/%s", src
);
872 asprintf(&save
, "/dev/mapper/%s", src
);
879 subpartition_get_mountpoint(const struct subpartition
*sp
)
881 return(sp
->mountpoint
);
885 subpartition_get_letter(const struct subpartition
*sp
)
891 subpartition_get_fsize(const struct subpartition
*sp
)
897 subpartition_get_bsize(const struct subpartition
*sp
)
903 subpartition_get_capacity(const struct subpartition
*sp
)
905 return(sp
->capacity
);
909 subpartition_clr_encrypted(struct subpartition
*sp
)
915 subpartition_is_encrypted(const struct subpartition
*sp
)
917 return(sp
->encrypted
);
921 subpartition_is_swap(const struct subpartition
*sp
)
927 subpartition_is_softupdated(const struct subpartition
*sp
)
929 return(sp
->softupdates
);
932 subpartition_is_tmpfsbacked(const struct subpartition
*sp
)
934 return(sp
->tmpfsbacked
);
938 subpartition_count(const struct slice
*s
)
940 struct subpartition
*sp
= s
->subpartition_head
;
952 subpartitions_free(struct slice
*s
)
954 struct subpartition
*sp
= s
->subpartition_head
, *next
;
958 free(sp
->mountpoint
);
959 AURA_FREE(sp
, subpartition
);
963 s
->subpartition_head
= NULL
;
964 s
->subpartition_tail
= NULL
;
968 measure_activated_swap(const struct i_fn_args
*a
)
975 if ((p
= aura_popen("%s%s -k", "r", a
->os_root
, cmd_name(a
, "SWAPINFO"))) == NULL
)
977 while (fgets(line
, 255, p
) != NULL
) {
978 if ((word
= strtok(line
, " \t")) == NULL
)
980 if (strcmp(word
, "Device") == 0)
982 if ((word
= strtok(NULL
, " \t")) == NULL
)
992 measure_activated_swap_from_slice(const struct i_fn_args
*a
,
993 const struct disk
*d
, const struct slice
*s
)
1000 if ((p
= aura_popen("%s%s -k", "r", a
->os_root
, cmd_name(a
, "SWAPINFO"))) == NULL
)
1003 asprintf(&dev
, "/dev/%ss%d", d
->device
, s
->number
);
1005 while (fgets(line
, 255, p
) != NULL
) {
1006 if ((word
= strtok(line
, " \t")) == NULL
)
1008 if (strcmp(word
, "Device") == 0)
1010 if (strstr(word
, dev
) != word
)
1012 if ((word
= strtok(NULL
, " \t")) == NULL
)
1019 return(swap
/ 1024);
1023 measure_activated_swap_from_disk(const struct i_fn_args
*a
,
1024 const struct disk
*d
)
1029 for (s
= d
->slice_head
; s
!= NULL
; s
= s
->next
)
1030 swap
+= measure_activated_swap_from_slice(a
, d
, s
);
1036 swapoff_all(const struct i_fn_args
*a
)
1040 if ((p
= aura_popen("%s%s off; %s%s | %s%s \"^/dev\" | %s%s '{print $1;}' | %s%s %s%s", "r",
1041 a
->os_root
, cmd_name(a
, "DUMPON"),
1042 a
->os_root
, cmd_name(a
, "SWAPINFO"),
1043 a
->os_root
, cmd_name(a
, "GREP"),
1044 a
->os_root
, cmd_name(a
, "AWK"),
1045 a
->os_root
, cmd_name(a
, "XARGS"),
1046 a
->os_root
, cmd_name(a
, "SWAPOFF"))) != NULL
)
1053 remove_all_mappings(const struct i_fn_args
*a
)
1057 if ((p
= aura_popen("%s%s -1 /dev/mapper | %s%s -vw control | %s%s -n 1 %s%s luksClose", "r",
1058 a
->os_root
, cmd_name(a
, "LS"),
1059 a
->os_root
, cmd_name(a
, "GREP"),
1060 a
->os_root
, cmd_name(a
, "XARGS"),
1061 a
->os_root
, cmd_name(a
, "CRYPTSETUP"))) != NULL
)