2 * Copyright (c)2004 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 $
46 #include "aura/fspred.h"
47 #include "aura/popen.h"
49 #include "dfui/dfui.h"
50 #include "dfui/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_mfs_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_mfsbacked(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 if (disk_find(s, dev_name) != NULL) {
157 /* Already discovered */
161 AURA_MALLOC(d, disk);
163 d->device = aura_strdup(dev_name);
168 d->cylinders = -1; /* -1 indicates "we don't know" */
172 d->slice_head = NULL;
173 d->slice_tail = NULL;
176 if (s->disk_head == NULL)
179 s->disk_tail->next = d;
181 d->prev = s->disk_tail;
188 disk_description_is_better(const char *existing, const char *new_desc __unused)
190 if (existing == NULL)
196 disk_get_desc(const struct disk *d)
202 disk_set_desc(struct disk *d, const char *desc)
206 if (!disk_description_is_better(d->desc, desc))
210 d->desc = aura_strdup(desc);
213 * Get the disk's total capacity.
214 * XXX we should do this with C/H/S ?
217 while (*c != ':' && *c != '\0')
222 d->capacity = atoi(c + 1);
226 * Returns the name of the device node used to represent the disk.
227 * Note that the storage used for the returned string is static,
228 * and the string is overwritten each time this function is called.
231 disk_get_device_name(const struct disk *d)
233 static char tmp_dev_name[256];
236 * for OpenBSD, this has a "c" suffixed to it.
239 snprintf(tmp_dev_name, 256, "%sc", d->device);
241 snprintf(tmp_dev_name, 256, "%s", d->device);
243 return(tmp_dev_name);
247 * Returns the name of the device node used to represent the
249 * Note that the storage used for the returned string is static,
250 * and the string is overwritten each time this function is called.
253 disk_get_raw_device_name(const struct disk *d)
255 static char tmp_dev_name[256];
258 * for OpenBSD, this has an "r" prepended to it,
259 * and a "c" suffixed to it.
262 snprintf(tmp_dev_name, 256, "r%sc", d->device);
264 snprintf(tmp_dev_name, 256, "%s", d->device);
266 return(tmp_dev_name);
270 * Find the first disk description structure in the given
271 * storage description which matches the given device name
272 * prefix. Note that this means that if a storage
273 * description s contains disks named "ad0" and "ad1",
274 * disk_find(s, "ad0s1c") will return a pointer to the disk
275 * structure for "ad0".
278 disk_find(const struct storage *s, const char *device)
280 struct disk *d = s->disk_head;
283 if (strncmp(device, d->device, strlen(d->device)) == 0)
292 disk_next(const struct disk *d)
298 disk_slice_first(const struct disk *d)
300 return(d->slice_head);
304 disk_set_formatted(struct disk *d, int formatted)
306 d->we_formatted = formatted;
310 disk_get_formatted(const struct disk *d)
312 return(d->we_formatted);
316 disk_set_geometry(struct disk *d, int cyl, int hd, int sec)
324 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec)
332 * Free the memory allocated to hold the set of disk descriptions.
335 disks_free(struct storage *s)
337 struct disk *d = s->disk_head, *next;
341 slices_free(d->slice_head);
353 * Create a new slice description and add it to a disk description.
356 slice_new(struct disk *d, int number, int type, int flags,
357 unsigned long start, unsigned long size)
360 const char *sysid_desc = NULL;
364 dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
365 "to disk %s\n", number, start, size, type, d->device);
367 AURA_MALLOC(s, slice);
371 s->subpartition_head = NULL;
372 s->subpartition_tail = NULL;
381 if (part_types[i].type == type) {
382 sysid_desc = part_types[i].name;
385 if (part_types[i].type == 255)
388 if (sysid_desc == NULL) {
389 snprintf(unknown, 256, "??? Unknown, sysid = %d", type);
390 sysid_desc = unknown;
393 asprintf(&s->desc, "%ldM - %ldM: %s",
394 start / 2048, (start + size) / 2048, sysid_desc);
395 s->capacity = size / 2048;
398 if (d->slice_head == NULL)
401 d->slice_tail->next = s;
403 s->prev = d->slice_tail;
410 * Find a slice description on a given disk description given the
414 slice_find(const struct disk *d, int number)
416 struct slice *s = d->slice_head;
419 if (s->number == number)
428 slice_next(const struct slice *s)
434 * Returns the name of the device node used to represent the slice.
435 * Note that the storage used for the returned string is static,
436 * and the string is overwritten each time this function is called.
439 slice_get_device_name(const struct slice *s)
441 static char tmp_dev_name[256];
444 * XXX for OpenBSD, this appears to be meaningless?
445 * i.e. the number of the current slice is hidden in-core
446 * and not accessible (or needed) from userland.
449 snprintf(tmp_dev_name, 256, "%sc", s->parent->device);
451 snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
453 return(tmp_dev_name);
457 * Returns the name of the device node used to represent
459 * Note that the storage used for the returned string is static,
460 * and the string is overwritten each time this function is called.
463 slice_get_raw_device_name(const struct slice *s)
465 static char tmp_dev_name[256];
468 * XXX for OpenBSD, this needs an "r" prepended to it.
469 * XXX for OpenBSD, this appears to be meaningless?
472 snprintf(tmp_dev_name, 256, "r%sc", s->parent->device);
474 snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
476 return(tmp_dev_name);
480 slice_get_number(const struct slice *s)
486 slice_get_desc(const struct slice *s)
492 slice_get_capacity(const struct slice *s)
498 slice_get_start(const struct slice *s)
504 slice_get_size(const struct slice *s)
510 slice_get_type(const struct slice *s)
516 slice_get_flags(const struct slice *s)
521 struct subpartition *
522 slice_subpartition_first(const struct slice *s)
524 return(s->subpartition_head);
528 * Free all memory for a list of slice descriptions.
531 slices_free(struct slice *head)
535 while (head != NULL) {
537 subpartitions_free(head);
539 AURA_FREE(head, slice);
545 * NOTE: arguments to this function are not checked for sanity.
547 * fsize and/or bsize may both be -1, indicating
548 * "choose a reasonable default."
550 struct subpartition *
551 subpartition_new(struct slice *s, const char *mountpoint, long capacity,
552 int softupdates, long fsize, long bsize, int mfsbacked)
554 struct subpartition *sp;
556 AURA_MALLOC(sp, subpartition);
563 struct subpartition *last = s->subpartition_tail;
564 while (last != NULL && last->mfsbacked) {
569 } else if (last->letter == 'b') {
572 sp->letter = (char)(last->letter + 1);
576 sp->mountpoint = aura_strdup(mountpoint);
577 sp->capacity = capacity;
580 if (sp->capacity < 1024)
589 if (sp->capacity < 1024)
597 if (softupdates == -1) {
598 if (strcmp(mountpoint, "/") == 0)
603 sp->softupdates = softupdates;
606 sp->mfsbacked = mfsbacked;
609 if (strcasecmp(mountpoint, "swap") == 0)
613 if (s->subpartition_head == NULL)
614 s->subpartition_head = sp;
616 s->subpartition_tail->next = sp;
618 sp->prev = s->subpartition_tail;
619 s->subpartition_tail = sp;
625 * Find the subpartition description in the given storage
626 * description whose mountpoint matches the given string exactly.
628 struct subpartition *
629 subpartition_find(const struct slice *s, const char *fmt, ...)
631 struct subpartition *sp = s->subpartition_head;
636 vasprintf(&mountpoint, fmt, args);
640 if (strcmp(mountpoint, sp->mountpoint) == 0) {
652 * Find the subpartition description in the given storage
653 * description where the given filename would presumably
654 * reside. This is the subpartition whose mountpoint is
655 * the longest match for the given filename.
657 struct subpartition *
658 subpartition_of(const struct slice *s, const char *fmt, ...)
660 struct subpartition *sp = s->subpartition_head;
661 struct subpartition *csp = NULL;
667 vasprintf(&filename, fmt, args);
671 if (strlen(sp->mountpoint) > len &&
672 strlen(sp->mountpoint) <= strlen(filename) &&
673 strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
675 len = strlen(csp->mountpoint);
684 struct subpartition *
685 subpartition_find_capacity(const struct slice *s, long capacity)
687 struct subpartition *sp = s->subpartition_head;
690 if (sp->capacity == capacity)
698 struct subpartition *
699 subpartition_next(const struct subpartition *sp)
705 * Returns the name of the device node used to represent
707 * Note that the storage used for the returned string is static,
708 * and the string is overwritten each time this function is called.
711 subpartition_get_device_name(const struct subpartition *sp)
713 static char tmp_dev_name[256];
716 snprintf(tmp_dev_name, 256, "%s%c", sp->parent->parent->device,
719 snprintf(tmp_dev_name, 256, "%ss%d%c", sp->parent->parent->device,
720 sp->parent->number, sp->letter);
722 return(tmp_dev_name);
726 * Returns the name of the device node used to represent
727 * the raw subpartition.
728 * Note that the storage used for the returned string is static,
729 * and the string is overwritten each time this function is called.
732 subpartition_get_raw_device_name(const struct subpartition *sp)
734 static char tmp_dev_name[256];
737 * for OpenBSD, this has an "r" prepended to it.
740 snprintf(tmp_dev_name, 256, "r%s%c", sp->parent->parent->device,
743 snprintf(tmp_dev_name, 256, "r%ss%d%c", sp->parent->parent->device,
744 sp->parent->number, sp->letter);
746 return(tmp_dev_name);
750 subpartition_get_mountpoint(const struct subpartition *sp)
752 return(sp->mountpoint);
756 subpartition_get_letter(const struct subpartition *sp)
762 subpartition_get_fsize(const struct subpartition *sp)
768 subpartition_get_bsize(const struct subpartition *sp)
774 subpartition_get_capacity(const struct subpartition *sp)
776 return(sp->capacity);
780 subpartition_is_swap(const struct subpartition *sp)
786 subpartition_is_softupdated(const struct subpartition *sp)
788 return(sp->softupdates);
791 subpartition_is_mfsbacked(const struct subpartition *sp)
793 return(sp->mfsbacked);
797 subpartition_count(const struct slice *s)
799 struct subpartition *sp = s->subpartition_head;
811 subpartitions_free(struct slice *s)
813 struct subpartition *sp = s->subpartition_head, *next;
817 free(sp->mountpoint);
818 AURA_FREE(sp, subpartition);
822 s->subpartition_head = NULL;
823 s->subpartition_tail = NULL;
827 measure_activated_swap(const struct i_fn_args *a)
834 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
836 while (fgets(line, 255, p) != NULL) {
837 if ((word = strtok(line, " \t")) == NULL)
839 if (strcmp(word, "Device") == 0)
841 if ((word = strtok(NULL, " \t")) == NULL)
851 measure_activated_swap_from_slice(const struct i_fn_args *a,
852 const struct disk *d, const struct slice *s)
859 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
862 asprintf(&dev, "/dev/%ss%d", d->device, s->number);
864 while (fgets(line, 255, p) != NULL) {
865 if ((word = strtok(line, " \t")) == NULL)
867 if (strcmp(word, "Device") == 0)
869 if (strstr(word, dev) != word)
871 if ((word = strtok(NULL, " \t")) == NULL)
882 measure_activated_swap_from_disk(const struct i_fn_args *a,
883 const struct disk *d)
888 for (s = d->slice_head; s != NULL; s = s->next)
889 swap += measure_activated_swap_from_slice(a, d, s);