HAMMER VFS - Hack cursor iterator when locked cursor moved to parent
[dragonfly.git] / usr.sbin / installer / libinstaller / diskutil.c
blob7158e30c3d2846067a6948a500b6b087fb13e99c
1 /*
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
6 * are met:
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
14 * distribution.
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.
35 * diskutil.c
36 * Disk utility functions for installer.
37 * $Id: diskutil.c,v 1.44 2005/02/07 06:41:42 cpressey Exp $
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
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
53 #include "diskutil.h"
54 #undef NEEDS_DISKUTIL_STRUCTURE_DEFINITIONS
56 #include "commands.h"
57 #include "functions.h"
58 #include "sysids.h"
59 #include "uiutil.h"
61 static int disk_description_is_better(const char *, const char *);
63 /** STORAGE DESCRIPTORS **/
65 struct storage *
66 storage_new(void)
68 struct storage *s;
70 AURA_MALLOC(s, storage);
72 s->disk_head = NULL;
73 s->disk_tail = NULL;
74 s->selected_disk = NULL;
75 s->selected_slice = NULL;
76 s->ram = -1;
78 return(s);
81 int
82 storage_get_mfs_status(const char *mountpoint, struct storage *s)
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_mfsbacked(sp) == 1) {
90 return 1;
91 } else {
92 return 0;
96 return 0;
99 void
100 storage_free(struct storage *s)
102 disks_free(s);
103 AURA_FREE(s, storage);
106 void
107 storage_set_memsize(struct storage *s, unsigned long memsize)
109 s->ram = memsize;
112 unsigned long
113 storage_get_memsize(const struct storage *s)
115 return(s->ram);
118 struct disk *
119 storage_disk_first(const struct storage *s)
121 return(s->disk_head);
124 void
125 storage_set_selected_disk(struct storage *s, struct disk *d)
127 s->selected_disk = d;
130 struct disk *
131 storage_get_selected_disk(const struct storage *s)
133 return(s->selected_disk);
136 void
137 storage_set_selected_slice(struct storage *s, struct slice *sl)
139 s->selected_slice = sl;
142 struct slice *
143 storage_get_selected_slice(const struct storage *s)
145 return(s->selected_slice);
149 * Create a new disk description structure.
151 struct disk *
152 disk_new(struct storage *s, const char *dev_name)
154 struct disk *d;
156 if (disk_find(s, dev_name) != NULL) {
157 /* Already discovered */
158 return(NULL);
161 AURA_MALLOC(d, disk);
163 d->device = aura_strdup(dev_name);
164 d->desc = NULL;
165 d->serno = NULL;
166 d->we_formatted = 0;
167 d->capacity = 0;
169 d->cylinders = -1; /* -1 indicates "we don't know" */
170 d->heads = -1;
171 d->sectors = -1;
173 d->slice_head = NULL;
174 d->slice_tail = NULL;
176 d->next = NULL;
177 if (s->disk_head == NULL)
178 s->disk_head = d;
179 else
180 s->disk_tail->next = d;
182 d->prev = s->disk_tail;
183 s->disk_tail = d;
185 return(d);
188 static int
189 disk_description_is_better(const char *existing, const char *new_desc __unused)
191 if (existing == NULL)
192 return(1);
193 return(0);
196 const char *
197 disk_get_desc(const struct disk *d)
199 return(d->desc);
202 void
203 disk_set_desc(struct disk *d, const char *desc)
205 char *c;
207 if (!disk_description_is_better(d->desc, desc))
208 return;
209 if (d->desc != NULL)
210 free(d->desc);
211 d->desc = aura_strdup(desc);
214 * Get the disk's total capacity.
215 * XXX we should do this with C/H/S ?
217 c = d->desc;
218 while (*c != ':' && *c != '\0')
219 c++;
220 if (*c == '\0')
221 d->capacity = 0;
222 else
223 d->capacity = atoi(c + 1);
227 * Returns the name of the device node used to represent the disk.
228 * Note that the storage used for the returned string is static,
229 * and the string is overwritten each time this function is called.
231 const char *
232 disk_get_device_name(const struct disk *d)
234 static char tmp_dev_name[256];
236 snprintf(tmp_dev_name, 256, "%s", d->device);
237 return(tmp_dev_name);
240 const char *
241 disk_get_serno(const struct disk *d)
243 return(d->serno);
246 void
247 disk_set_serno(struct disk *d, const char *serno)
249 d->serno = aura_strdup(serno);
253 disk_get_number(const struct disk *d)
255 return(d->number);
258 void
259 disk_set_number(struct disk *d, const int number)
261 d->number = number;
265 * Find the first disk description structure in the given
266 * storage description which matches the given device name
267 * prefix. Note that this means that if a storage
268 * description s contains disks named "ad0" and "ad1",
269 * disk_find(s, "ad0s1c") will return a pointer to the disk
270 * structure for "ad0".
272 struct disk *
273 disk_find(const struct storage *s, const char *device)
275 struct disk *d = s->disk_head;
277 while (d != NULL) {
278 if (strncmp(device, d->device, strlen(d->device)) == 0)
279 return(d);
280 d = d->next;
283 return(NULL);
286 struct disk *
287 disk_next(const struct disk *d)
289 return(d->next);
292 struct slice *
293 disk_slice_first(const struct disk *d)
295 return(d->slice_head);
298 void
299 disk_set_formatted(struct disk *d, int formatted)
301 d->we_formatted = formatted;
305 disk_get_formatted(const struct disk *d)
307 return(d->we_formatted);
310 void
311 disk_set_geometry(struct disk *d, int cyl, int hd, int sec)
313 d->cylinders = cyl;
314 d->heads = hd;
315 d->sectors = sec;
318 void
319 disk_get_geometry(const struct disk *d, int *cyl, int *hd, int *sec)
321 *cyl = d->cylinders;
322 *hd = d->heads;
323 *sec = d->sectors;
327 * Free the memory allocated to hold the set of disk descriptions.
329 void
330 disks_free(struct storage *s)
332 struct disk *d = s->disk_head, *next;
334 while (d != NULL) {
335 next = d->next;
336 slices_free(d->slice_head);
337 free(d->desc);
338 free(d->device);
339 AURA_FREE(d, disk);
340 d = next;
343 s->disk_head = NULL;
344 s->disk_tail = NULL;
348 * Create a new slice description and add it to a disk description.
350 struct slice *
351 slice_new(struct disk *d, int number, int type, int flags,
352 unsigned long start, unsigned long size)
354 struct slice *s;
355 const char *sysid_desc = NULL;
356 char unknown[256];
357 int i;
359 dfui_debug("** adding slice %d (start %ld, size %ld, sysid %d) "
360 "to disk %s\n", number, start, size, type, d->device);
362 AURA_MALLOC(s, slice);
364 s->parent = d;
366 s->subpartition_head = NULL;
367 s->subpartition_tail = NULL;
368 s->number = number;
370 s->type = type;
371 s->flags = flags;
372 s->start = start;
373 s->size = size;
375 for (i = 0; ; i++) {
376 if (part_types[i].type == type) {
377 sysid_desc = part_types[i].name;
378 break;
380 if (part_types[i].type == 255)
381 break;
383 if (sysid_desc == NULL) {
384 snprintf(unknown, 256, "??? Unknown, sysid = %d", type);
385 sysid_desc = unknown;
388 asprintf(&s->desc, "%ldM - %ldM: %s",
389 start / 2048, (start + size) / 2048, sysid_desc);
390 s->capacity = size / 2048;
392 s->next = NULL;
393 if (d->slice_head == NULL)
394 d->slice_head = s;
395 else
396 d->slice_tail->next = s;
398 s->prev = d->slice_tail;
399 d->slice_tail = s;
401 return(s);
405 * Find a slice description on a given disk description given the
406 * slice number.
408 struct slice *
409 slice_find(const struct disk *d, int number)
411 struct slice *s = d->slice_head;
413 while (s != NULL) {
414 if (s->number == number)
415 return(s);
416 s = s->next;
419 return(NULL);
422 struct slice *
423 slice_next(const struct slice *s)
425 return(s->next);
429 * Returns the name of the device node used to represent the slice.
430 * Note that the storage used for the returned string is static,
431 * and the string is overwritten each time this function is called.
433 const char *
434 slice_get_device_name(const struct slice *s)
436 static char tmp_dev_name[256];
438 snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
439 return(tmp_dev_name);
443 slice_get_number(const struct slice *s)
445 return(s->number);
448 const char *
449 slice_get_desc(const struct slice *s)
451 return(s->desc);
454 unsigned long
455 slice_get_capacity(const struct slice *s)
457 return(s->capacity);
460 unsigned long
461 slice_get_start(const struct slice *s)
463 return(s->start);
466 unsigned long
467 slice_get_size(const struct slice *s)
469 return(s->size);
473 slice_get_type(const struct slice *s)
475 return(s->type);
479 slice_get_flags(const struct slice *s)
481 return(s->flags);
484 struct subpartition *
485 slice_subpartition_first(const struct slice *s)
487 return(s->subpartition_head);
491 * Free all memory for a list of slice descriptions.
493 void
494 slices_free(struct slice *head)
496 struct slice *next;
498 while (head != NULL) {
499 next = head->next;
500 subpartitions_free(head);
501 free(head->desc);
502 AURA_FREE(head, slice);
503 head = next;
507 struct subpartition *
508 subpartition_new_hammer(struct slice *s, const char *mountpoint, long capacity)
510 struct subpartition *sp;
512 AURA_MALLOC(sp, subpartition);
514 sp->parent = s;
516 struct subpartition *last = s->subpartition_tail;
517 if (last == NULL) {
518 sp->letter = 'a';
519 } else if (last->letter == 'b') {
520 sp->letter = 'd';
521 } else {
522 sp->letter = (char)(last->letter + 1);
525 sp->mountpoint = aura_strdup(mountpoint);
526 sp->capacity = capacity;
527 sp->type = FS_HAMMER;
530 * We need this here, because a UFS /boot needs valid values
532 if (sp->capacity < 1024)
533 sp->fsize = 1024;
534 else
535 sp->fsize = 2048;
537 if (sp->capacity < 1024)
538 sp->bsize = 8192;
539 else
540 sp->bsize = 16384;
542 sp->is_swap = 0;
543 sp->pfs = 0;
544 if (strcasecmp(mountpoint, "swap") == 0)
545 sp->is_swap = 1;
546 if (strcmp(mountpoint, "/") != 0 && strcmp(mountpoint, "/boot") != 0 &&
547 strcmp(mountpoint, "swap") != 0)
548 sp->pfs = 1;
550 sp->next = NULL;
551 if (s->subpartition_head == NULL)
552 s->subpartition_head = sp;
553 else
554 s->subpartition_tail->next = sp;
556 sp->prev = s->subpartition_tail;
557 s->subpartition_tail = sp;
559 return(sp);
563 * NOTE: arguments to this function are not checked for sanity.
565 * fsize and/or bsize may both be -1, indicating
566 * "choose a reasonable default."
568 struct subpartition *
569 subpartition_new(struct slice *s, const char *mountpoint, long capacity,
570 int softupdates, long fsize, long bsize, int mfsbacked)
572 struct subpartition *sp, *sptmp;
573 int letter='d';
575 AURA_MALLOC(sp, subpartition);
577 sp->parent = s;
579 sp->mountpoint = aura_strdup(mountpoint);
580 sp->capacity = capacity;
581 sp->type = FS_UFS;
583 if (fsize == -1) {
584 if (sp->capacity < 1024)
585 sp->fsize = 1024;
586 else
587 sp->fsize = 2048;
588 } else {
589 sp->fsize = fsize;
592 if (bsize == -1) {
593 if (sp->capacity < 1024)
594 sp->bsize = 8192;
595 else
596 sp->bsize = 16384;
597 } else {
598 sp->bsize = bsize;
601 if (softupdates == -1) {
602 if (strcmp(mountpoint, "/") == 0)
603 sp->softupdates = 0;
604 else
605 sp->softupdates = 1;
606 } else {
607 sp->softupdates = softupdates;
610 sp->mfsbacked = mfsbacked;
612 sp->is_swap = 0;
613 if (strcasecmp(mountpoint, "swap") == 0)
614 sp->is_swap = 1;
616 if (s->subpartition_head == NULL) {
617 s->subpartition_head = sp;
618 s->subpartition_tail = sp;
619 } else {
620 for (sptmp = s->subpartition_head; sptmp != NULL;
621 sptmp = sptmp->next) {
622 if (strcmp(sptmp->mountpoint, sp->mountpoint) > 0)
623 break;
625 if (sptmp != NULL) {
626 if (s->subpartition_head == sptmp)
627 s->subpartition_head = sp;
628 else
629 sptmp->prev->next = sp;
630 sp->next = sptmp;
631 sp->prev = sptmp->prev;
632 sptmp->prev = sp;
633 } else {
634 sp->prev = s->subpartition_tail;
635 s->subpartition_tail->next = sp;
636 s->subpartition_tail = sp;
640 for (sptmp = s->subpartition_head; sptmp != NULL;
641 sptmp = sptmp->next) {
642 if (sptmp->mfsbacked)
643 sptmp->letter = '@';
644 else if (strcmp(sptmp->mountpoint, "/") == 0 ||
645 strcmp(sptmp->mountpoint, "/dummy") == 0)
646 sptmp->letter = 'a';
647 else if (strcasecmp(sptmp->mountpoint, "swap") == 0)
648 sptmp->letter = 'b';
649 else
650 sptmp->letter = letter++;
653 return(sp);
657 * Find the subpartition description in the given storage
658 * description whose mountpoint matches the given string exactly.
660 struct subpartition *
661 subpartition_find(const struct slice *s, const char *fmt, ...)
663 struct subpartition *sp = s->subpartition_head;
664 char *mountpoint;
665 va_list args;
667 va_start(args, fmt);
668 vasprintf(&mountpoint, fmt, args);
669 va_end(args);
671 while (sp != NULL) {
672 if (strcmp(mountpoint, sp->mountpoint) == 0) {
673 free(mountpoint);
674 return(sp);
676 sp = sp->next;
679 free(mountpoint);
680 return(NULL);
684 * Find the subpartition description in the given storage
685 * description where the given filename would presumably
686 * reside. This is the subpartition whose mountpoint is
687 * the longest match for the given filename.
689 struct subpartition *
690 subpartition_of(const struct slice *s, const char *fmt, ...)
692 struct subpartition *sp = s->subpartition_head;
693 struct subpartition *csp = NULL;
694 size_t len = 0;
695 char *filename;
696 va_list args;
698 va_start(args, fmt);
699 vasprintf(&filename, fmt, args);
700 va_end(args);
702 while (sp != NULL) {
703 if (strlen(sp->mountpoint) > len &&
704 strlen(sp->mountpoint) <= strlen(filename) &&
705 strncmp(filename, sp->mountpoint, strlen(sp->mountpoint)) == 0) {
706 csp = sp;
707 len = strlen(csp->mountpoint);
709 sp = sp->next;
712 free(filename);
713 return(csp);
716 struct subpartition *
717 subpartition_find_capacity(const struct slice *s, long capacity)
719 struct subpartition *sp = s->subpartition_head;
721 while (sp != NULL) {
722 if (sp->capacity == capacity)
723 return(sp);
724 sp = sp->next;
727 return(NULL);
730 struct subpartition *
731 subpartition_next(const struct subpartition *sp)
733 return(sp->next);
737 subpartition_get_pfs(const struct subpartition *sp)
739 return(sp->pfs);
743 * Returns the name of the device node used to represent
744 * the subpartition, either by serial number or traditional style.
745 * Note that the storage used for the returned string is static,
746 * and the string is overwritten each time this function is called.
748 const char *
749 subpartition_get_device_name(const struct subpartition *sp)
751 static char tmp_dev_name[256];
753 if (sp->parent->parent->serno != NULL)
754 snprintf(tmp_dev_name, 256, "serno/%s.s%d%c",
755 sp->parent->parent->serno, sp->parent->number, sp->letter);
756 else
757 snprintf(tmp_dev_name, 256, "%ss%d%c",
758 sp->parent->parent->device, sp->parent->number, sp->letter);
759 return(tmp_dev_name);
762 const char *
763 subpartition_get_mountpoint(const struct subpartition *sp)
765 return(sp->mountpoint);
768 char
769 subpartition_get_letter(const struct subpartition *sp)
771 return(sp->letter);
774 unsigned long
775 subpartition_get_fsize(const struct subpartition *sp)
777 return(sp->fsize);
780 unsigned long
781 subpartition_get_bsize(const struct subpartition *sp)
783 return(sp->bsize);
786 unsigned long
787 subpartition_get_capacity(const struct subpartition *sp)
789 return(sp->capacity);
793 subpartition_is_swap(const struct subpartition *sp)
795 return(sp->is_swap);
799 subpartition_is_softupdated(const struct subpartition *sp)
801 return(sp->softupdates);
804 subpartition_is_mfsbacked(const struct subpartition *sp)
806 return(sp->mfsbacked);
810 subpartition_count(const struct slice *s)
812 struct subpartition *sp = s->subpartition_head;
813 int count = 0;
815 while (sp != NULL) {
816 count++;
817 sp = sp->next;
820 return(count);
823 void
824 subpartitions_free(struct slice *s)
826 struct subpartition *sp = s->subpartition_head, *next;
828 while (sp != NULL) {
829 next = sp->next;
830 free(sp->mountpoint);
831 AURA_FREE(sp, subpartition);
832 sp = next;
835 s->subpartition_head = NULL;
836 s->subpartition_tail = NULL;
839 long
840 measure_activated_swap(const struct i_fn_args *a)
842 FILE *p;
843 char line[256];
844 char *word;
845 long swap = 0;
847 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
848 return(0);
849 while (fgets(line, 255, p) != NULL) {
850 if ((word = strtok(line, " \t")) == NULL)
851 continue;
852 if (strcmp(word, "Device") == 0)
853 continue;
854 if ((word = strtok(NULL, " \t")) == NULL)
855 continue;
856 swap += atol(word);
858 aura_pclose(p);
860 return(swap / 1024);
863 long
864 measure_activated_swap_from_slice(const struct i_fn_args *a,
865 const struct disk *d, const struct slice *s)
867 FILE *p;
868 char *dev, *word;
869 char line[256];
870 long swap = 0;
872 if ((p = aura_popen("%s%s -k", "r", a->os_root, cmd_name(a, "SWAPINFO"))) == NULL)
873 return(0);
875 asprintf(&dev, "/dev/%ss%d", d->device, s->number);
877 while (fgets(line, 255, p) != NULL) {
878 if ((word = strtok(line, " \t")) == NULL)
879 continue;
880 if (strcmp(word, "Device") == 0)
881 continue;
882 if (strstr(word, dev) != word)
883 continue;
884 if ((word = strtok(NULL, " \t")) == NULL)
885 continue;
886 swap += atol(word);
888 aura_pclose(p);
889 free(dev);
891 return(swap / 1024);
894 long
895 measure_activated_swap_from_disk(const struct i_fn_args *a,
896 const struct disk *d)
898 struct slice *s;
899 long swap = 0;
901 for (s = d->slice_head; s != NULL; s = s->next)
902 swap += measure_activated_swap_from_slice(a, d, s);
904 return(swap);