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.
10 * Jordan Hubbard. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer,
17 * verbatim and that no modifications are made prior to this
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "sysinstall.h"
39 #include <sys/disklabel.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
43 #define AUTO_HOME 0 /* do not create /home automatically */
46 * Everything to do with editing the contents of disk labels.
49 /* A nice message we use a lot in the disklabel editor */
50 #define MSG_NOT_APPLICABLE "That option is not applicable here"
52 /* Where to start printing the freebsd slices */
53 #define CHUNK_SLICE_START_ROW 2
54 #define CHUNK_PART_START_ROW 11
56 /* The smallest filesystem we're willing to create */
57 #define FS_MIN_SIZE ONE_MEG
60 * Minimum partition sizes
62 #if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__)
63 #define ROOT_MIN_SIZE 40
65 #define ROOT_MIN_SIZE 30
67 #define SWAP_MIN_SIZE 32
68 #define USR_MIN_SIZE 80
69 #define VAR_MIN_SIZE 20
70 #define TMP_MIN_SIZE 20
71 #define HOME_MIN_SIZE 20
74 * Swap size limit for auto-partitioning (4G).
76 #define SWAP_AUTO_LIMIT_SIZE 4096
79 * Default partition sizes. If we do not have sufficient disk space
80 * for this configuration we scale things relative to the NOM vs DEFAULT
81 * sizes. If the disk is larger then /home will get any remaining space.
83 #define ROOT_DEFAULT_SIZE 128
84 #define USR_DEFAULT_SIZE 3072
85 #define VAR_DEFAULT_SIZE 256
86 #define TMP_DEFAULT_SIZE 256
87 #define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE
90 * Nominal partition sizes. These are used to scale the default sizes down
91 * when we have insufficient disk space. If this isn't sufficient we scale
92 * down using the MIN sizes instead.
94 #define ROOT_NOMINAL_SIZE 128
95 #define USR_NOMINAL_SIZE 512
96 #define VAR_NOMINAL_SIZE 64
97 #define TMP_NOMINAL_SIZE 64
98 #define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE
100 /* The bottom-most row we're allowed to scribble on */
101 #define CHUNK_ROW_MAX 16
104 /* All the chunks currently displayed on the screen */
108 } label_chunk_info[MAX_CHUNKS + 1];
111 /*** with this value we try to track the most recently added label ***/
112 static int label_focus = 0, pslice_focus = 0;
114 static int diskLabel(Device *dev);
115 static int diskLabelNonInteractive(Device *dev);
116 static char *try_auto_label(Device **devs, Device *dev, int perc, int *req);
119 labelHook(dialogMenuItem *selected)
121 Device **devs = NULL;
123 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
125 msgConfirm("Unable to find disk %s!", selected->prompt);
126 return DITEM_FAILURE;
128 /* Toggle enabled status? */
129 if (!devs[0]->enabled) {
130 devs[0]->enabled = TRUE;
134 devs[0]->enabled = FALSE;
135 return DITEM_SUCCESS;
139 labelCheck(dialogMenuItem *selected)
141 Device **devs = NULL;
143 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
144 if (!devs || devs[0]->enabled == FALSE)
150 diskLabelEditor(dialogMenuItem *self)
157 cnt = diskGetSelectCount(&devs);
159 msgConfirm("No disks found! Please verify that your disk controller is being\n"
160 "properly probed at boot time. See the Hardware Guide on the\n"
161 "Documentation menu for clues on diagnosing this type of problem.");
162 return DITEM_FAILURE;
165 /* Some are already selected */
166 if (variable_get(VAR_NONINTERACTIVE) &&
167 !variable_get(VAR_DISKINTERACTIVE))
168 i = diskLabelNonInteractive(NULL);
173 /* No disks are selected, fall-back case now */
174 cnt = deviceCount(devs);
176 devs[0]->enabled = TRUE;
177 if (variable_get(VAR_NONINTERACTIVE) &&
178 !variable_get(VAR_DISKINTERACTIVE))
179 i = diskLabelNonInteractive(devs[0]);
181 i = diskLabel(devs[0]);
184 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
186 msgConfirm("No devices suitable for installation found!\n\n"
187 "Please verify that your disk controller (and attached drives)\n"
188 "were detected properly. This can be done by pressing the\n"
189 "[Scroll Lock] key and using the Arrow keys to move back to\n"
190 "the boot messages. Press [Scroll Lock] again to return.");
194 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
199 if (DITEM_STATUS(i) != DITEM_FAILURE) {
200 if (variable_cmp(DISK_LABELLED, "written"))
201 variable_set2(DISK_LABELLED, "yes", 0);
207 diskLabelCommit(dialogMenuItem *self)
213 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
216 msgConfirm("You must assign disk labels before this option can be used.");
219 /* The routine will guard against redundant writes, just as this one does */
220 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
222 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
225 msgInfo("All filesystem information written successfully.");
226 variable_set2(DISK_LABELLED, "written", 0);
232 /* See if we're already using a desired partition name */
234 check_conflict(char *name)
238 for (i = 0; label_chunk_info[i].c; i++)
239 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
240 && label_chunk_info[i].c->private_data
241 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
246 /* How much space is in this FreeBSD slice? */
248 space_free(struct chunk *c)
253 for (c1 = c->part; c1; c1 = c1->next) {
254 if (c1->type != unused)
258 msgFatal("Partitions are larger than actual chunk??");
262 /* Snapshot the current situation into the displayed chunks structure */
264 record_label_chunks(Device **devs, Device *dev)
267 struct chunk *c1, *c2;
271 /* First buzz through and pick up the FreeBSD slices */
272 for (i = 0; devs[i]; i++) {
273 if ((dev && devs[i] != dev) || !devs[i]->enabled)
275 d = (Disk *)devs[i]->private;
277 msgFatal("No chunk list found for %s!", d->name);
279 /* Put the slice entries first */
280 for (c1 = d->chunks->part; c1; c1 = c1->next) {
281 if (c1->type == freebsd) {
282 label_chunk_info[j].type = PART_SLICE;
283 label_chunk_info[j].c = c1;
289 /* Now run through again and get the FreeBSD partition entries */
290 for (i = 0; devs[i]; i++) {
291 if (!devs[i]->enabled)
293 d = (Disk *)devs[i]->private;
294 /* Then buzz through and pick up the partitions */
295 for (c1 = d->chunks->part; c1; c1 = c1->next) {
296 if (c1->type == freebsd) {
297 for (c2 = c1->part; c2; c2 = c2->next) {
298 if (c2->type == part) {
299 if (c2->subtype == FS_SWAP)
300 label_chunk_info[j].type = PART_SWAP;
302 label_chunk_info[j].type = PART_FILESYSTEM;
303 label_chunk_info[j].c = c2;
308 else if (c1->type == fat || c1->type == efi) {
309 label_chunk_info[j].type = PART_FAT;
310 label_chunk_info[j].c = c1;
315 label_chunk_info[j].c = NULL;
317 here = j ? j - 1 : 0;
321 /* A new partition entry */
323 new_part(char *mpoint, Boolean newfs)
328 mpoint = "/change_me";
330 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
331 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
332 strcpy(ret->newfs_cmd, "newfs ");
333 strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS));
335 ret->soft = strcmp(mpoint, "/") ? 1 : 0;
339 #if defined(__ia64__)
341 new_efi_part(char *mpoint, Boolean newfs)
348 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
349 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
351 strcpy(ret->newfs_cmd, "newfs_msdos ");
358 /* Get the mountpoint for a partition and save it away */
360 get_mountpoint(struct chunk *old)
366 if (old && old->private_data)
367 tmp = old->private_data;
370 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
375 free(old->private_data);
376 old->private_data = NULL;
381 /* Is it just the same value? */
382 if (tmp && !strcmp(tmp->mountpoint, val))
385 /* Did we use it already? */
386 if (check_conflict(val)) {
387 msgConfirm("You already have a mount point for %s assigned!", val);
393 msgConfirm("Mount point must start with a / character");
397 /* Is it going to be mounted on root? */
398 if (!strcmp(val, "/")) {
400 old->flags |= CHUNK_IS_ROOT;
403 old->flags &= ~CHUNK_IS_ROOT;
410 val = string_skipwhite(string_prune(val));
411 tmp = new_part(val, newfs);
413 old->private_data = tmp;
414 old->private_free = safe_free;
419 /* Get the type of the new partiton */
421 get_partition_type(void)
425 static unsigned char *fs_types[] = {
431 WINDOW *w = savescr();
433 i = dialog_menu("Please choose a partition type",
434 "If you want to use this partition for swap space, select Swap.\n"
435 "If you want to put a filesystem on it, choose FS.",
436 -1, -1, 2, 2, fs_types, selection, NULL, NULL);
439 if (!strcmp(selection, "FS"))
440 return PART_FILESYSTEM;
441 else if (!strcmp(selection, "Swap"))
447 /* If the user wants a special newfs command for this, set it */
449 getNewfsCmd(PartInfo *p)
453 val = msgGetInput(p->newfs_cmd,
454 "Please enter the newfs command and options you'd like to use in\n"
455 "creating this file system.");
457 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
460 #define MAX_MOUNT_NAME 9
462 #define PART_PART_COL 0
463 #define PART_MOUNT_COL 10
464 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
465 #define PART_NEWFS_COL (PART_SIZE_COL + 8)
468 #define TOTAL_AVAIL_LINES (10)
469 #define PSLICE_SHOWABLE (4)
472 /* stick this all up on the screen */
474 print_label_chunks(void)
476 int i, j, srow, prow, pcol;
479 int ChunkPartStartRow;
482 /********************************************************/
483 /*** These values are for controling screen resources ***/
484 /*** Each label line holds up to 2 labels, so beware! ***/
485 /*** strategy will be to try to always make sure the ***/
486 /*** highlighted label is in the active display area. ***/
487 /********************************************************/
488 int pslice_max, label_max;
489 int pslice_count, label_count, label_focus_found, pslice_focus_found;
492 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
495 /*** Count the number of parition slices ***/
497 for (i = 0; label_chunk_info[i].c ; i++) {
498 if (label_chunk_info[i].type == PART_SLICE)
501 pslice_max = pslice_count;
503 /*** 4 line max for partition slices ***/
504 if (pslice_max > PSLICE_SHOWABLE) {
505 pslice_max = PSLICE_SHOWABLE;
507 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
509 /*** View partition slices modulo pslice_max ***/
510 label_max = TOTAL_AVAIL_LINES - pslice_max;
512 for (i = 0; i < 2; i++) {
513 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
514 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
516 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
517 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
519 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
520 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
522 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
523 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
525 srow = CHUNK_SLICE_START_ROW;
529 /*** these variables indicate that the focused item is shown currently ***/
530 label_focus_found = 0;
531 pslice_focus_found = 0;
535 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " ");
536 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " ");
538 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
541 /*** wrefresh(ChunkWin); ***/
543 for (i = 0; label_chunk_info[i].c; i++) {
544 /* Is it a slice entry displayed at the top? */
545 if (label_chunk_info[i].type == PART_SLICE) {
546 /*** This causes the new pslice to replace the previous display ***/
547 /*** focus must remain on the most recently active pslice ***/
548 if (pslice_count == pslice_max) {
549 if (pslice_focus_found) {
550 /*** This is where we can mark the more following ***/
552 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
557 /*** this is where we set the more previous ***/
559 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
562 srow = CHUNK_SLICE_START_ROW;
566 sz = space_free(label_chunk_info[i].c);
568 attrset(ATTR_SELECTED);
569 if (i == pslice_focus)
570 pslice_focus_found = -1;
573 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
574 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
582 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
584 char onestr[PART_OFF], num[10], *mountpoint, newfs[10];
587 * We copy this into a blank-padded string so that it looks like
588 * a solid bar in reverse-video
590 memset(onestr, ' ', PART_OFF - 1);
591 onestr[PART_OFF - 1] = '\0';
593 /*** Track how many labels have been displayed ***/
594 if (label_count == ((label_max - 1 ) * 2)) {
595 if (label_focus_found) {
605 /* Go for two columns if we've written one full columns worth */
606 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
607 if (label_count == label_max - 1) {
611 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
612 /* If it's a filesystem, display the mountpoint */
613 if (label_chunk_info[i].c->private_data
614 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
615 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
616 else if (label_chunk_info[i].type == PART_SWAP)
619 mountpoint = "<none>";
621 /* Now display the newfs field */
622 if (label_chunk_info[i].type == PART_FAT) {
623 strcpy(newfs, "DOS");
624 #if defined(__ia64__)
625 if (label_chunk_info[i].c->private_data &&
626 label_chunk_info[i].c->type == efi) {
628 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
629 strcat(newfs, pi->newfs ? " Y" : " N");
633 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
634 strcpy(newfs, "UFS");
636 ((PartInfo *)label_chunk_info[i].c->private_data)->soft ?
639 ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ?
642 else if (label_chunk_info[i].type == PART_SWAP)
643 strcpy(newfs, "SWAP");
646 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
647 onestr[PART_MOUNT_COL + j] = mountpoint[j];
648 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
649 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
650 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
651 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
652 if (i == label_focus) {
653 label_focus_found = -1;
654 wattrset(ChunkWin, A_BOLD);
657 wattrset(ChunkWin, ATTR_SELECTED);
659 /*** lazy man's way of expensively padding this string ***/
660 while (strlen(onestr) < 37)
663 mvwaddstr(ChunkWin, prow, pcol, onestr);
664 wattrset(ChunkWin, A_NORMAL);
671 /*** this will erase all the extra stuff ***/
672 memset(clrmsg, ' ', 37);
675 while (pslice_count < pslice_max) {
676 mvprintw(srow++, 0, clrmsg);
680 while (label_count < (2 * (label_max - 1))) {
681 mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
683 if (prow == (label_max - 1)) {
693 print_command_summary(void)
695 mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
696 mvprintw(18, 0, "C = Create D = Delete M = Mount pt.");
698 mvprintw(18, 47, "W = Write");
699 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates");
700 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge");
701 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
708 extern void print_label_chunks();
710 print_label_chunks();
714 diskLabel(Device *dev)
722 WINDOW *w = savescr();
728 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
730 msgConfirm("No disks found!");
732 return DITEM_FAILURE;
735 keypad(stdscr, TRUE);
736 record_label_chunks(devs, dev);
741 int rflags = DELCHUNK_NORMAL;
743 print_label_chunks();
744 print_command_summary();
746 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
758 switch (toupper(key)) {
760 static char _msg[40];
762 case '\014': /* ^L */
766 case '\020': /* ^P */
772 while (label_chunk_info[here + 1].c)
776 case '\016': /* ^N */
781 if (label_chunk_info[here + 1].c)
792 while (label_chunk_info[here + 1].c)
798 systemDisplayHelp("partition");
803 if (label_chunk_info[here].type != PART_SLICE) {
804 msg = "You can only do this in a disk slice (at top of screen)";
808 * Generate standard partitions automatically. If we do not
809 * have sufficient space we attempt to scale-down the size
810 * of the partitions within certain bounds.
816 for (perc = 100; perc > 0; perc -= 5) {
817 req = 0; /* reset for each loop */
818 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
832 if (label_chunk_info[here].type != PART_SLICE) {
833 msg = "You can only do this in a master partition (see top of screen)";
836 sz = space_free(label_chunk_info[here].c);
837 if (sz <= FS_MIN_SIZE) {
838 msg = "Not enough space to create an additional FreeBSD partition";
848 sprintf(osize, "%d", sz);
849 val = msgGetInput(osize,
850 "Please specify the partition size in blocks or append a trailing G for\n"
851 "gigabytes, M for megabytes, or C for cylinders.\n"
852 "%d blocks (%dMB) are free.",
854 if (!val || (size = strtol(val, &cp, 0)) <= 0) {
860 if (toupper(*cp) == 'M')
862 else if (toupper(*cp) == 'G')
864 else if (toupper(*cp) == 'C')
865 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
867 if (size <= FS_MIN_SIZE) {
868 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
872 type = get_partition_type();
873 if (type == PART_NONE) {
879 if (type == PART_FILESYSTEM) {
880 if ((p = get_mountpoint(NULL)) == NULL) {
885 else if (!strcmp(p->mountpoint, "/"))
886 flags |= CHUNK_IS_ROOT;
888 flags &= ~CHUNK_IS_ROOT;
893 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
894 msgConfirm("Warning: This is smaller than the recommended size for a\n"
895 "root partition. For a variety of reasons, root\n"
896 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
898 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
899 label_chunk_info[here].c,
901 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
904 msgConfirm("Unable to create the partition. Too big?");
911 * SRM requires that the root partition is at the
912 * begining of the disk and cannot boot otherwise.
913 * Warn Alpha users if they are about to shoot themselves in
914 * the foot in this way.
916 * Since partitions may not start precisely at offset 0 we
917 * check for a "close to 0" instead. :-(
919 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
920 msgConfirm("Your root partition `a' does not seem to be the first\n"
921 "partition. The Alpha's firmware can only boot from the\n"
922 "first partition. So it is unlikely that your current\n"
923 "disk layout will be bootable boot after installation.\n"
925 "Please allocate the root partition before allocating\n"
930 tmp->private_data = p;
931 tmp->private_free = safe_free;
932 if (variable_cmp(DISK_LABELLED, "written"))
933 variable_set2(DISK_LABELLED, "yes", 0);
934 record_label_chunks(devs, dev);
936 /* This is where we assign focus to new label so it shows. */
940 for (i = 0; label_chunk_info[i].c; ++i) {
941 if (label_chunk_info[i].c == tmp) {
946 if (label_focus == -1)
953 case 'R': /* recover space (delete w/ recover) */
955 * Delete the partition w/ space recovery.
957 rflags = DELCHUNK_RECOVER;
959 case 'D': /* delete */
960 if (label_chunk_info[here].type == PART_SLICE) {
961 msg = MSG_NOT_APPLICABLE;
964 else if (label_chunk_info[here].type == PART_FAT) {
965 msg = "Use the Disk Partition Editor to delete DOS partitions";
968 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
969 if (variable_cmp(DISK_LABELLED, "written"))
970 variable_set2(DISK_LABELLED, "yes", 0);
971 record_label_chunks(devs, dev);
974 case 'M': /* mount */
975 switch(label_chunk_info[here].type) {
977 msg = MSG_NOT_APPLICABLE;
981 msg = "You don't need to specify a mountpoint for a swap partition.";
985 case PART_FILESYSTEM:
986 oldp = label_chunk_info[here].c->private_data;
987 p = get_mountpoint(label_chunk_info[here].c);
991 if (label_chunk_info[here].type == PART_FAT
992 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
993 || !strcmp(p->mountpoint, "/var"))) {
994 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
995 strcpy(p->mountpoint, "/bogus");
998 if (variable_cmp(DISK_LABELLED, "written"))
999 variable_set2(DISK_LABELLED, "yes", 0);
1000 record_label_chunks(devs, dev);
1005 msgFatal("Bogus partition under cursor???");
1010 case 'N': /* Set newfs options */
1011 if (label_chunk_info[here].c->private_data &&
1012 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
1013 getNewfsCmd(label_chunk_info[here].c->private_data);
1015 msg = MSG_NOT_APPLICABLE;
1019 case 'S': /* Toggle soft updates flag */
1020 if (label_chunk_info[here].type == PART_FILESYSTEM) {
1021 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1023 pi->soft = !pi->soft;
1025 msg = MSG_NOT_APPLICABLE;
1028 msg = MSG_NOT_APPLICABLE;
1031 case 'T': /* Toggle newfs state */
1032 if ((label_chunk_info[here].type == PART_FILESYSTEM) &&
1033 (label_chunk_info[here].c->private_data)) {
1034 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1036 label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1038 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1040 label_chunk_info[here].c->private_data =
1041 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE);
1043 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
1045 label_chunk_info[here].c->private_free = safe_free;
1046 if (variable_cmp(DISK_LABELLED, "written"))
1047 variable_set2(DISK_LABELLED, "yes", 0);
1049 #if defined(__ia64__)
1050 else if (label_chunk_info[here].type == PART_FAT &&
1051 label_chunk_info[here].c->type == efi &&
1052 label_chunk_info[here].c->private_data) {
1053 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1055 label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1057 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1059 label_chunk_info[here].c->private_data =
1060 new_efi_part(pi->mountpoint, !pi->newfs);
1062 label_chunk_info[here].c->private_free = safe_free;
1063 if (variable_cmp(DISK_LABELLED, "written"))
1064 variable_set2(DISK_LABELLED, "yes", 0);
1068 msg = MSG_NOT_APPLICABLE;
1073 if (!variable_cmp(DISK_LABELLED, "written")) {
1074 msgConfirm("You've already written out your changes -\n"
1075 "it's too late to undo!");
1077 else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1078 variable_unset(DISK_PARTITIONED);
1079 variable_unset(DISK_LABELLED);
1080 for (i = 0; devs[i]; i++) {
1083 if (!devs[i]->enabled)
1085 else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1086 Free_Disk(devs[i]->private);
1087 devs[i]->private = d;
1089 diskPartition(devs[i]);
1093 record_label_chunks(devs, dev);
1099 if (!variable_cmp(DISK_LABELLED, "written")) {
1100 msgConfirm("You've already written out your changes - if you\n"
1101 "wish to overwrite them, you'll have to restart\n"
1102 "sysinstall first.");
1104 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n"
1105 "installation. If you are installing FreeBSD for the first time\n"
1106 "then you should simply type Q when you're finished here and your\n"
1107 "changes will be committed in one batch automatically at the end of\n"
1108 "these questions.\n\n"
1109 "Are you absolutely sure you want to do this now?")) {
1110 variable_set2(DISK_LABELLED, "yes", 0);
1111 diskLabelCommit(NULL);
1117 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1118 "This is an entirely undocumented feature which you are not\n"
1119 "expected to understand!")) {
1125 DialogActive = FALSE;
1126 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1128 msgConfirm("Can't find any disk devices!");
1131 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1132 if (devs[i]->enabled)
1133 slice_wizard(((Disk *)devs[i]->private));
1135 if (variable_cmp(DISK_LABELLED, "written"))
1136 variable_set2(DISK_LABELLED, "yes", 0);
1137 DialogActive = TRUE;
1138 record_label_chunks(devs, dev);
1142 msg = "A most prudent choice!";
1145 case '\033': /* ESC */
1152 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1156 if (label_chunk_info[here].type == PART_SLICE)
1157 pslice_focus = here;
1162 return DITEM_SUCCESS;
1166 requested_part_size(char *varName, int nom, int def, int perc)
1171 if ((cp = variable_get(varName)) != NULL)
1174 sz = nom + (def - nom) * perc / 100;
1175 return(sz * ONE_MEG);
1179 * Attempt to auto-label the disk. 'perc' (0-100) scales
1180 * the size of the various partitions within appropriate
1181 * bounds (NOMINAL through DEFAULT sizes). The procedure
1182 * succeeds of NULL is returned. A non-null return message
1183 * is either a failure-status message (*req == 0), or
1184 * a confirmation requestor (*req == 1). *req is 0 on
1185 * entry to this call.
1187 * We autolabel the following partitions: /, swap, /var, /tmp, /usr,
1188 * and /home. /home receives any extra left over disk space.
1191 try_auto_label(Device **devs, Device *dev, int perc, int *req)
1194 struct chunk *root_chunk = NULL;
1195 struct chunk *swap_chunk = NULL;
1196 struct chunk *usr_chunk = NULL;
1197 struct chunk *var_chunk = NULL;
1198 struct chunk *tmp_chunk = NULL;
1199 struct chunk *home_chunk = NULL;
1201 unsigned long physmem;
1203 Chunk *rootdev, *swapdev, *usrdev, *vardev;
1204 Chunk *tmpdev, *homedev;
1207 sz = space_free(label_chunk_info[here].c);
1208 if (sz <= FS_MIN_SIZE)
1209 return("Not enough free space to create a new partition in the slice");
1211 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
1212 &vardev, &tmpdev, &homedev);
1214 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1216 root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1217 label_chunk_info[here].c, sz, part,
1218 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1221 msg = "Unable to create the root partition. Too big?";
1224 root_chunk->private_data = new_part("/", TRUE);
1225 root_chunk->private_free = safe_free;
1226 root_chunk->flags |= CHUNK_NEWFS;
1227 record_label_chunks(devs, dev);
1230 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1236 mib[1] = HW_PHYSMEM;
1237 size = sizeof physmem;
1238 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1239 def = 2 * (int)(physmem / 512);
1240 if (def < SWAP_MIN_SIZE * ONE_MEG)
1241 def = SWAP_MIN_SIZE * ONE_MEG;
1242 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1243 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1244 nom = (int)(physmem / 512) / 2;
1245 sz = nom + (def - nom) * perc / 100;
1247 swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1248 label_chunk_info[here].c, sz, part,
1249 FS_SWAP, CHUNK_AUTO_SIZE);
1252 msg = "Unable to create the swap partition. Too big?";
1255 swap_chunk->private_data = 0;
1256 swap_chunk->private_free = safe_free;
1257 record_label_chunks(devs, dev);
1260 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
1262 var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1263 label_chunk_info[here].c, sz, part,
1264 FS_BSDFFS, CHUNK_AUTO_SIZE);
1267 msg = "Not enough free space for /var - you will need to\n"
1268 "partition your disk manually with a custom install!";
1271 var_chunk->private_data = new_part("/var", TRUE);
1272 var_chunk->private_free = safe_free;
1273 var_chunk->flags |= CHUNK_NEWFS;
1274 record_label_chunks(devs, dev);
1276 if (!tmpdev && !variable_get(VAR_NO_TMP)) {
1277 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
1279 tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1280 label_chunk_info[here].c, sz, part,
1281 FS_BSDFFS, CHUNK_AUTO_SIZE);
1284 msg = "Not enough free space for /tmp - you will need to\n"
1285 "partition your disk manually with a custom install!";
1288 tmp_chunk->private_data = new_part("/tmp", TRUE);
1289 tmp_chunk->private_free = safe_free;
1290 tmp_chunk->flags |= CHUNK_NEWFS;
1291 record_label_chunks(devs, dev);
1293 if (!usrdev && !variable_get(VAR_NO_USR)) {
1294 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1296 sz = space_free(label_chunk_info[here].c);
1299 if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1301 msg = "Not enough free space for /usr - you will need to\n"
1302 "partition your disk manually with a custom install!";
1305 usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1306 label_chunk_info[here].c, sz, part,
1307 FS_BSDFFS, CHUNK_AUTO_SIZE);
1309 msg = "Unable to create the /usr partition. Not enough space?\n"
1310 "You will need to partition your disk manually with a custom install!";
1313 usr_chunk->private_data = new_part("/usr", TRUE);
1314 usr_chunk->private_free = safe_free;
1315 usr_chunk->flags |= CHUNK_NEWFS;
1316 record_label_chunks(devs, dev);
1320 if (!homedev && !variable_get(VAR_NO_HOME)) {
1321 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1322 if (sz < space_free(label_chunk_info[here].c))
1323 sz = space_free(label_chunk_info[here].c);
1325 if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1327 msg = "Not enough free space for /home - you will need to\n"
1328 "partition your disk manually with a custom install!";
1332 home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1333 label_chunk_info[here].c, sz, part,
1334 FS_BSDFFS, CHUNK_AUTO_SIZE);
1336 msg = "Unable to create the /home partition. Not enough space?\n"
1337 "You will need to partition your disk manually with a custom install!";
1340 home_chunk->private_data = new_part("/home", TRUE);
1341 home_chunk->private_free = safe_free;
1342 home_chunk->flags |= CHUNK_NEWFS;
1343 record_label_chunks(devs, dev);
1348 /* At this point, we're reasonably "labelled" */
1349 if (variable_cmp(DISK_LABELLED, "written"))
1350 variable_set2(DISK_LABELLED, "yes", 0);
1355 Delete_Chunk(root_chunk->disk, root_chunk);
1357 Delete_Chunk(swap_chunk->disk, swap_chunk);
1359 Delete_Chunk(var_chunk->disk, var_chunk);
1361 Delete_Chunk(tmp_chunk->disk, tmp_chunk);
1363 Delete_Chunk(usr_chunk->disk, usr_chunk);
1365 Delete_Chunk(home_chunk->disk, home_chunk);
1366 record_label_chunks(devs, dev);
1372 diskLabelNonInteractive(Device *dev)
1382 status = DITEM_SUCCESS;
1383 cp = variable_get(VAR_DISK);
1385 msgConfirm("diskLabel: No disk selected - can't label automatically.");
1386 return DITEM_FAILURE;
1388 devs = deviceFind(cp, DEVICE_TYPE_DISK);
1390 msgConfirm("diskLabel: No disk device %s found!", cp);
1391 return DITEM_FAILURE;
1396 d = devs[0]->private;
1397 record_label_chunks(devs, dev);
1398 for (i = 0; label_chunk_info[i].c; i++) {
1399 Chunk *c1 = label_chunk_info[i].c;
1401 if (label_chunk_info[i].type == PART_SLICE) {
1403 char typ[10], mpoint[50];
1406 for (entries = 1;; entries++) {
1408 snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1409 if ((cp = variable_get(name)) == NULL)
1411 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1412 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1413 status = DITEM_FAILURE;
1419 if (!strcmp(typ, "swap")) {
1421 strcpy(mpoint, "SWAP");
1423 type = PART_FILESYSTEM;
1424 if (!strcmp(mpoint, "/"))
1425 flags |= CHUNK_IS_ROOT;
1428 sz = space_free(c1);
1429 if (sz > space_free(c1)) {
1430 msgConfirm("Not enough free space to create partition: %s", mpoint);
1431 status = DITEM_FAILURE;
1434 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1435 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1436 msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1437 status = DITEM_FAILURE;
1440 tmp->private_data = new_part(mpoint, TRUE);
1441 tmp->private_free = safe_free;
1442 ((PartInfo *)tmp->private_data)->soft = soft;
1447 /* Must be something we can set a mountpoint for */
1448 cp = variable_get(c1->name);
1450 char mpoint[50], do_newfs[8];
1451 Boolean newfs = FALSE;
1454 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1455 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1456 status = DITEM_FAILURE;
1459 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1460 if (c1->private_data) {
1461 p = c1->private_data;
1463 strcpy(p->mountpoint, mpoint);
1466 c1->private_data = new_part(mpoint, newfs);
1467 c1->private_free = safe_free;
1469 if (!strcmp(mpoint, "/"))
1470 c1->flags |= CHUNK_IS_ROOT;
1472 c1->flags &= ~CHUNK_IS_ROOT;
1476 if (status == DITEM_SUCCESS)
1477 variable_set2(DISK_LABELLED, "yes", 0);