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 $
40 #include <sys/diskmbr.h>
47 #include "libaura/mem.h"
48 #include "libaura/fspred.h"
49 #include "libaura/popen.h"
51 #include "libdfui/dfui.h"
52 #include "libdfui/dump.h"
54 #define NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
56 #undef NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
59 #include "functions.h"
62 static int disk_description_is_better(const char *, const char *);
64 /** STORAGE DESCRIPTORS **/
71 AURA_MALLOC(s
, storage
);
75 s
->selected_disk
= NULL
;
76 s
->selected_slice
= NULL
;
83 storage_get_tmpfs_status(const char *mountpoint
, struct storage
*s
)
85 struct subpartition
*sp
;
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) {
101 storage_free(struct storage
*s
)
104 AURA_FREE(s
, storage
);
108 storage_set_memsize(struct storage
*s
, unsigned long memsize
)
114 storage_get_memsize(const struct storage
*s
)
120 storage_disk_first(const struct storage
*s
)
122 return(s
->disk_head
);
126 storage_set_selected_disk(struct storage
*s
, struct disk
*d
)
128 s
->selected_disk
= d
;
132 storage_get_selected_disk(const struct storage
*s
)
134 return(s
->selected_disk
);
138 storage_set_selected_slice(struct storage
*s
, struct slice
*sl
)
140 s
->selected_slice
= sl
;
144 storage_get_selected_slice(const struct storage
*s
)
146 return(s
->selected_slice
);
150 * Create a new disk description structure.
153 disk_new(struct storage
*s
, const char *dev_name
)
157 AURA_MALLOC(d
, disk
);
159 d
->device
= aura_strdup(dev_name
);
165 d
->cylinders
= -1; /* -1 indicates "we don't know" */
169 d
->slice_head
= NULL
;
170 d
->slice_tail
= NULL
;
173 if (s
->disk_head
== NULL
)
176 s
->disk_tail
->next
= d
;
178 d
->prev
= s
->disk_tail
;
185 disk_description_is_better(const char *existing
, const char *new_desc __unused
)
187 if (existing
== NULL
)
193 disk_get_desc(const struct disk
*d
)
199 disk_get_capacity(const struct disk
*d
)
206 disk_set_desc(struct disk
*d
, const char *desc
)
210 if (!disk_description_is_better(d
->desc
, desc
))
214 d
->desc
= aura_strdup(desc
);
217 * Get the disk's total capacity.
218 * XXX we should do this with C/H/S ?
221 while (*c
!= ':' && *c
!= '\0')
226 d
->capacity
= strtoul(c
+ 1, NULL
, 0);
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.
235 disk_get_device_name(const struct disk
*d
)
237 static char tmp_dev_name
[256];
239 snprintf(tmp_dev_name
, 256, "%s", d
->device
);
240 return(tmp_dev_name
);
244 disk_get_serno(const struct disk
*d
)
250 disk_set_serno(struct disk
*d
, const char *serno
)
252 d
->serno
= aura_strdup(serno
);
256 disk_get_number(const struct disk
*d
)
262 disk_set_number(struct disk
*d
, const int number
)
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".
276 disk_find(const struct storage
*s
, const char *device
)
278 struct disk
*d
= s
->disk_head
;
281 if (strncmp(device
, d
->device
, strlen(d
->device
)) == 0 &&
282 strlen(device
) == strlen(d
->device
))
291 disk_next(const struct disk
*d
)
297 disk_slice_first(const struct disk
*d
)
299 return(d
->slice_head
);
303 disk_set_formatted(struct disk
*d
, int formatted
)
305 d
->we_formatted
= formatted
;
309 disk_get_formatted(const struct disk
*d
)
311 return(d
->we_formatted
);
315 disk_set_geometry(struct disk
*d
, int cyl
, int hd
, int sec
)
323 disk_get_geometry(const struct disk
*d
, int *cyl
, int *hd
, int *sec
)
331 * Free the memory allocated to hold the set of disk descriptions.
334 disks_free(struct storage
*s
)
336 struct disk
*d
= s
->disk_head
, *next
;
340 slices_free(d
->slice_head
);
352 * Create a new slice description and add it to a disk description.
355 slice_new(struct disk
*d
, int number
, int type
, int flags
,
356 unsigned long start
, unsigned long size
)
359 const char *sysid_desc
= NULL
;
363 dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
364 "to disk %s\n", number
, start
, size
, type
, d
->device
);
366 AURA_MALLOC(s
, slice
);
370 s
->subpartition_head
= NULL
;
371 s
->subpartition_tail
= NULL
;
380 if (dos_ptypes
[i
].type
== type
) {
381 sysid_desc
= dos_ptypes
[i
].name
;
384 if (dos_ptypes
[i
].type
== 255)
387 if (sysid_desc
== NULL
) {
388 snprintf(unknown
, 256, "??? Unknown, sysid = %d", type
);
389 sysid_desc
= unknown
;
392 asprintf(&s
->desc
, "%ldM - %ldM: %s",
393 start
/ 2048, (start
+ size
) / 2048, sysid_desc
);
394 s
->capacity
= size
/ 2048;
397 if (d
->slice_head
== NULL
)
400 d
->slice_tail
->next
= s
;
402 s
->prev
= d
->slice_tail
;
409 * Find a slice description on a given disk description given the
413 slice_find(const struct disk
*d
, int number
)
415 struct slice
*s
= d
->slice_head
;
418 if (s
->number
== number
)
427 slice_next(const struct slice
*s
)
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.
438 slice_get_device_name(const struct slice
*s
)
440 static char tmp_dev_name
[256];
442 snprintf(tmp_dev_name
, 256, "%ss%d", s
->parent
->device
, s
->number
);
443 return(tmp_dev_name
);
447 slice_get_number(const struct slice
*s
)
453 slice_get_desc(const struct slice
*s
)
459 slice_get_capacity(const struct slice
*s
)
465 slice_get_start(const struct slice
*s
)
471 slice_get_size(const struct slice
*s
)
477 slice_get_type(const struct slice
*s
)
483 slice_get_flags(const struct slice
*s
)
488 struct subpartition
*
489 slice_subpartition_first(const struct slice
*s
)
491 return(s
->subpartition_head
);
495 * Free all memory for a list of slice descriptions.
498 slices_free(struct slice
*head
)
502 while (head
!= NULL
) {
504 subpartitions_free(head
);
506 AURA_FREE(head
, slice
);
511 struct subpartition
*
512 subpartition_new_hammer(struct slice
*s
, const char *mountpoint
,
513 long capacity
, int encrypted
)
515 struct subpartition
*sp
;
516 struct subpartition
*last
= s
->subpartition_tail
;
518 AURA_MALLOC(sp
, subpartition
);
524 } else if (last
->letter
== 'b') {
527 sp
->letter
= (char)(last
->letter
+ 1);
529 if (sp
->letter
== 'b' && strcmp(mountpoint
, "swap") != 0)
532 sp
->mountpoint
= aura_strdup(mountpoint
);
533 sp
->capacity
= capacity
;
534 sp
->encrypted
= encrypted
;
535 sp
->type
= FS_HAMMER
;
538 * We need this here, because a UFS /boot needs valid values
540 if (sp
->capacity
< 1024)
545 if (sp
->capacity
< 1024)
554 if (strcasecmp(mountpoint
, "swap") == 0)
557 if (strcmp(mountpoint
, "/") != 0 && strcmp(mountpoint
, "/boot") != 0 &&
558 strcmp(mountpoint
, "swap") != 0)
563 if (s
->subpartition_head
== NULL
)
564 s
->subpartition_head
= sp
;
566 s
->subpartition_tail
->next
= sp
;
568 sp
->prev
= s
->subpartition_tail
;
569 s
->subpartition_tail
= sp
;
574 struct subpartition
*
575 subpartition_new_hammer2(struct slice
*s
, const char *mountpoint
,
576 long capacity
, int encrypted
)
578 struct subpartition
*sp
;
579 struct subpartition
*last
= s
->subpartition_tail
;
581 AURA_MALLOC(sp
, subpartition
);
587 } else if (last
->letter
== 'b') {
590 sp
->letter
= (char)(last
->letter
+ 1);
592 if (sp
->letter
== 'b' && strcmp(mountpoint
, "swap") != 0)
595 sp
->mountpoint
= aura_strdup(mountpoint
);
596 sp
->capacity
= capacity
;
597 sp
->encrypted
= encrypted
;
598 sp
->type
= FS_HAMMER2
;
601 * We need this here, because a UFS /boot needs valid values
603 if (sp
->capacity
< 1024)
608 if (sp
->capacity
< 1024)
617 if (strcasecmp(mountpoint
, "swap") == 0)
620 if (strcmp(mountpoint
, "/") != 0 && strcmp(mountpoint
, "/boot") != 0 &&
621 strcmp(mountpoint
, "swap") != 0)
626 if (s
->subpartition_head
== NULL
)
627 s
->subpartition_head
= sp
;
629 s
->subpartition_tail
->next
= sp
;
631 sp
->prev
= s
->subpartition_tail
;
632 s
->subpartition_tail
= sp
;
638 * NOTE: arguments to this function are not checked for sanity.
640 * fsize and/or bsize may both be -1, indicating
641 * "choose a reasonable default."
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
)
647 struct subpartition
*sp
;
648 struct subpartition
*last
= s
->subpartition_tail
;
650 AURA_MALLOC(sp
, subpartition
);
655 while (last
&& last
->letter
== '@')
659 } else if (last
->letter
== 'b') {
662 sp
->letter
= (char)(last
->letter
+ 1);
664 if (sp
->letter
== 'b' && strcmp(mountpoint
, "swap") != 0)
670 sp
->mountpoint
= aura_strdup(mountpoint
);
671 sp
->capacity
= capacity
;
672 sp
->encrypted
= encrypted
;
676 if (sp
->capacity
< 1024)
685 if (sp
->capacity
< 1024)
693 if (softupdates
== -1) {
694 if (strcmp(mountpoint
, "/") == 0)
699 sp
->softupdates
= softupdates
;
702 sp
->tmpfsbacked
= tmpfsbacked
;
705 if (strcasecmp(mountpoint
, "swap") == 0)
712 if (s
->subpartition_head
== NULL
)
713 s
->subpartition_head
= sp
;
715 s
->subpartition_tail
->next
= sp
;
717 sp
->prev
= s
->subpartition_tail
;
718 s
->subpartition_tail
= sp
;
722 for (sptmp
= s
->subpartition_head
; sptmp
!= NULL
;
723 sptmp
= sptmp
->next
) {
724 if (sptmp
->tmpfsbacked
)
726 else if (strcmp(sptmp
->mountpoint
, "/") == 0 ||
727 strcmp(sptmp
->mountpoint
, "/dummy") == 0)
729 else if (strcasecmp(sptmp
->mountpoint
, "swap") == 0)
732 sptmp
->letter
= letter
++;
740 * Find the subpartition description in the given storage
741 * description whose mountpoint matches the given string exactly.
743 struct subpartition
*
744 subpartition_find(const struct slice
*s
, const char *fmt
, ...)
746 struct subpartition
*sp
= s
->subpartition_head
;
751 vasprintf(&mountpoint
, fmt
, args
);
755 if (strcmp(mountpoint
, sp
->mountpoint
) == 0) {
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.
772 struct subpartition
*
773 subpartition_of(const struct slice
*s
, const char *fmt
, ...)
775 struct subpartition
*sp
= s
->subpartition_head
;
776 struct subpartition
*csp
= NULL
;
782 vasprintf(&filename
, fmt
, args
);
786 if (strlen(sp
->mountpoint
) > len
&&
787 strlen(sp
->mountpoint
) <= strlen(filename
) &&
788 strncmp(filename
, sp
->mountpoint
, strlen(sp
->mountpoint
)) == 0) {
790 len
= strlen(csp
->mountpoint
);
799 struct subpartition
*
800 subpartition_find_capacity(const struct slice
*s
, long capacity
)
802 struct subpartition
*sp
= s
->subpartition_head
;
805 if (sp
->capacity
== capacity
)
813 struct subpartition
*
814 subpartition_next(const struct subpartition
*sp
)
820 subpartition_get_pfs(const struct subpartition
*sp
)
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.
832 subpartition_get_device_name(const struct subpartition
*sp
)
834 static char tmp_dev_name
[256];
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
);
840 snprintf(tmp_dev_name
, 256, "%ss%d%c",
841 sp
->parent
->parent
->device
, sp
->parent
->number
, sp
->letter
);
842 return(tmp_dev_name
);
848 * (result is persistant until next call)
851 subpartition_get_mapper_name(const struct subpartition
*sp
, int withdev
)
856 src
= strrchr(sp
->mountpoint
, '/');
857 if (src
== NULL
|| src
[1] == 0)
866 asprintf(&save
, "%s", src
);
869 asprintf(&save
, "mapper/%s", src
);
873 asprintf(&save
, "/dev/mapper/%s", src
);
880 subpartition_get_mountpoint(const struct subpartition
*sp
)
882 return(sp
->mountpoint
);
886 subpartition_get_letter(const struct subpartition
*sp
)
892 subpartition_get_fsize(const struct subpartition
*sp
)
898 subpartition_get_bsize(const struct subpartition
*sp
)
904 subpartition_get_capacity(const struct subpartition
*sp
)
906 return(sp
->capacity
);
910 subpartition_clr_encrypted(struct subpartition
*sp
)
916 subpartition_is_encrypted(const struct subpartition
*sp
)
918 return(sp
->encrypted
);
922 subpartition_is_swap(const struct subpartition
*sp
)
928 subpartition_is_softupdated(const struct subpartition
*sp
)
930 return(sp
->softupdates
);
933 subpartition_is_tmpfsbacked(const struct subpartition
*sp
)
935 return(sp
->tmpfsbacked
);
939 subpartition_count(const struct slice
*s
)
941 struct subpartition
*sp
= s
->subpartition_head
;
953 subpartitions_free(struct slice
*s
)
955 struct subpartition
*sp
= s
->subpartition_head
, *next
;
959 free(sp
->mountpoint
);
960 AURA_FREE(sp
, subpartition
);
964 s
->subpartition_head
= NULL
;
965 s
->subpartition_tail
= NULL
;
969 measure_activated_swap(const struct i_fn_args
*a
)
976 if ((p
= aura_popen("%s%s -k", "r", a
->os_root
, cmd_name(a
, "SWAPINFO"))) == NULL
)
978 while (fgets(line
, 255, p
) != NULL
) {
979 if ((word
= strtok(line
, " \t")) == NULL
)
981 if (strcmp(word
, "Device") == 0)
983 if ((word
= strtok(NULL
, " \t")) == NULL
)
993 measure_activated_swap_from_slice(const struct i_fn_args
*a
,
994 const struct disk
*d
, const struct slice
*s
)
1001 if ((p
= aura_popen("%s%s -k", "r", a
->os_root
, cmd_name(a
, "SWAPINFO"))) == NULL
)
1004 asprintf(&dev
, "/dev/%ss%d", d
->device
, s
->number
);
1006 while (fgets(line
, 255, p
) != NULL
) {
1007 if ((word
= strtok(line
, " \t")) == NULL
)
1009 if (strcmp(word
, "Device") == 0)
1011 if (strstr(word
, dev
) != word
)
1013 if ((word
= strtok(NULL
, " \t")) == NULL
)
1020 return(swap
/ 1024);
1024 measure_activated_swap_from_disk(const struct i_fn_args
*a
,
1025 const struct disk
*d
)
1030 for (s
= d
->slice_head
; s
!= NULL
; s
= s
->next
)
1031 swap
+= measure_activated_swap_from_slice(a
, d
, s
);
1037 swapoff_all(const struct i_fn_args
*a
)
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
)
1054 remove_all_mappings(const struct i_fn_args
*a
)
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
)