2 * The new sysinstall program.
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
7 * $FreeBSD: src/release/sysinstall/label.c,v 1.98.2.13 2003/01/27 19:59:28 dillon Exp $
8 * $DragonFly: src/release/sysinstall/Attic/label.c,v 1.2 2003/06/17 04:27:21 dillon Exp $
11 * Jordan Hubbard. All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer,
18 * verbatim and that no modifications are made prior to this
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
24 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include "sysinstall.h"
40 #include <sys/disklabel.h>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
44 #define AUTO_HOME 0 /* do not create /home automatically */
47 * Everything to do with editing the contents of disk labels.
50 /* A nice message we use a lot in the disklabel editor */
51 #define MSG_NOT_APPLICABLE "That option is not applicable here"
53 /* Where to start printing the freebsd slices */
54 #define CHUNK_SLICE_START_ROW 2
55 #define CHUNK_PART_START_ROW 11
57 /* The smallest filesystem we're willing to create */
58 #define FS_MIN_SIZE ONE_MEG
61 * Minimum partition sizes
64 #define ROOT_MIN_SIZE 40
66 #define ROOT_MIN_SIZE 30
68 #define SWAP_MIN_SIZE 32
69 #define USR_MIN_SIZE 80
70 #define VAR_MIN_SIZE 20
71 #define TMP_MIN_SIZE 20
72 #define HOME_MIN_SIZE 20
75 * Swap size limit for auto-partitioning (4G).
77 #define SWAP_AUTO_LIMIT_SIZE 4096
80 * Default partition sizes. If we do not have sufficient disk space
81 * for this configuration we scale things relative to the NOM vs DEFAULT
82 * sizes. If the disk is larger then /home will get any remaining space.
84 #define ROOT_DEFAULT_SIZE 128
85 #define USR_DEFAULT_SIZE 3072
86 #define VAR_DEFAULT_SIZE 256
87 #define TMP_DEFAULT_SIZE 256
88 #define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE
91 * Nominal partition sizes. These are used to scale the default sizes down
92 * when we have insufficient disk space. If this isn't sufficient we scale
93 * down using the MIN sizes instead.
95 #define ROOT_NOMINAL_SIZE 128
96 #define USR_NOMINAL_SIZE 512
97 #define VAR_NOMINAL_SIZE 64
98 #define TMP_NOMINAL_SIZE 64
99 #define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE
101 /* The bottom-most row we're allowed to scribble on */
102 #define CHUNK_ROW_MAX 16
105 /* All the chunks currently displayed on the screen */
109 } label_chunk_info[MAX_CHUNKS + 1];
112 /*** with this value we try to track the most recently added label ***/
113 static int label_focus = 0, pslice_focus = 0;
115 static int diskLabel(Device *dev);
116 static int diskLabelNonInteractive(Device *dev);
117 static char *try_auto_label(Device **devs, Device *dev, int perc, int *req);
120 labelHook(dialogMenuItem *selected)
122 Device **devs = NULL;
124 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
126 msgConfirm("Unable to find disk %s!", selected->prompt);
127 return DITEM_FAILURE;
129 /* Toggle enabled status? */
130 if (!devs[0]->enabled) {
131 devs[0]->enabled = TRUE;
135 devs[0]->enabled = FALSE;
136 return DITEM_SUCCESS;
140 labelCheck(dialogMenuItem *selected)
142 Device **devs = NULL;
144 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
145 if (!devs || devs[0]->enabled == FALSE)
151 diskLabelEditor(dialogMenuItem *self)
158 cnt = diskGetSelectCount(&devs);
160 msgConfirm("No disks found! Please verify that your disk controller is being\n"
161 "properly probed at boot time. See the Hardware Guide on the\n"
162 "Documentation menu for clues on diagnosing this type of problem.");
163 return DITEM_FAILURE;
166 /* Some are already selected */
167 if (variable_get(VAR_NONINTERACTIVE) &&
168 !variable_get(VAR_DISKINTERACTIVE))
169 i = diskLabelNonInteractive(NULL);
174 /* No disks are selected, fall-back case now */
175 cnt = deviceCount(devs);
177 devs[0]->enabled = TRUE;
178 if (variable_get(VAR_NONINTERACTIVE) &&
179 !variable_get(VAR_DISKINTERACTIVE))
180 i = diskLabelNonInteractive(devs[0]);
182 i = diskLabel(devs[0]);
185 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
187 msgConfirm("No devices suitable for installation found!\n\n"
188 "Please verify that your disk controller (and attached drives)\n"
189 "were detected properly. This can be done by pressing the\n"
190 "[Scroll Lock] key and using the Arrow keys to move back to\n"
191 "the boot messages. Press [Scroll Lock] again to return.");
195 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
200 if (DITEM_STATUS(i) != DITEM_FAILURE) {
201 if (variable_cmp(DISK_LABELLED, "written"))
202 variable_set2(DISK_LABELLED, "yes", 0);
208 diskLabelCommit(dialogMenuItem *self)
214 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
217 msgConfirm("You must assign disk labels before this option can be used.");
220 /* The routine will guard against redundant writes, just as this one does */
221 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
223 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
226 msgInfo("All filesystem information written successfully.");
227 variable_set2(DISK_LABELLED, "written", 0);
233 /* See if we're already using a desired partition name */
235 check_conflict(char *name)
239 for (i = 0; label_chunk_info[i].c; i++)
240 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
241 && label_chunk_info[i].c->private_data
242 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
247 /* How much space is in this FreeBSD slice? */
249 space_free(struct chunk *c)
254 for (c1 = c->part; c1; c1 = c1->next) {
255 if (c1->type != unused)
259 msgFatal("Partitions are larger than actual chunk??");
263 /* Snapshot the current situation into the displayed chunks structure */
265 record_label_chunks(Device **devs, Device *dev)
268 struct chunk *c1, *c2;
272 /* First buzz through and pick up the FreeBSD slices */
273 for (i = 0; devs[i]; i++) {
274 if ((dev && devs[i] != dev) || !devs[i]->enabled)
276 d = (Disk *)devs[i]->private;
278 msgFatal("No chunk list found for %s!", d->name);
280 /* Put the slice entries first */
281 for (c1 = d->chunks->part; c1; c1 = c1->next) {
282 if (c1->type == freebsd) {
283 label_chunk_info[j].type = PART_SLICE;
284 label_chunk_info[j].c = c1;
290 /* Now run through again and get the FreeBSD partition entries */
291 for (i = 0; devs[i]; i++) {
292 if (!devs[i]->enabled)
294 d = (Disk *)devs[i]->private;
295 /* Then buzz through and pick up the partitions */
296 for (c1 = d->chunks->part; c1; c1 = c1->next) {
297 if (c1->type == freebsd) {
298 for (c2 = c1->part; c2; c2 = c2->next) {
299 if (c2->type == part) {
300 if (c2->subtype == FS_SWAP)
301 label_chunk_info[j].type = PART_SWAP;
303 label_chunk_info[j].type = PART_FILESYSTEM;
304 label_chunk_info[j].c = c2;
309 else if (c1->type == fat) {
310 label_chunk_info[j].type = PART_FAT;
311 label_chunk_info[j].c = c1;
316 label_chunk_info[j].c = NULL;
318 here = j ? j - 1 : 0;
322 /* A new partition entry */
324 new_part(char *mpoint, Boolean newfs, u_long size)
329 mpoint = "/change_me";
331 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
332 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
333 strcpy(ret->newfs_cmd, "newfs ");
334 strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS));
336 ret->soft = strcmp(mpoint, "/") ? 1 : 0;
342 /* Get the mountpoint for a partition and save it away */
344 get_mountpoint(struct chunk *old)
349 if (old && old->private_data)
350 tmp = old->private_data;
353 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
358 free(old->private_data);
359 old->private_data = NULL;
364 /* Is it just the same value? */
365 if (tmp && !strcmp(tmp->mountpoint, val))
368 /* Did we use it already? */
369 if (check_conflict(val)) {
370 msgConfirm("You already have a mount point for %s assigned!", val);
376 msgConfirm("Mount point must start with a / character");
380 /* Is it going to be mounted on root? */
381 if (!strcmp(val, "/")) {
383 old->flags |= CHUNK_IS_ROOT;
386 old->flags &= ~CHUNK_IS_ROOT;
389 val = string_skipwhite(string_prune(val));
390 tmp = new_part(val, TRUE, 0);
392 old->private_data = tmp;
393 old->private_free = safe_free;
398 /* Get the type of the new partiton */
400 get_partition_type(void)
404 static unsigned char *fs_types[] = {
410 WINDOW *w = savescr();
412 i = dialog_menu("Please choose a partition type",
413 "If you want to use this partition for swap space, select Swap.\n"
414 "If you want to put a filesystem on it, choose FS.",
415 -1, -1, 2, 2, fs_types, selection, NULL, NULL);
418 if (!strcmp(selection, "FS"))
419 return PART_FILESYSTEM;
420 else if (!strcmp(selection, "Swap"))
426 /* If the user wants a special newfs command for this, set it */
428 getNewfsCmd(PartInfo *p)
432 val = msgGetInput(p->newfs_cmd,
433 "Please enter the newfs command and options you'd like to use in\n"
434 "creating this file system.");
436 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
439 #define MAX_MOUNT_NAME 9
441 #define PART_PART_COL 0
442 #define PART_MOUNT_COL 10
443 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
444 #define PART_NEWFS_COL (PART_SIZE_COL + 8)
447 #define TOTAL_AVAIL_LINES (10)
448 #define PSLICE_SHOWABLE (4)
451 /* stick this all up on the screen */
453 print_label_chunks(void)
455 int i, j, srow, prow, pcol;
458 int ChunkPartStartRow;
461 /********************************************************/
462 /*** These values are for controling screen resources ***/
463 /*** Each label line holds up to 2 labels, so beware! ***/
464 /*** strategy will be to try to always make sure the ***/
465 /*** highlighted label is in the active display area. ***/
466 /********************************************************/
467 int pslice_max, label_max;
468 int pslice_count, label_count, label_focus_found, pslice_focus_found;
471 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
474 /*** Count the number of parition slices ***/
476 for (i = 0; label_chunk_info[i].c ; i++) {
477 if (label_chunk_info[i].type == PART_SLICE)
480 pslice_max = pslice_count;
482 /*** 4 line max for partition slices ***/
483 if (pslice_max > PSLICE_SHOWABLE) {
484 pslice_max = PSLICE_SHOWABLE;
486 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
488 /*** View partition slices modulo pslice_max ***/
489 label_max = TOTAL_AVAIL_LINES - pslice_max;
491 for (i = 0; i < 2; i++) {
492 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
493 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
495 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
496 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
498 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
499 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
501 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
502 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
504 srow = CHUNK_SLICE_START_ROW;
508 /*** these variables indicate that the focused item is shown currently ***/
509 label_focus_found = 0;
510 pslice_focus_found = 0;
514 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " ");
515 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " ");
517 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
520 /*** wrefresh(ChunkWin); ***/
522 for (i = 0; label_chunk_info[i].c; i++) {
523 /* Is it a slice entry displayed at the top? */
524 if (label_chunk_info[i].type == PART_SLICE) {
525 /*** This causes the new pslice to replace the previous display ***/
526 /*** focus must remain on the most recently active pslice ***/
527 if (pslice_count == pslice_max) {
528 if (pslice_focus_found) {
529 /*** This is where we can mark the more following ***/
531 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
536 /*** this is where we set the more previous ***/
538 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
541 srow = CHUNK_SLICE_START_ROW;
545 sz = space_free(label_chunk_info[i].c);
547 attrset(ATTR_SELECTED);
548 if (i == pslice_focus)
549 pslice_focus_found = -1;
552 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
553 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
561 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
563 char onestr[PART_OFF], num[10], *mountpoint, newfs[10];
566 * We copy this into a blank-padded string so that it looks like
567 * a solid bar in reverse-video
569 memset(onestr, ' ', PART_OFF - 1);
570 onestr[PART_OFF - 1] = '\0';
572 /*** Track how many labels have been displayed ***/
573 if (label_count == ((label_max - 1 ) * 2)) {
574 if (label_focus_found) {
584 /* Go for two columns if we've written one full columns worth */
585 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
586 if (label_count == label_max - 1) {
590 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
591 /* If it's a filesystem, display the mountpoint */
592 if (label_chunk_info[i].c->private_data
593 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
594 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
595 else if (label_chunk_info[i].type == PART_SWAP)
598 mountpoint = "<none>";
600 /* Now display the newfs field */
601 if (label_chunk_info[i].type == PART_FAT)
602 strcpy(newfs, "DOS");
603 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
604 strcpy(newfs, "UFS");
606 ((PartInfo *)label_chunk_info[i].c->private_data)->soft ?
609 ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ?
612 else if (label_chunk_info[i].type == PART_SWAP)
613 strcpy(newfs, "SWAP");
616 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
617 onestr[PART_MOUNT_COL + j] = mountpoint[j];
618 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
619 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
620 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
621 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
622 if (i == label_focus) {
623 label_focus_found = -1;
624 wattrset(ChunkWin, A_BOLD);
627 wattrset(ChunkWin, ATTR_SELECTED);
629 /*** lazy man's way of expensively padding this string ***/
630 while (strlen(onestr) < 37)
633 mvwaddstr(ChunkWin, prow, pcol, onestr);
634 wattrset(ChunkWin, A_NORMAL);
641 /*** this will erase all the extra stuff ***/
642 memset(clrmsg, ' ', 37);
645 while (pslice_count < pslice_max) {
646 mvprintw(srow++, 0, clrmsg);
650 while (label_count < (2 * (label_max - 1))) {
651 mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
653 if (prow == (label_max - 1)) {
663 print_command_summary(void)
665 mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
666 mvprintw(18, 0, "C = Create D = Delete M = Mount pt.");
668 mvprintw(18, 47, "W = Write");
669 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates");
670 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge");
671 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
678 extern void print_label_chunks();
680 print_label_chunks();
686 * If there isn't a freebsd chunk already (i.e. there is no label),
690 maybe_dedicate(Disk* d)
694 for (c = d->chunks->part; c; c = c->next) {
695 if (c->type == freebsd)
700 msgDebug("dedicating disk");
708 diskLabel(Device *dev)
719 WINDOW *w = savescr();
725 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
727 msgConfirm("No disks found!");
729 return DITEM_FAILURE;
732 keypad(stdscr, TRUE);
734 for (i = 0; devs[i]; i++) {
735 maybe_dedicate((Disk*) devs[i]->private);
738 record_label_chunks(devs, dev);
743 int rflags = DELCHUNK_NORMAL;
745 print_label_chunks();
746 print_command_summary();
748 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
760 switch (toupper(key)) {
762 static char _msg[40];
764 case '\014': /* ^L */
768 case '\020': /* ^P */
774 while (label_chunk_info[here + 1].c)
778 case '\016': /* ^N */
783 if (label_chunk_info[here + 1].c)
794 while (label_chunk_info[here + 1].c)
800 systemDisplayHelp("partition");
805 if (label_chunk_info[here].type != PART_SLICE) {
806 msg = "You can only do this in a disk slice (at top of screen)";
810 * Generate standard partitions automatically. If we do not
811 * have sufficient space we attempt to scale-down the size
812 * of the partitions within certain bounds.
818 for (perc = 100; perc > 0; perc -= 5) {
819 req = 0; /* reset for each loop */
820 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
834 if (label_chunk_info[here].type != PART_SLICE) {
835 msg = "You can only do this in a master partition (see top of screen)";
838 sz = space_free(label_chunk_info[here].c);
839 if (sz <= FS_MIN_SIZE) {
840 msg = "Not enough space to create an additional FreeBSD partition";
850 sprintf(osize, "%d", sz);
851 val = msgGetInput(osize,
852 "Please specify the partition size in blocks or append a trailing G for\n"
853 "gigabytes, M for megabytes, or C for cylinders.\n"
854 "%d blocks (%dMB) are free.",
856 if (!val || (size = strtol(val, &cp, 0)) <= 0) {
862 if (toupper(*cp) == 'M')
864 else if (toupper(*cp) == 'G')
866 else if (toupper(*cp) == 'C')
867 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
869 if (size <= FS_MIN_SIZE) {
870 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
874 type = get_partition_type();
875 if (type == PART_NONE) {
881 if (type == PART_FILESYSTEM) {
882 if ((p = get_mountpoint(NULL)) == NULL) {
887 else if (!strcmp(p->mountpoint, "/"))
888 flags |= CHUNK_IS_ROOT;
890 flags &= ~CHUNK_IS_ROOT;
895 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
896 msgConfirm("Warning: This is smaller than the recommended size for a\n"
897 "root partition. For a variety of reasons, root\n"
898 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
900 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
901 label_chunk_info[here].c,
903 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
906 msgConfirm("Unable to create the partition. Too big?");
913 * SRM requires that the root partition is at the
914 * begining of the disk and cannot boot otherwise.
915 * Warn Alpha users if they are about to shoot themselves in
916 * the foot in this way.
918 * Since partitions may not start precisely at offset 0 we
919 * check for a "close to 0" instead. :-(
921 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
922 msgConfirm("Your root partition `a' does not seem to be the first\n"
923 "partition. The Alpha's firmware can only boot from the\n"
924 "first partition. So it is unlikely that your current\n"
925 "disk layout will be bootable boot after installation.\n"
927 "Please allocate the root partition before allocating\n"
932 if (type != PART_SWAP) {
933 /* This is needed to tell the newfs -u about the size */
934 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
938 tmp->private_data = p;
939 tmp->private_free = safe_free;
940 if (variable_cmp(DISK_LABELLED, "written"))
941 variable_set2(DISK_LABELLED, "yes", 0);
942 record_label_chunks(devs, dev);
944 /* This is where we assign focus to new label so it shows. */
948 for (i = 0; label_chunk_info[i].c; ++i) {
949 if (label_chunk_info[i].c == tmp) {
954 if (label_focus == -1)
961 case 'R': /* recover space (delete w/ recover) */
963 * Delete the partition w/ space recovery.
965 rflags = DELCHUNK_RECOVER;
967 case 'D': /* delete */
968 if (label_chunk_info[here].type == PART_SLICE) {
969 msg = MSG_NOT_APPLICABLE;
972 else if (label_chunk_info[here].type == PART_FAT) {
973 msg = "Use the Disk Partition Editor to delete DOS partitions";
976 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
977 if (variable_cmp(DISK_LABELLED, "written"))
978 variable_set2(DISK_LABELLED, "yes", 0);
979 record_label_chunks(devs, dev);
982 case 'M': /* mount */
983 switch(label_chunk_info[here].type) {
985 msg = MSG_NOT_APPLICABLE;
989 msg = "You don't need to specify a mountpoint for a swap partition.";
993 case PART_FILESYSTEM:
994 oldp = label_chunk_info[here].c->private_data;
995 p = get_mountpoint(label_chunk_info[here].c);
999 if (label_chunk_info[here].type == PART_FAT
1000 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
1001 || !strcmp(p->mountpoint, "/var"))) {
1002 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
1003 strcpy(p->mountpoint, "/bogus");
1006 if (variable_cmp(DISK_LABELLED, "written"))
1007 variable_set2(DISK_LABELLED, "yes", 0);
1008 record_label_chunks(devs, dev);
1013 msgFatal("Bogus partition under cursor???");
1018 case 'N': /* Set newfs options */
1019 if (label_chunk_info[here].c->private_data &&
1020 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
1021 getNewfsCmd(label_chunk_info[here].c->private_data);
1023 msg = MSG_NOT_APPLICABLE;
1027 case 'S': /* Toggle soft updates flag */
1028 if (label_chunk_info[here].type == PART_FILESYSTEM) {
1029 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1031 pi->soft = !pi->soft;
1033 msg = MSG_NOT_APPLICABLE;
1036 msg = MSG_NOT_APPLICABLE;
1039 case 'T': /* Toggle newfs state */
1040 if ((label_chunk_info[here].type == PART_FILESYSTEM) &&
1041 (label_chunk_info[here].c->private_data)) {
1042 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1044 label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1046 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1048 label_chunk_info[here].c->private_data =
1049 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
1051 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
1053 label_chunk_info[here].c->private_free = safe_free;
1054 if (variable_cmp(DISK_LABELLED, "written"))
1055 variable_set2(DISK_LABELLED, "yes", 0);
1058 msg = MSG_NOT_APPLICABLE;
1063 if (!variable_cmp(DISK_LABELLED, "written")) {
1064 msgConfirm("You've already written out your changes -\n"
1065 "it's too late to undo!");
1067 else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1068 variable_unset(DISK_PARTITIONED);
1069 variable_unset(DISK_LABELLED);
1070 for (i = 0; devs[i]; i++) {
1073 if (!devs[i]->enabled)
1075 else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1076 Free_Disk(devs[i]->private);
1077 devs[i]->private = d;
1078 diskPartition(devs[i]);
1081 record_label_chunks(devs, dev);
1087 if (!variable_cmp(DISK_LABELLED, "written")) {
1088 msgConfirm("You've already written out your changes - if you\n"
1089 "wish to overwrite them, you'll have to restart\n"
1090 "sysinstall first.");
1092 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n"
1093 "installation. If you are installing FreeBSD for the first time\n"
1094 "then you should simply type Q when you're finished here and your\n"
1095 "changes will be committed in one batch automatically at the end of\n"
1096 "these questions.\n\n"
1097 "Are you absolutely sure you want to do this now?")) {
1098 variable_set2(DISK_LABELLED, "yes", 0);
1099 diskLabelCommit(NULL);
1105 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1106 "This is an entirely undocumented feature which you are not\n"
1107 "expected to understand!")) {
1113 DialogActive = FALSE;
1114 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1116 msgConfirm("Can't find any disk devices!");
1119 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1120 if (devs[i]->enabled)
1121 slice_wizard(((Disk *)devs[i]->private));
1123 if (variable_cmp(DISK_LABELLED, "written"))
1124 variable_set2(DISK_LABELLED, "yes", 0);
1125 DialogActive = TRUE;
1126 record_label_chunks(devs, dev);
1130 msg = "A most prudent choice!";
1133 case '\033': /* ESC */
1140 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1144 if (label_chunk_info[here].type == PART_SLICE)
1145 pslice_focus = here;
1150 return DITEM_SUCCESS;
1154 requested_part_size(char *varName, int nom, int def, int perc)
1159 if ((cp = variable_get(varName)) != NULL)
1162 sz = nom + (def - nom) * perc / 100;
1163 return(sz * ONE_MEG);
1167 * Attempt to auto-label the disk. 'perc' (0-100) scales
1168 * the size of the various partitions within appropriate
1169 * bounds (NOMINAL through DEFAULT sizes). The procedure
1170 * succeeds of NULL is returned. A non-null return message
1171 * is either a failure-status message (*req == 0), or
1172 * a confirmation requestor (*req == 1). *req is 0 on
1173 * entry to this call.
1175 * We autolabel the following partitions: /, swap, /var, /tmp, /usr,
1176 * and /home. /home receives any extra left over disk space.
1179 try_auto_label(Device **devs, Device *dev, int perc, int *req)
1182 struct chunk *root_chunk = NULL;
1183 struct chunk *swap_chunk = NULL;
1184 struct chunk *usr_chunk = NULL;
1185 struct chunk *var_chunk = NULL;
1186 struct chunk *tmp_chunk = NULL;
1187 struct chunk *home_chunk = NULL;
1189 unsigned int physmem;
1191 Chunk *rootdev, *swapdev, *usrdev, *vardev;
1192 Chunk *tmpdev, *homedev;
1195 sz = space_free(label_chunk_info[here].c);
1196 if (sz <= FS_MIN_SIZE)
1197 return("Not enough free space to create a new partition in the slice");
1199 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
1200 &vardev, &tmpdev, &homedev);
1202 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1204 root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1205 label_chunk_info[here].c, sz, part,
1206 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1209 msg = "Unable to create the root partition. Too big?";
1212 root_chunk->private_data = new_part("/", TRUE, root_chunk->size);
1213 root_chunk->private_free = safe_free;
1214 root_chunk->flags |= CHUNK_NEWFS;
1215 record_label_chunks(devs, dev);
1218 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1224 mib[1] = HW_PHYSMEM;
1225 size = sizeof physmem;
1226 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1227 def = 2 * (int)(physmem / 512);
1228 if (def < SWAP_MIN_SIZE * ONE_MEG)
1229 def = SWAP_MIN_SIZE * ONE_MEG;
1230 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1231 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1232 nom = (int)(physmem / 512) / 8;
1233 sz = nom + (def - nom) * perc / 100;
1235 swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1236 label_chunk_info[here].c, sz, part,
1237 FS_SWAP, CHUNK_AUTO_SIZE);
1240 msg = "Unable to create the swap partition. Too big?";
1243 swap_chunk->private_data = 0;
1244 swap_chunk->private_free = safe_free;
1245 record_label_chunks(devs, dev);
1248 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
1250 var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1251 label_chunk_info[here].c, sz, part,
1252 FS_BSDFFS, CHUNK_AUTO_SIZE);
1255 msg = "Not enough free space for /var - you will need to\n"
1256 "partition your disk manually with a custom install!";
1259 var_chunk->private_data = new_part("/var", TRUE, var_chunk->size);
1260 var_chunk->private_free = safe_free;
1261 var_chunk->flags |= CHUNK_NEWFS;
1262 record_label_chunks(devs, dev);
1264 if (!tmpdev && !variable_get(VAR_NO_TMP)) {
1265 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
1267 tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1268 label_chunk_info[here].c, sz, part,
1269 FS_BSDFFS, CHUNK_AUTO_SIZE);
1272 msg = "Not enough free space for /tmp - you will need to\n"
1273 "partition your disk manually with a custom install!";
1276 tmp_chunk->private_data = new_part("/tmp", TRUE, tmp_chunk->size);
1277 tmp_chunk->private_free = safe_free;
1278 tmp_chunk->flags |= CHUNK_NEWFS;
1279 record_label_chunks(devs, dev);
1281 if (!usrdev && !variable_get(VAR_NO_USR)) {
1282 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1284 sz = space_free(label_chunk_info[here].c);
1287 if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1289 msg = "Not enough free space for /usr - you will need to\n"
1290 "partition your disk manually with a custom install!";
1293 usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1294 label_chunk_info[here].c, sz, part,
1295 FS_BSDFFS, CHUNK_AUTO_SIZE);
1297 msg = "Unable to create the /usr partition. Not enough space?\n"
1298 "You will need to partition your disk manually with a custom install!";
1301 usr_chunk->private_data = new_part("/usr", TRUE, usr_chunk->size);
1302 usr_chunk->private_free = safe_free;
1303 usr_chunk->flags |= CHUNK_NEWFS;
1304 record_label_chunks(devs, dev);
1308 if (!homedev && !variable_get(VAR_NO_HOME)) {
1309 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1310 if (sz < space_free(label_chunk_info[here].c))
1311 sz = space_free(label_chunk_info[here].c);
1313 if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1315 msg = "Not enough free space for /home - you will need to\n"
1316 "partition your disk manually with a custom install!";
1320 home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1321 label_chunk_info[here].c, sz, part,
1322 FS_BSDFFS, CHUNK_AUTO_SIZE);
1324 msg = "Unable to create the /home partition. Not enough space?\n"
1325 "You will need to partition your disk manually with a custom install!";
1328 home_chunk->private_data = new_part("/home", TRUE, home_chunk->size);
1329 home_chunk->private_free = safe_free;
1330 home_chunk->flags |= CHUNK_NEWFS;
1331 record_label_chunks(devs, dev);
1336 /* At this point, we're reasonably "labelled" */
1337 if (variable_cmp(DISK_LABELLED, "written"))
1338 variable_set2(DISK_LABELLED, "yes", 0);
1343 Delete_Chunk(root_chunk->disk, root_chunk);
1345 Delete_Chunk(swap_chunk->disk, swap_chunk);
1347 Delete_Chunk(var_chunk->disk, var_chunk);
1349 Delete_Chunk(tmp_chunk->disk, tmp_chunk);
1351 Delete_Chunk(usr_chunk->disk, usr_chunk);
1353 Delete_Chunk(home_chunk->disk, home_chunk);
1354 record_label_chunks(devs, dev);
1360 diskLabelNonInteractive(Device *dev)
1370 status = DITEM_SUCCESS;
1371 cp = variable_get(VAR_DISK);
1373 msgConfirm("diskLabel: No disk selected - can't label automatically.");
1374 return DITEM_FAILURE;
1376 devs = deviceFind(cp, DEVICE_TYPE_DISK);
1378 msgConfirm("diskLabel: No disk device %s found!", cp);
1379 return DITEM_FAILURE;
1384 d = devs[0]->private;
1388 record_label_chunks(devs, dev);
1389 for (i = 0; label_chunk_info[i].c; i++) {
1390 Chunk *c1 = label_chunk_info[i].c;
1392 if (label_chunk_info[i].type == PART_SLICE) {
1397 snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1398 if ((cp = variable_get(name)) != NULL) {
1400 char typ[10], mpoint[50];
1402 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1403 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1404 status = DITEM_FAILURE;
1410 if (!strcmp(typ, "swap")) {
1412 strcpy(mpoint, "SWAP");
1415 type = PART_FILESYSTEM;
1416 if (!strcmp(mpoint, "/"))
1417 flags |= CHUNK_IS_ROOT;
1419 flags &= ~CHUNK_IS_ROOT;
1422 sz = space_free(c1);
1423 if (sz > space_free(c1)) {
1424 msgConfirm("Not enough free space to create partition: %s", mpoint);
1425 status = DITEM_FAILURE;
1428 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1429 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1430 msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1431 status = DITEM_FAILURE;
1435 tmp->private_data = new_part(mpoint, TRUE, sz);
1436 tmp->private_free = safe_free;
1437 ((PartInfo *)tmp->private_data)->soft = soft;
1438 status = DITEM_SUCCESS;
1444 /* No more matches, leave the loop */
1450 /* Must be something we can set a mountpoint for */
1451 cp = variable_get(c1->name);
1453 char mpoint[50], do_newfs[8];
1454 Boolean newfs = FALSE;
1457 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1458 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1459 status = DITEM_FAILURE;
1462 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1463 if (c1->private_data) {
1464 p = c1->private_data;
1466 strcpy(p->mountpoint, mpoint);
1469 c1->private_data = new_part(mpoint, newfs, 0);
1470 c1->private_free = safe_free;
1472 if (!strcmp(mpoint, "/"))
1473 c1->flags |= CHUNK_IS_ROOT;
1475 c1->flags &= ~CHUNK_IS_ROOT;
1479 if (status == DITEM_SUCCESS)
1480 variable_set2(DISK_LABELLED, "yes", 0);