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
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) {
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, u_long size)
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;
341 /* Get the mountpoint for a partition and save it away */
343 get_mountpoint(struct chunk *old)
348 if (old && old->private_data)
349 tmp = old->private_data;
352 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
357 free(old->private_data);
358 old->private_data = NULL;
363 /* Is it just the same value? */
364 if (tmp && !strcmp(tmp->mountpoint, val))
367 /* Did we use it already? */
368 if (check_conflict(val)) {
369 msgConfirm("You already have a mount point for %s assigned!", val);
375 msgConfirm("Mount point must start with a / character");
379 /* Is it going to be mounted on root? */
380 if (!strcmp(val, "/")) {
382 old->flags |= CHUNK_IS_ROOT;
385 old->flags &= ~CHUNK_IS_ROOT;
388 val = string_skipwhite(string_prune(val));
389 tmp = new_part(val, TRUE, 0);
391 old->private_data = tmp;
392 old->private_free = safe_free;
397 /* Get the type of the new partiton */
399 get_partition_type(void)
403 static unsigned char *fs_types[] = {
409 WINDOW *w = savescr();
411 i = dialog_menu("Please choose a partition type",
412 "If you want to use this partition for swap space, select Swap.\n"
413 "If you want to put a filesystem on it, choose FS.",
414 -1, -1, 2, 2, fs_types, selection, NULL, NULL);
417 if (!strcmp(selection, "FS"))
418 return PART_FILESYSTEM;
419 else if (!strcmp(selection, "Swap"))
425 /* If the user wants a special newfs command for this, set it */
427 getNewfsCmd(PartInfo *p)
431 val = msgGetInput(p->newfs_cmd,
432 "Please enter the newfs command and options you'd like to use in\n"
433 "creating this file system.");
435 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
438 #define MAX_MOUNT_NAME 9
440 #define PART_PART_COL 0
441 #define PART_MOUNT_COL 10
442 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
443 #define PART_NEWFS_COL (PART_SIZE_COL + 8)
446 #define TOTAL_AVAIL_LINES (10)
447 #define PSLICE_SHOWABLE (4)
450 /* stick this all up on the screen */
452 print_label_chunks(void)
454 int i, j, srow, prow, pcol;
457 int ChunkPartStartRow;
460 /********************************************************/
461 /*** These values are for controling screen resources ***/
462 /*** Each label line holds up to 2 labels, so beware! ***/
463 /*** strategy will be to try to always make sure the ***/
464 /*** highlighted label is in the active display area. ***/
465 /********************************************************/
466 int pslice_max, label_max;
467 int pslice_count, label_count, label_focus_found, pslice_focus_found;
470 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
473 /*** Count the number of parition slices ***/
475 for (i = 0; label_chunk_info[i].c ; i++) {
476 if (label_chunk_info[i].type == PART_SLICE)
479 pslice_max = pslice_count;
481 /*** 4 line max for partition slices ***/
482 if (pslice_max > PSLICE_SHOWABLE) {
483 pslice_max = PSLICE_SHOWABLE;
485 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
487 /*** View partition slices modulo pslice_max ***/
488 label_max = TOTAL_AVAIL_LINES - pslice_max;
490 for (i = 0; i < 2; i++) {
491 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
492 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
494 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
495 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
497 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
498 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
500 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
501 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
503 srow = CHUNK_SLICE_START_ROW;
507 /*** these variables indicate that the focused item is shown currently ***/
508 label_focus_found = 0;
509 pslice_focus_found = 0;
513 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " ");
514 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " ");
516 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
519 /*** wrefresh(ChunkWin); ***/
521 for (i = 0; label_chunk_info[i].c; i++) {
522 /* Is it a slice entry displayed at the top? */
523 if (label_chunk_info[i].type == PART_SLICE) {
524 /*** This causes the new pslice to replace the previous display ***/
525 /*** focus must remain on the most recently active pslice ***/
526 if (pslice_count == pslice_max) {
527 if (pslice_focus_found) {
528 /*** This is where we can mark the more following ***/
530 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
535 /*** this is where we set the more previous ***/
537 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
540 srow = CHUNK_SLICE_START_ROW;
544 sz = space_free(label_chunk_info[i].c);
546 attrset(ATTR_SELECTED);
547 if (i == pslice_focus)
548 pslice_focus_found = -1;
551 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
552 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
560 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
562 char onestr[PART_OFF], num[10], *mountpoint, newfs[10];
565 * We copy this into a blank-padded string so that it looks like
566 * a solid bar in reverse-video
568 memset(onestr, ' ', PART_OFF - 1);
569 onestr[PART_OFF - 1] = '\0';
571 /*** Track how many labels have been displayed ***/
572 if (label_count == ((label_max - 1 ) * 2)) {
573 if (label_focus_found) {
583 /* Go for two columns if we've written one full columns worth */
584 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
585 if (label_count == label_max - 1) {
589 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
590 /* If it's a filesystem, display the mountpoint */
591 if (label_chunk_info[i].c->private_data
592 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
593 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
594 else if (label_chunk_info[i].type == PART_SWAP)
597 mountpoint = "<none>";
599 /* Now display the newfs field */
600 if (label_chunk_info[i].type == PART_FAT)
601 strcpy(newfs, "DOS");
602 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
603 strcpy(newfs, "UFS");
605 ((PartInfo *)label_chunk_info[i].c->private_data)->soft ?
608 ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ?
611 else if (label_chunk_info[i].type == PART_SWAP)
612 strcpy(newfs, "SWAP");
615 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
616 onestr[PART_MOUNT_COL + j] = mountpoint[j];
617 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
618 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
619 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
620 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
621 if (i == label_focus) {
622 label_focus_found = -1;
623 wattrset(ChunkWin, A_BOLD);
626 wattrset(ChunkWin, ATTR_SELECTED);
628 /*** lazy man's way of expensively padding this string ***/
629 while (strlen(onestr) < 37)
632 mvwaddstr(ChunkWin, prow, pcol, onestr);
633 wattrset(ChunkWin, A_NORMAL);
640 /*** this will erase all the extra stuff ***/
641 memset(clrmsg, ' ', 37);
644 while (pslice_count < pslice_max) {
645 mvprintw(srow++, 0, clrmsg);
649 while (label_count < (2 * (label_max - 1))) {
650 mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
652 if (prow == (label_max - 1)) {
662 print_command_summary(void)
664 mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
665 mvprintw(18, 0, "C = Create D = Delete M = Mount pt.");
667 mvprintw(18, 47, "W = Write");
668 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates");
669 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge");
670 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
677 extern void print_label_chunks();
679 print_label_chunks();
685 * If there isn't a freebsd chunk already (i.e. there is no label),
689 maybe_dedicate(Disk* d)
693 for (c = d->chunks->part; c; c = c->next) {
694 if (c->type == freebsd)
699 msgDebug("dedicating disk");
707 diskLabel(Device *dev)
718 WINDOW *w = savescr();
724 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
726 msgConfirm("No disks found!");
728 return DITEM_FAILURE;
731 keypad(stdscr, TRUE);
733 for (i = 0; devs[i]; i++) {
734 maybe_dedicate((Disk*) devs[i]->private);
737 record_label_chunks(devs, dev);
742 int rflags = DELCHUNK_NORMAL;
744 print_label_chunks();
745 print_command_summary();
747 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
759 switch (toupper(key)) {
761 static char _msg[40];
763 case '\014': /* ^L */
767 case '\020': /* ^P */
773 while (label_chunk_info[here + 1].c)
777 case '\016': /* ^N */
782 if (label_chunk_info[here + 1].c)
793 while (label_chunk_info[here + 1].c)
799 systemDisplayHelp("partition");
804 if (label_chunk_info[here].type != PART_SLICE) {
805 msg = "You can only do this in a disk slice (at top of screen)";
809 * Generate standard partitions automatically. If we do not
810 * have sufficient space we attempt to scale-down the size
811 * of the partitions within certain bounds.
817 for (perc = 100; perc > 0; perc -= 5) {
818 req = 0; /* reset for each loop */
819 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
833 if (label_chunk_info[here].type != PART_SLICE) {
834 msg = "You can only do this in a master partition (see top of screen)";
837 sz = space_free(label_chunk_info[here].c);
838 if (sz <= FS_MIN_SIZE) {
839 msg = "Not enough space to create an additional FreeBSD partition";
849 sprintf(osize, "%d", sz);
850 val = msgGetInput(osize,
851 "Please specify the partition size in blocks or append a trailing G for\n"
852 "gigabytes, M for megabytes, or C for cylinders.\n"
853 "%d blocks (%dMB) are free.",
855 if (!val || (size = strtol(val, &cp, 0)) <= 0) {
861 if (toupper(*cp) == 'M')
863 else if (toupper(*cp) == 'G')
865 else if (toupper(*cp) == 'C')
866 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
868 if (size <= FS_MIN_SIZE) {
869 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
873 type = get_partition_type();
874 if (type == PART_NONE) {
880 if (type == PART_FILESYSTEM) {
881 if ((p = get_mountpoint(NULL)) == NULL) {
886 else if (!strcmp(p->mountpoint, "/"))
887 flags |= CHUNK_IS_ROOT;
889 flags &= ~CHUNK_IS_ROOT;
894 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
895 msgConfirm("Warning: This is smaller than the recommended size for a\n"
896 "root partition. For a variety of reasons, root\n"
897 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
899 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
900 label_chunk_info[here].c,
902 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
905 msgConfirm("Unable to create the partition. Too big?");
912 * SRM requires that the root partition is at the
913 * begining of the disk and cannot boot otherwise.
914 * Warn Alpha users if they are about to shoot themselves in
915 * the foot in this way.
917 * Since partitions may not start precisely at offset 0 we
918 * check for a "close to 0" instead. :-(
920 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
921 msgConfirm("Your root partition `a' does not seem to be the first\n"
922 "partition. The Alpha's firmware can only boot from the\n"
923 "first partition. So it is unlikely that your current\n"
924 "disk layout will be bootable boot after installation.\n"
926 "Please allocate the root partition before allocating\n"
931 if (type != PART_SWAP) {
932 /* This is needed to tell the newfs -u about the size */
933 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
937 tmp->private_data = p;
938 tmp->private_free = safe_free;
939 if (variable_cmp(DISK_LABELLED, "written"))
940 variable_set2(DISK_LABELLED, "yes", 0);
941 record_label_chunks(devs, dev);
943 /* This is where we assign focus to new label so it shows. */
947 for (i = 0; label_chunk_info[i].c; ++i) {
948 if (label_chunk_info[i].c == tmp) {
953 if (label_focus == -1)
960 case 'R': /* recover space (delete w/ recover) */
962 * Delete the partition w/ space recovery.
964 rflags = DELCHUNK_RECOVER;
966 case 'D': /* delete */
967 if (label_chunk_info[here].type == PART_SLICE) {
968 msg = MSG_NOT_APPLICABLE;
971 else if (label_chunk_info[here].type == PART_FAT) {
972 msg = "Use the Disk Partition Editor to delete DOS partitions";
975 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
976 if (variable_cmp(DISK_LABELLED, "written"))
977 variable_set2(DISK_LABELLED, "yes", 0);
978 record_label_chunks(devs, dev);
981 case 'M': /* mount */
982 switch(label_chunk_info[here].type) {
984 msg = MSG_NOT_APPLICABLE;
988 msg = "You don't need to specify a mountpoint for a swap partition.";
992 case PART_FILESYSTEM:
993 oldp = label_chunk_info[here].c->private_data;
994 p = get_mountpoint(label_chunk_info[here].c);
998 if (label_chunk_info[here].type == PART_FAT
999 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
1000 || !strcmp(p->mountpoint, "/var"))) {
1001 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
1002 strcpy(p->mountpoint, "/bogus");
1005 if (variable_cmp(DISK_LABELLED, "written"))
1006 variable_set2(DISK_LABELLED, "yes", 0);
1007 record_label_chunks(devs, dev);
1012 msgFatal("Bogus partition under cursor???");
1017 case 'N': /* Set newfs options */
1018 if (label_chunk_info[here].c->private_data &&
1019 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
1020 getNewfsCmd(label_chunk_info[here].c->private_data);
1022 msg = MSG_NOT_APPLICABLE;
1026 case 'S': /* Toggle soft updates flag */
1027 if (label_chunk_info[here].type == PART_FILESYSTEM) {
1028 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1030 pi->soft = !pi->soft;
1032 msg = MSG_NOT_APPLICABLE;
1035 msg = MSG_NOT_APPLICABLE;
1038 case 'T': /* Toggle newfs state */
1039 if ((label_chunk_info[here].type == PART_FILESYSTEM) &&
1040 (label_chunk_info[here].c->private_data)) {
1041 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1043 label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1045 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1047 label_chunk_info[here].c->private_data =
1048 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
1050 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
1052 label_chunk_info[here].c->private_free = safe_free;
1053 if (variable_cmp(DISK_LABELLED, "written"))
1054 variable_set2(DISK_LABELLED, "yes", 0);
1057 msg = MSG_NOT_APPLICABLE;
1062 if (!variable_cmp(DISK_LABELLED, "written")) {
1063 msgConfirm("You've already written out your changes -\n"
1064 "it's too late to undo!");
1066 else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1067 variable_unset(DISK_PARTITIONED);
1068 variable_unset(DISK_LABELLED);
1069 for (i = 0; devs[i]; i++) {
1072 if (!devs[i]->enabled)
1074 else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1075 Free_Disk(devs[i]->private);
1076 devs[i]->private = d;
1077 diskPartition(devs[i]);
1080 record_label_chunks(devs, dev);
1086 if (!variable_cmp(DISK_LABELLED, "written")) {
1087 msgConfirm("You've already written out your changes - if you\n"
1088 "wish to overwrite them, you'll have to restart\n"
1089 "sysinstall first.");
1091 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n"
1092 "installation. If you are installing FreeBSD for the first time\n"
1093 "then you should simply type Q when you're finished here and your\n"
1094 "changes will be committed in one batch automatically at the end of\n"
1095 "these questions.\n\n"
1096 "Are you absolutely sure you want to do this now?")) {
1097 variable_set2(DISK_LABELLED, "yes", 0);
1098 diskLabelCommit(NULL);
1104 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1105 "This is an entirely undocumented feature which you are not\n"
1106 "expected to understand!")) {
1112 DialogActive = FALSE;
1113 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1115 msgConfirm("Can't find any disk devices!");
1118 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1119 if (devs[i]->enabled)
1120 slice_wizard(((Disk *)devs[i]->private));
1122 if (variable_cmp(DISK_LABELLED, "written"))
1123 variable_set2(DISK_LABELLED, "yes", 0);
1124 DialogActive = TRUE;
1125 record_label_chunks(devs, dev);
1129 msg = "A most prudent choice!";
1132 case '\033': /* ESC */
1139 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1143 if (label_chunk_info[here].type == PART_SLICE)
1144 pslice_focus = here;
1149 return DITEM_SUCCESS;
1153 requested_part_size(char *varName, int nom, int def, int perc)
1158 if ((cp = variable_get(varName)) != NULL)
1161 sz = nom + (def - nom) * perc / 100;
1162 return(sz * ONE_MEG);
1166 * Attempt to auto-label the disk. 'perc' (0-100) scales
1167 * the size of the various partitions within appropriate
1168 * bounds (NOMINAL through DEFAULT sizes). The procedure
1169 * succeeds of NULL is returned. A non-null return message
1170 * is either a failure-status message (*req == 0), or
1171 * a confirmation requestor (*req == 1). *req is 0 on
1172 * entry to this call.
1174 * We autolabel the following partitions: /, swap, /var, /tmp, /usr,
1175 * and /home. /home receives any extra left over disk space.
1178 try_auto_label(Device **devs, Device *dev, int perc, int *req)
1181 struct chunk *root_chunk = NULL;
1182 struct chunk *swap_chunk = NULL;
1183 struct chunk *usr_chunk = NULL;
1184 struct chunk *var_chunk = NULL;
1185 struct chunk *tmp_chunk = NULL;
1186 struct chunk *home_chunk = NULL;
1188 unsigned int physmem;
1190 Chunk *rootdev, *swapdev, *usrdev, *vardev;
1191 Chunk *tmpdev, *homedev;
1194 sz = space_free(label_chunk_info[here].c);
1195 if (sz <= FS_MIN_SIZE)
1196 return("Not enough free space to create a new partition in the slice");
1198 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
1199 &vardev, &tmpdev, &homedev);
1201 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1203 root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1204 label_chunk_info[here].c, sz, part,
1205 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1208 msg = "Unable to create the root partition. Too big?";
1211 root_chunk->private_data = new_part("/", TRUE, root_chunk->size);
1212 root_chunk->private_free = safe_free;
1213 root_chunk->flags |= CHUNK_NEWFS;
1214 record_label_chunks(devs, dev);
1217 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1223 mib[1] = HW_PHYSMEM;
1224 size = sizeof physmem;
1225 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1226 def = 2 * (int)(physmem / 512);
1227 if (def < SWAP_MIN_SIZE * ONE_MEG)
1228 def = SWAP_MIN_SIZE * ONE_MEG;
1229 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1230 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1231 nom = (int)(physmem / 512) / 2;
1232 sz = nom + (def - nom) * perc / 100;
1234 swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1235 label_chunk_info[here].c, sz, part,
1236 FS_SWAP, CHUNK_AUTO_SIZE);
1239 msg = "Unable to create the swap partition. Too big?";
1242 swap_chunk->private_data = 0;
1243 swap_chunk->private_free = safe_free;
1244 record_label_chunks(devs, dev);
1247 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
1249 var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1250 label_chunk_info[here].c, sz, part,
1251 FS_BSDFFS, CHUNK_AUTO_SIZE);
1254 msg = "Not enough free space for /var - you will need to\n"
1255 "partition your disk manually with a custom install!";
1258 var_chunk->private_data = new_part("/var", TRUE, var_chunk->size);
1259 var_chunk->private_free = safe_free;
1260 var_chunk->flags |= CHUNK_NEWFS;
1261 record_label_chunks(devs, dev);
1263 if (!tmpdev && !variable_get(VAR_NO_TMP)) {
1264 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
1266 tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1267 label_chunk_info[here].c, sz, part,
1268 FS_BSDFFS, CHUNK_AUTO_SIZE);
1271 msg = "Not enough free space for /tmp - you will need to\n"
1272 "partition your disk manually with a custom install!";
1275 tmp_chunk->private_data = new_part("/tmp", TRUE, tmp_chunk->size);
1276 tmp_chunk->private_free = safe_free;
1277 tmp_chunk->flags |= CHUNK_NEWFS;
1278 record_label_chunks(devs, dev);
1280 if (!usrdev && !variable_get(VAR_NO_USR)) {
1281 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1283 sz = space_free(label_chunk_info[here].c);
1286 if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1288 msg = "Not enough free space for /usr - you will need to\n"
1289 "partition your disk manually with a custom install!";
1292 usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1293 label_chunk_info[here].c, sz, part,
1294 FS_BSDFFS, CHUNK_AUTO_SIZE);
1296 msg = "Unable to create the /usr partition. Not enough space?\n"
1297 "You will need to partition your disk manually with a custom install!";
1300 usr_chunk->private_data = new_part("/usr", TRUE, usr_chunk->size);
1301 usr_chunk->private_free = safe_free;
1302 usr_chunk->flags |= CHUNK_NEWFS;
1303 record_label_chunks(devs, dev);
1307 if (!homedev && !variable_get(VAR_NO_HOME)) {
1308 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1309 if (sz < space_free(label_chunk_info[here].c))
1310 sz = space_free(label_chunk_info[here].c);
1312 if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1314 msg = "Not enough free space for /home - you will need to\n"
1315 "partition your disk manually with a custom install!";
1319 home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1320 label_chunk_info[here].c, sz, part,
1321 FS_BSDFFS, CHUNK_AUTO_SIZE);
1323 msg = "Unable to create the /home partition. Not enough space?\n"
1324 "You will need to partition your disk manually with a custom install!";
1327 home_chunk->private_data = new_part("/home", TRUE, home_chunk->size);
1328 home_chunk->private_free = safe_free;
1329 home_chunk->flags |= CHUNK_NEWFS;
1330 record_label_chunks(devs, dev);
1335 /* At this point, we're reasonably "labelled" */
1336 if (variable_cmp(DISK_LABELLED, "written"))
1337 variable_set2(DISK_LABELLED, "yes", 0);
1342 Delete_Chunk(root_chunk->disk, root_chunk);
1344 Delete_Chunk(swap_chunk->disk, swap_chunk);
1346 Delete_Chunk(var_chunk->disk, var_chunk);
1348 Delete_Chunk(tmp_chunk->disk, tmp_chunk);
1350 Delete_Chunk(usr_chunk->disk, usr_chunk);
1352 Delete_Chunk(home_chunk->disk, home_chunk);
1353 record_label_chunks(devs, dev);
1359 diskLabelNonInteractive(Device *dev)
1369 status = DITEM_SUCCESS;
1370 cp = variable_get(VAR_DISK);
1372 msgConfirm("diskLabel: No disk selected - can't label automatically.");
1373 return DITEM_FAILURE;
1375 devs = deviceFind(cp, DEVICE_TYPE_DISK);
1377 msgConfirm("diskLabel: No disk device %s found!", cp);
1378 return DITEM_FAILURE;
1383 d = devs[0]->private;
1387 record_label_chunks(devs, dev);
1388 for (i = 0; label_chunk_info[i].c; i++) {
1389 Chunk *c1 = label_chunk_info[i].c;
1391 if (label_chunk_info[i].type == PART_SLICE) {
1396 snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1397 if ((cp = variable_get(name)) != NULL) {
1399 char typ[10], mpoint[50];
1401 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1402 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1403 status = DITEM_FAILURE;
1409 if (!strcmp(typ, "swap")) {
1411 strcpy(mpoint, "SWAP");
1414 type = PART_FILESYSTEM;
1415 if (!strcmp(mpoint, "/"))
1416 flags |= CHUNK_IS_ROOT;
1418 flags &= ~CHUNK_IS_ROOT;
1421 sz = space_free(c1);
1422 if (sz > space_free(c1)) {
1423 msgConfirm("Not enough free space to create partition: %s", mpoint);
1424 status = DITEM_FAILURE;
1427 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1428 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1429 msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1430 status = DITEM_FAILURE;
1434 tmp->private_data = new_part(mpoint, TRUE, sz);
1435 tmp->private_free = safe_free;
1436 ((PartInfo *)tmp->private_data)->soft = soft;
1437 status = DITEM_SUCCESS;
1443 /* No more matches, leave the loop */
1449 /* Must be something we can set a mountpoint for */
1450 cp = variable_get(c1->name);
1452 char mpoint[50], do_newfs[8];
1453 Boolean newfs = FALSE;
1456 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1457 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1458 status = DITEM_FAILURE;
1461 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1462 if (c1->private_data) {
1463 p = c1->private_data;
1465 strcpy(p->mountpoint, mpoint);
1468 c1->private_data = new_part(mpoint, newfs, 0);
1469 c1->private_free = safe_free;
1471 if (!strcmp(mpoint, "/"))
1472 c1->flags |= CHUNK_IS_ROOT;
1474 c1->flags &= ~CHUNK_IS_ROOT;
1478 if (status == DITEM_SUCCESS)
1479 variable_set2(DISK_LABELLED, "yes", 0);