]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sysinstall/label.c
This commit was generated by cvs2svn to compensate for changes in r153872,
[FreeBSD/FreeBSD.git] / usr.sbin / sysinstall / label.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last program in the `sysinstall' line - the next
5  * generation being essentially a complete rewrite.
6  *
7  * $FreeBSD$
8  *
9  * Copyright (c) 1995
10  *      Jordan Hubbard.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
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
18  *    point in the file.
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.
22  *
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
33  * SUCH DAMAGE.
34  *
35  */
36
37 #include "sysinstall.h"
38 #include <ctype.h>
39 #include <inttypes.h>
40 #include <libdisk.h>
41 #include <sys/disklabel.h>
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44
45 #define AUTO_HOME       0       /* do not create /home automatically */
46
47 /*
48  * Everything to do with editing the contents of disk labels.
49  */
50
51 /* A nice message we use a lot in the disklabel editor */
52 #define MSG_NOT_APPLICABLE      "That option is not applicable here"
53
54 /* Where to start printing the freebsd slices */
55 #define CHUNK_SLICE_START_ROW           2
56 #define CHUNK_PART_START_ROW            11
57
58 /* The smallest filesystem we're willing to create */
59 #define FS_MIN_SIZE                     ONE_MEG
60
61 /*
62  * Minimum partition sizes
63  */
64 #if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) || defined(__amd64__)
65 #define ROOT_MIN_SIZE                   128
66 #else
67 #define ROOT_MIN_SIZE                   118
68 #endif
69 #define SWAP_MIN_SIZE                   32
70 #define USR_MIN_SIZE                    80
71 #define VAR_MIN_SIZE                    20
72 #define TMP_MIN_SIZE                    20
73 #define HOME_MIN_SIZE                   20
74
75 /*
76  * Swap size limit for auto-partitioning (4G).
77  */
78 #define SWAP_AUTO_LIMIT_SIZE            4096
79
80 /*
81  * Default partition sizes.  If we do not have sufficient disk space
82  * for this configuration we scale things relative to the NOM vs DEFAULT
83  * sizes.  If the disk is larger then /home will get any remaining space.
84  */
85 #define ROOT_DEFAULT_SIZE               512
86 #define USR_DEFAULT_SIZE                8192
87 #define VAR_DEFAULT_SIZE                1024
88 #define TMP_DEFAULT_SIZE                512
89 #define HOME_DEFAULT_SIZE               USR_DEFAULT_SIZE
90
91 /*
92  * Nominal partition sizes.  These are used to scale the default sizes down
93  * when we have insufficient disk space.  If this isn't sufficient we scale
94  * down using the MIN sizes instead.
95  */
96 #define ROOT_NOMINAL_SIZE               256
97 #define USR_NOMINAL_SIZE                1536
98 #define VAR_NOMINAL_SIZE                128
99 #define TMP_NOMINAL_SIZE                128
100 #define HOME_NOMINAL_SIZE               USR_NOMINAL_SIZE
101
102 /* The bottom-most row we're allowed to scribble on */
103 #define CHUNK_ROW_MAX                   16
104
105
106 /* All the chunks currently displayed on the screen */
107 static struct {
108     struct chunk *c;
109     PartType type;
110 } label_chunk_info[MAX_CHUNKS + 1];
111 static int here;
112
113 /*** with this value we try to track the most recently added label ***/
114 static int label_focus = 0, pslice_focus = 0;
115
116 static int diskLabel(Device *dev);
117 static int diskLabelNonInteractive(Device *dev);
118 static char *try_auto_label(Device **devs, Device *dev, int perc, int *req);
119
120 static int
121 labelHook(dialogMenuItem *selected)
122 {
123     Device **devs = NULL;
124
125     devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
126     if (!devs) {
127         msgConfirm("Unable to find disk %s!", selected->prompt);
128         return DITEM_FAILURE;
129     }
130     /* Toggle enabled status? */
131     if (!devs[0]->enabled) {
132         devs[0]->enabled = TRUE;
133         diskLabel(devs[0]);
134     }
135     else
136         devs[0]->enabled = FALSE;
137     return DITEM_SUCCESS;
138 }
139
140 static int
141 labelCheck(dialogMenuItem *selected)
142 {
143     Device **devs = NULL;
144
145     devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
146     if (!devs || devs[0]->enabled == FALSE)
147         return FALSE;
148     return TRUE;
149 }
150
151 int
152 diskLabelEditor(dialogMenuItem *self)
153 {
154     DMenu *menu;
155     Device **devs;
156     int i, cnt;
157
158     i = 0;
159     cnt = diskGetSelectCount(&devs);
160     if (cnt == -1) {
161         msgConfirm("No disks found!  Please verify that your disk controller is being\n"
162                    "properly probed at boot time.  See the Hardware Guide on the\n"
163                    "Documentation menu for clues on diagnosing this type of problem.");
164         return DITEM_FAILURE;
165     }
166     else if (cnt) {
167         /* Some are already selected */
168         if (variable_get(VAR_NONINTERACTIVE) &&
169           !variable_get(VAR_DISKINTERACTIVE))
170             i = diskLabelNonInteractive(NULL);
171         else
172             i = diskLabel(NULL);
173     }
174     else {
175         /* No disks are selected, fall-back case now */
176         cnt = deviceCount(devs);
177         if (cnt == 1) {
178             devs[0]->enabled = TRUE;
179             if (variable_get(VAR_NONINTERACTIVE) &&
180               !variable_get(VAR_DISKINTERACTIVE))
181                 i = diskLabelNonInteractive(devs[0]);
182             else
183                 i = diskLabel(devs[0]);
184         }
185         else {
186             menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
187             if (!menu) {
188                 msgConfirm("No devices suitable for installation found!\n\n"
189                            "Please verify that your disk controller (and attached drives)\n"
190                            "were detected properly.  This can be done by pressing the\n"
191                            "[Scroll Lock] key and using the Arrow keys to move back to\n"
192                            "the boot messages.  Press [Scroll Lock] again to return.");
193                 i = DITEM_FAILURE;
194             }
195             else {
196                 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
197                 free(menu);
198             }
199         }
200     }
201     if (DITEM_STATUS(i) != DITEM_FAILURE) {
202         if (variable_cmp(DISK_LABELLED, "written"))
203             variable_set2(DISK_LABELLED, "yes", 0);
204     }
205     return i;
206 }
207
208 int
209 diskLabelCommit(dialogMenuItem *self)
210 {
211     char *cp;
212     int i;
213
214     /* Already done? */
215     if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
216         i = DITEM_SUCCESS;
217     else if (!cp) {
218         msgConfirm("You must assign disk labels before this option can be used.");
219         i = DITEM_FAILURE;
220     }
221     /* The routine will guard against redundant writes, just as this one does */
222     else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
223         i = DITEM_FAILURE;
224     else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
225         i = DITEM_FAILURE;
226     else {
227         msgInfo("All filesystem information written successfully.");
228         variable_set2(DISK_LABELLED, "written", 0);
229         i = DITEM_SUCCESS;
230     }
231     return i;
232 }
233
234 /* See if we're already using a desired partition name */
235 static Boolean
236 check_conflict(char *name)
237 {
238     int i;
239
240     for (i = 0; label_chunk_info[i].c; i++)
241         if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT
242             || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data
243             && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
244             return TRUE;
245     return FALSE;
246 }
247
248 /* How much space is in this FreeBSD slice? */
249 static daddr_t
250 space_free(struct chunk *c)
251 {
252     struct chunk *c1;
253     daddr_t sz = c->size;
254
255     for (c1 = c->part; c1; c1 = c1->next) {
256         if (c1->type != unused)
257             sz -= c1->size;
258     }
259     if (sz < 0)
260         msgFatal("Partitions are larger than actual chunk??");
261     return sz;
262 }
263
264 /* Snapshot the current situation into the displayed chunks structure */
265 static void
266 record_label_chunks(Device **devs, Device *dev)
267 {
268     int i, j, p;
269     struct chunk *c1, *c2;
270     Disk *d;
271
272     j = p = 0;
273     /* First buzz through and pick up the FreeBSD slices */
274     for (i = 0; devs[i]; i++) {
275         if ((dev && devs[i] != dev) || !devs[i]->enabled)
276             continue;
277         d = (Disk *)devs[i]->private;
278         if (!d->chunks)
279             msgFatal("No chunk list found for %s!", d->name);
280
281 #ifdef __ia64__
282         label_chunk_info[j].type = PART_SLICE;
283         label_chunk_info[j].c = d->chunks;
284         j++;
285 #endif
286
287         /* Put the slice entries first */
288         for (c1 = d->chunks->part; c1; c1 = c1->next) {
289             if (c1->type == freebsd) {
290                 label_chunk_info[j].type = PART_SLICE;
291                 label_chunk_info[j].c = c1;
292                 ++j;
293             }
294 #ifdef __powerpc__
295             if (c1->type == apple) {
296                 label_chunk_info[j].type = PART_SLICE;
297                 label_chunk_info[j].c = c1;
298                 ++j;
299             }
300 #endif
301         }
302     }
303
304     /* Now run through again and get the FreeBSD partition entries */
305     for (i = 0; devs[i]; i++) {
306         if (!devs[i]->enabled)
307             continue;
308         d = (Disk *)devs[i]->private;
309         /* Then buzz through and pick up the partitions */
310         for (c1 = d->chunks->part; c1; c1 = c1->next) {
311             if (c1->type == freebsd) {
312                 for (c2 = c1->part; c2; c2 = c2->next) {
313                     if (c2->type == part) {
314                         if (c2->subtype == FS_SWAP)
315                             label_chunk_info[j].type = PART_SWAP;
316                         else
317                             label_chunk_info[j].type = PART_FILESYSTEM;
318                         label_chunk_info[j].c = c2;
319                         ++j;
320                     }
321                 }
322             }
323             else if (c1->type == fat) {
324                 label_chunk_info[j].type = PART_FAT;
325                 label_chunk_info[j].c = c1;
326                 ++j;
327             }
328 #ifdef __ia64__
329             else if (c1->type == efi) {
330                 label_chunk_info[j].type = PART_EFI;
331                 label_chunk_info[j].c = c1;
332                 ++j;
333             }
334             else if (c1->type == part) {
335                 if (c1->subtype == FS_SWAP)
336                     label_chunk_info[j].type = PART_SWAP;
337                 else
338                     label_chunk_info[j].type = PART_FILESYSTEM;
339                 label_chunk_info[j].c = c1;
340                 ++j;
341             }
342 #endif
343 #ifdef __powerpc__
344             else if (c1->type == apple) {
345                 for (c2 = c1->part; c2; c2 = c2->next) {
346                     if (c2->type == part) {
347                         if (c2->subtype == FS_SWAP)
348                             label_chunk_info[j].type = PART_SWAP;
349                         else
350                             label_chunk_info[j].type = PART_FILESYSTEM;
351                         label_chunk_info[j].c = c2;
352                         ++j;
353                     }
354                 }
355             }
356 #endif
357         }
358     }
359     label_chunk_info[j].c = NULL;
360     if (here >= j) {
361         here = j  ? j - 1 : 0;
362     }
363 }
364
365 /* A new partition entry */
366 static PartInfo *
367 new_part(PartType type, char *mpoint, Boolean newfs)
368 {
369     PartInfo *pi;
370
371     if (!mpoint)
372         mpoint = (type == PART_EFI) ? "/efi" : "/change_me";
373
374     pi = (PartInfo *)safe_malloc(sizeof(PartInfo));
375     sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX);
376
377     pi->do_newfs = newfs;
378
379     if (type == PART_EFI) {
380         pi->newfs_type = NEWFS_MSDOS;
381     } else {
382         pi->newfs_type = NEWFS_UFS;
383         strcpy(pi->newfs_data.newfs_ufs.user_options, "");
384         pi->newfs_data.newfs_ufs.acls = FALSE;
385         pi->newfs_data.newfs_ufs.multilabel = FALSE;
386         pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/");
387 #ifdef PC98
388         pi->newfs_data.newfs_ufs.ufs1 = TRUE;
389 #else
390         pi->newfs_data.newfs_ufs.ufs1 = FALSE;
391 #endif
392     }
393
394     return pi;
395 }
396
397 /* Get the mountpoint for a partition and save it away */
398 static PartInfo *
399 get_mountpoint(PartType type, struct chunk *old)
400 {
401     char *val;
402     PartInfo *tmp;
403     Boolean newfs;
404
405     if (old && old->private_data)
406         tmp = old->private_data;
407     else
408         tmp = NULL;
409     val = (tmp != NULL) ? tmp->mountpoint : (type == PART_EFI) ? "/efi" : NULL;
410     val = msgGetInput(val, "Please specify a mount point for the partition");
411     if (!val || !*val) {
412         if (!old)
413             return NULL;
414         else {
415             free(old->private_data);
416             old->private_data = NULL;
417         }
418         return NULL;
419     }
420
421     /* Is it just the same value? */
422     if (tmp && !strcmp(tmp->mountpoint, val))
423         return NULL;
424
425     /* Did we use it already? */
426     if (check_conflict(val)) {
427         msgConfirm("You already have a mount point for %s assigned!", val);
428         return NULL;
429     }
430
431     /* Is it bogus? */
432     if (*val != '/') {
433         msgConfirm("Mount point must start with a / character");
434         return NULL;
435     }
436
437     /* Is it going to be mounted on root? */
438     if (!strcmp(val, "/")) {
439         if (old)
440             old->flags |= CHUNK_IS_ROOT;
441     }
442     else if (old)
443         old->flags &= ~CHUNK_IS_ROOT;
444
445     newfs = TRUE;
446     if (tmp) {
447         newfs = tmp->do_newfs;
448         safe_free(tmp);
449     }
450     val = string_skipwhite(string_prune(val));
451     tmp = new_part(type, val, newfs);
452     if (old) {
453         old->private_data = tmp;
454         old->private_free = safe_free;
455     }
456     return tmp;
457 }
458
459 /* Get the type of the new partiton */
460 static PartType
461 get_partition_type(void)
462 {
463     char selection[20];
464     int i;
465     static unsigned char *fs_types[] = {
466 #ifdef __ia64__
467         "EFI",  "An EFI system partition",
468 #endif
469         "FS",   "A file system",
470         "Swap", "A swap partition.",
471     };
472     WINDOW *w = savescr();
473
474     i = dialog_menu("Please choose a partition type",
475         "If you want to use this partition for swap space, select Swap.\n"
476         "If you want to put a filesystem on it, choose FS.",
477         -1, -1,
478 #ifdef __ia64__
479         3, 3,
480 #else
481         2, 2,
482 #endif
483         fs_types, selection, NULL, NULL);
484     restorescr(w);
485     if (!i) {
486 #ifdef __ia64__
487         if (!strcmp(selection, "EFI"))
488             return PART_EFI;
489 #endif
490         if (!strcmp(selection, "FS"))
491             return PART_FILESYSTEM;
492         else if (!strcmp(selection, "Swap"))
493             return PART_SWAP;
494     }
495     return PART_NONE;
496 }
497
498 /* If the user wants a special newfs command for this, set it */
499 static void
500 getNewfsCmd(PartInfo *p)
501 {
502     char buffer[NEWFS_CMD_ARGS_MAX];
503     char *val;
504
505     switch (p->newfs_type) {
506     case NEWFS_UFS:
507         snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s",
508             NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ?  "-U" : "",
509             p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2",
510             p->newfs_data.newfs_ufs.user_options);
511         break;
512     case NEWFS_MSDOS:
513         snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD);
514         break;
515     case NEWFS_CUSTOM:
516         strcpy(buffer, p->newfs_data.newfs_custom.command);
517         break;
518     }
519
520     val = msgGetInput(buffer,
521         "Please enter the newfs command and options you'd like to use in\n"
522         "creating this file system.");
523     if (val != NULL) {
524         p->newfs_type = NEWFS_CUSTOM;
525         strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX);
526     }
527 }
528
529 static void
530 getNewfsOptionalArguments(PartInfo *p)
531 {
532         char buffer[NEWFS_CMD_ARGS_MAX];
533         char *val;
534
535         /* Must be UFS, per argument checking in I/O routines. */
536
537         strlcpy(buffer,  p->newfs_data.newfs_ufs.user_options,
538             NEWFS_CMD_ARGS_MAX);
539         val = msgGetInput(buffer,
540             "Please enter any additional UFS newfs options you'd like to\n"
541             "use in creating this file system.");
542         if (val != NULL)
543                 strlcpy(p->newfs_data.newfs_ufs.user_options, val,
544                     NEWFS_CMD_ARGS_MAX);
545 }
546
547 #define MAX_MOUNT_NAME  9
548
549 #define PART_PART_COL   0
550 #define PART_MOUNT_COL  10
551 #define PART_SIZE_COL   (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
552 #define PART_NEWFS_COL  (PART_SIZE_COL + 8)
553 #define PART_OFF        38
554
555 #define TOTAL_AVAIL_LINES       (10)
556 #define PSLICE_SHOWABLE          (4)
557
558
559 /* stick this all up on the screen */
560 static void
561 print_label_chunks(void)
562 {
563     int  i, j, srow, prow, pcol;
564     daddr_t sz;
565     char clrmsg[80];
566     int ChunkPartStartRow;
567     WINDOW *ChunkWin;
568
569     /********************************************************/
570     /*** These values are for controling screen resources ***/
571     /*** Each label line holds up to 2 labels, so beware! ***/
572     /*** strategy will be to try to always make sure the  ***/
573     /*** highlighted label is in the active display area. ***/
574     /********************************************************/
575     int  pslice_max, label_max;
576     int  pslice_count, label_count, label_focus_found, pslice_focus_found;
577
578     attrset(A_REVERSE);
579     mvaddstr(0, 25, "FreeBSD Disklabel Editor");
580     attrset(A_NORMAL);
581
582     /*** Count the number of parition slices ***/
583     pslice_count = 0;
584     for (i = 0; label_chunk_info[i].c ; i++) {
585         if (label_chunk_info[i].type == PART_SLICE)
586             ++pslice_count;
587     }
588     pslice_max = pslice_count;
589
590     /*** 4 line max for partition slices ***/
591     if (pslice_max > PSLICE_SHOWABLE) {
592         pslice_max = PSLICE_SHOWABLE;
593     }
594     ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
595     
596     /*** View partition slices modulo pslice_max ***/
597     label_max = TOTAL_AVAIL_LINES - pslice_max;
598
599     for (i = 0; i < 2; i++) {
600         mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
601         mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
602
603         mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
604         mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
605
606         mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
607         mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
608
609         mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
610         mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
611     }
612     srow = CHUNK_SLICE_START_ROW;
613     prow = 0;
614     pcol = 0;
615
616     /*** these variables indicate that the focused item is shown currently ***/
617     label_focus_found = 0;
618     pslice_focus_found = 0;
619    
620     label_count = 0;
621     pslice_count = 0;
622     mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
623     mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
624
625     ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
626
627     wclear(ChunkWin);
628     /*** wrefresh(ChunkWin); ***/
629
630     for (i = 0; label_chunk_info[i].c; i++) {
631         /* Is it a slice entry displayed at the top? */
632         if (label_chunk_info[i].type == PART_SLICE) {
633             /*** This causes the new pslice to replace the previous display ***/
634             /*** focus must remain on the most recently active pslice       ***/
635             if (pslice_count == pslice_max) {
636                 if (pslice_focus_found) {
637                     /*** This is where we can mark the more following ***/
638                     attrset(A_BOLD);
639                     mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
640                     attrset(A_NORMAL);
641                     continue;
642                 }
643                 else {
644                     /*** this is where we set the more previous ***/
645                     attrset(A_BOLD);
646                     mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
647                     attrset(A_NORMAL);
648                     pslice_count = 0;
649                     srow = CHUNK_SLICE_START_ROW;
650                 }
651             }
652
653             sz = space_free(label_chunk_info[i].c);
654             if (i == here)
655                 attrset(ATTR_SELECTED);
656             if (i == pslice_focus)
657                 pslice_focus_found = -1;
658
659             if (label_chunk_info[i].c->type == whole) {
660                 if (sz >= 100 * ONE_GIG)
661                     mvprintw(srow++, 0,
662                         "Disk: %s\t\tFree: %jd blocks (%jdGB)",
663                         label_chunk_info[i].c->disk->name, (intmax_t)sz,
664                         (intmax_t)(sz / ONE_GIG));
665                 else
666                     mvprintw(srow++, 0,
667                         "Disk: %s\t\tFree: %jd blocks (%jdMB)",
668                         label_chunk_info[i].c->disk->name, (intmax_t)sz,
669                         (intmax_t)(sz / ONE_MEG));
670             } else {
671                 if (sz >= 100 * ONE_GIG)
672                     mvprintw(srow++, 0, 
673                         "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)",
674                         label_chunk_info[i].c->disk->name,
675                         label_chunk_info[i].c->name, 
676                         (intmax_t)sz, (intmax_t)(sz / ONE_GIG));
677                 else
678                     mvprintw(srow++, 0, 
679                         "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)",
680                         label_chunk_info[i].c->disk->name,
681                         label_chunk_info[i].c->name, 
682                         (intmax_t)sz, (intmax_t)(sz / ONE_MEG));
683             }
684             attrset(A_NORMAL);
685             clrtoeol();
686             move(0, 0);
687             /*** refresh(); ***/
688             ++pslice_count;
689         }
690         /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
691         else {
692             char onestr[PART_OFF], num[10], *mountpoint, newfs[12];
693
694             /*
695              * We copy this into a blank-padded string so that it looks like
696              * a solid bar in reverse-video
697              */
698             memset(onestr, ' ', PART_OFF - 1);
699             onestr[PART_OFF - 1] = '\0';
700
701             /*** Track how many labels have been displayed ***/
702             if (label_count == ((label_max - 1 ) * 2)) {
703                 if (label_focus_found) {
704                     continue;
705                 }
706                 else {
707                     label_count = 0;
708                     prow = 0;
709                     pcol = 0;
710                 }
711             }
712
713             /* Go for two columns if we've written one full columns worth */
714             /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
715             if (label_count == label_max - 1) {
716                 pcol = PART_OFF;
717                 prow = 0;
718             }
719             memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
720             /* If it's a filesystem, display the mountpoint */
721             if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM
722                 || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI))
723                 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
724             else if (label_chunk_info[i].type == PART_SWAP)
725                 mountpoint = "swap";
726             else
727                 mountpoint = "<none>";
728
729             /* Now display the newfs field */
730             if (label_chunk_info[i].type == PART_FAT)
731                 strcpy(newfs, "DOS");
732 #if defined(__ia64__)
733             else if (label_chunk_info[i].type == PART_EFI) {
734                 strcpy(newfs, "EFI");
735                 if (label_chunk_info[i].c->private_data) {
736                     strcat(newfs, "  ");
737                     PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
738                     strcat(newfs, pi->do_newfs ? " Y" : " N");
739                 }
740             }
741 #endif
742             else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
743                 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
744
745                 switch (pi->newfs_type) {
746                 case NEWFS_UFS:
747                         strcpy(newfs, NEWFS_UFS_STRING);
748                         if (pi->newfs_data.newfs_ufs.ufs1)
749                                 strcat(newfs, "1");
750                         else
751                                 strcat(newfs, "2");
752                         if (pi->newfs_data.newfs_ufs.softupdates)
753                                 strcat(newfs, "+S");
754                         else
755                                 strcat(newfs, "  ");
756
757                         break;
758                 case NEWFS_MSDOS:
759                         strcpy(newfs, "FAT");
760                         break;
761                 case NEWFS_CUSTOM:
762                         strcpy(newfs, "CUST");
763                         break;
764                 }
765                 strcat(newfs, pi->do_newfs ? " Y" : " N ");
766             }
767             else if (label_chunk_info[i].type == PART_SWAP)
768                 strcpy(newfs, "SWAP");
769             else
770                 strcpy(newfs, "*");
771             for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
772                 onestr[PART_MOUNT_COL + j] = mountpoint[j];
773             if (label_chunk_info[i].c->size == 0)
774                 snprintf(num, 10, "%5dMB", 0);
775             else if (label_chunk_info[i].c->size < (100 * ONE_GIG))
776                 snprintf(num, 10, "%5jdMB",
777                     (intmax_t)label_chunk_info[i].c->size / ONE_MEG);
778             else
779                 snprintf(num, 10, "%5jdGB",
780                     (intmax_t)label_chunk_info[i].c->size / ONE_GIG);
781             memcpy(onestr + PART_SIZE_COL, num, strlen(num));
782             memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
783             onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
784             if (i == label_focus) {
785                 label_focus_found = -1;
786                 wattrset(ChunkWin, A_BOLD);
787             }
788             if (i == here)
789                 wattrset(ChunkWin, ATTR_SELECTED);
790
791             /*** lazy man's way of expensively padding this string ***/
792             while (strlen(onestr) < 37)
793                 strcat(onestr, " ");
794
795             mvwaddstr(ChunkWin, prow, pcol, onestr);
796             wattrset(ChunkWin, A_NORMAL);
797             move(0, 0);
798             ++prow;
799             ++label_count;
800         }
801     }
802     
803     /*** this will erase all the extra stuff ***/
804     memset(clrmsg, ' ', 37);
805     clrmsg[37] = '\0';
806    
807     while (pslice_count < pslice_max) {
808         mvprintw(srow++, 0, clrmsg);
809         clrtoeol();
810         ++pslice_count;
811     }
812     while (label_count < (2 * (label_max - 1))) {
813         mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
814         ++label_count;
815         if (prow == (label_max - 1)) {
816             prow = 0;
817             pcol = PART_OFF;
818         }
819     }
820     refresh();
821     wrefresh(ChunkWin);
822 }
823
824 static void
825 print_command_summary(void)
826 {
827     mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
828     mvprintw(18, 0, "C = Create        D = Delete   M = Mount pt.");
829     if (!RunningAsInit)
830         mvprintw(18, 56, "W = Write");
831     mvprintw(19, 0, "N = Newfs Opts    Q = Finish   S = Toggle SoftUpdates   Z = Custom Newfs");
832     mvprintw(20, 0, "T = Toggle Newfs  U = Undo     A = Auto Defaults        R = Delete+Merge");
833     mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
834     move(0, 0);
835 }
836
837 static void
838 clear_wins(void)
839 {
840     extern void print_label_chunks();
841     clear();
842     print_label_chunks();
843 }
844
845 static int
846 diskLabel(Device *dev)
847 {
848     daddr_t sz;
849     int  key = 0;
850     Boolean labeling;
851     char *msg = NULL;
852     PartInfo *p, *oldp;
853     PartType type;
854     Device **devs;
855     WINDOW *w = savescr();
856
857     label_focus = 0;
858     pslice_focus = 0;
859     here = 0;
860
861     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
862     if (!devs) {
863         msgConfirm("No disks found!");
864         restorescr(w);
865         return DITEM_FAILURE;
866     }
867     labeling = TRUE;
868     keypad(stdscr, TRUE);
869     record_label_chunks(devs, dev);
870
871     clear();
872     while (labeling) {
873         char *cp;
874         int rflags = DELCHUNK_NORMAL;
875
876         print_label_chunks();
877         print_command_summary();
878         if (msg) {
879             attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
880             clrtoeol();
881             beep();
882             msg = NULL;
883         }
884         else {
885             move(23, 0);
886             clrtoeol();
887         }
888
889         refresh();
890         key = getch();
891         switch (toupper(key)) {
892             int i;
893             static char _msg[40];
894
895         case '\014':    /* ^L */
896             clear_wins();
897             break;
898
899         case '\020':    /* ^P */
900         case KEY_UP:
901         case '-':
902             if (here != 0)
903                 --here;
904             else
905                 while (label_chunk_info[here + 1].c)
906                     ++here;
907             break;
908
909         case '\016':    /* ^N */
910         case KEY_DOWN:
911         case '+':
912         case '\r':
913         case '\n':
914             if (label_chunk_info[here + 1].c)
915                 ++here;
916             else
917                 here = 0;
918             break;
919
920         case KEY_HOME:
921             here = 0;
922             break;
923
924         case KEY_END:
925             while (label_chunk_info[here + 1].c)
926                 ++here;
927             break;
928
929         case KEY_F(1):
930         case '?':
931             systemDisplayHelp("partition");
932             clear_wins();
933             break;
934
935         case '1':
936             if (label_chunk_info[here].type == PART_FILESYSTEM) {
937                 PartInfo *pi =
938                     ((PartInfo *)label_chunk_info[here].c->private_data);
939
940                 if ((pi != NULL) &&
941                     (pi->newfs_type == NEWFS_UFS)) {
942                         pi->newfs_data.newfs_ufs.ufs1 = true;
943                 } else
944                     msg = MSG_NOT_APPLICABLE;
945             } else
946                 msg = MSG_NOT_APPLICABLE;
947             break;
948                 break;
949
950         case '2':
951             if (label_chunk_info[here].type == PART_FILESYSTEM) {
952                 PartInfo *pi =
953                     ((PartInfo *)label_chunk_info[here].c->private_data);
954
955                 if ((pi != NULL) &&
956                     (pi->newfs_type == NEWFS_UFS)) {
957                         pi->newfs_data.newfs_ufs.ufs1 = false;
958                 } else
959                     msg = MSG_NOT_APPLICABLE;
960             } else
961                 msg = MSG_NOT_APPLICABLE;
962             break;
963                 break;
964
965         case 'A':
966             if (label_chunk_info[here].type != PART_SLICE) {
967                 msg = "You can only do this in a disk slice (at top of screen)";
968                 break;
969             }
970             /*
971              * Generate standard partitions automatically.  If we do not
972              * have sufficient space we attempt to scale-down the size
973              * of the partitions within certain bounds.
974              */
975             {
976                 int perc;
977                 int req = 0;
978
979                 for (perc = 100; perc > 0; perc -= 5) {
980                     req = 0;    /* reset for each loop */
981                     if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
982                         break;
983                 }
984                 if (msg) {
985                     if (req) {
986                         msgConfirm(msg);
987                         clear_wins();
988                         msg = NULL;
989                     }
990                 }
991             }
992             break;
993             
994         case 'C':
995             if (label_chunk_info[here].type != PART_SLICE) {
996                 msg = "You can only do this in a master partition (see top of screen)";
997                 break;
998             }
999             sz = space_free(label_chunk_info[here].c);
1000             if (sz <= FS_MIN_SIZE) {
1001                 msg = "Not enough space to create an additional FreeBSD partition";
1002                 break;
1003             }
1004             else {
1005                 char *val;
1006                 daddr_t size;
1007                 struct chunk *tmp;
1008                 char osize[80];
1009                 u_long flags = 0;
1010
1011 #ifdef __powerpc__
1012                 /* Always use the maximum size for apple partitions */
1013                 if (label_chunk_info[here].c->type == apple)
1014                     size = sz;
1015                 else {
1016 #endif
1017                 sprintf(osize, "%jd", (intmax_t)sz);
1018                 val = msgGetInput(osize,
1019                                   "Please specify the partition size in blocks or append a trailing G for\n"
1020 #ifdef __ia64__
1021                                   "gigabytes, M for megabytes.\n"
1022 #else
1023                                   "gigabytes, M for megabytes, or C for cylinders.\n"
1024 #endif
1025                                   "%jd blocks (%jdMB) are free.",
1026                                   (intmax_t)sz, (intmax_t)sz / ONE_MEG);
1027                 if (!val || (size = strtoimax(val, &cp, 0)) <= 0) {
1028                     clear_wins();
1029                     break;
1030                 }
1031
1032                 if (*cp) {
1033                     if (toupper(*cp) == 'M')
1034                         size *= ONE_MEG;
1035                     else if (toupper(*cp) == 'G')
1036                         size *= ONE_GIG;
1037 #ifndef __ia64__
1038                     else if (toupper(*cp) == 'C')
1039                         size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
1040 #endif
1041                 }
1042                 if (size <= FS_MIN_SIZE) {
1043                     msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
1044                     clear_wins();
1045                     break;
1046                 }
1047 #ifdef __powerpc__
1048                 }
1049 #endif
1050                 type = get_partition_type();
1051                 if (type == PART_NONE) {
1052                     clear_wins();
1053                     beep();
1054                     break;
1055                 }
1056
1057                 if (type == PART_FILESYSTEM || type == PART_EFI) {
1058                     if ((p = get_mountpoint(type, NULL)) == NULL) {
1059                         clear_wins();
1060                         beep();
1061                         break;
1062                     }
1063                     else if (!strcmp(p->mountpoint, "/")) {
1064                         if (type != PART_FILESYSTEM) {
1065                             clear_wins();
1066                             beep();
1067                             break;
1068                         }
1069                         else
1070                             flags |= CHUNK_IS_ROOT;
1071                     }
1072                     else
1073                         flags &= ~CHUNK_IS_ROOT;
1074                 }
1075                 else
1076                     p = NULL;
1077
1078                 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
1079                     msgConfirm("Warning: This is smaller than the recommended size for a\n"
1080                                "root partition.  For a variety of reasons, root\n"
1081                                "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
1082                 }
1083                 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1084                     label_chunk_info[here].c, size,
1085 #ifdef __ia64__
1086                     (type == PART_EFI) ? efi : part,
1087                     (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
1088 #else
1089                     part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
1090 #endif
1091                     flags);
1092                 if (!tmp) {
1093                     msgConfirm("Unable to create the partition. Too big?");
1094                     clear_wins();
1095                     break;
1096                 }
1097
1098 #ifdef __alpha__
1099                 /*
1100                  * SRM requires that the root partition is at the
1101                  * begining of the disk and cannot boot otherwise. 
1102                  * Warn Alpha users if they are about to shoot themselves in
1103                  * the foot in this way.
1104                  *
1105                  * Since partitions may not start precisely at offset 0 we
1106                  * check for a "close to 0" instead. :-(
1107                  */
1108                 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
1109                     msgConfirm("Your root partition `a' does not seem to be the first\n"
1110                                "partition.  The Alpha's firmware can only boot from the\n"
1111                                "first partition.  So it is unlikely that your current\n"
1112                                "disk layout will be bootable boot after installation.\n"
1113                                "\n"
1114                                "Please allocate the root partition before allocating\n"
1115                                "any others.\n");
1116                 }
1117 #endif  /* alpha */
1118
1119                 tmp->private_data = p;
1120                 tmp->private_free = safe_free;
1121                 if (variable_cmp(DISK_LABELLED, "written"))
1122                     variable_set2(DISK_LABELLED, "yes", 0);
1123                 record_label_chunks(devs, dev);
1124                 clear_wins();
1125                 /* This is where we assign focus to new label so it shows. */
1126                 {
1127                     int i;
1128                     label_focus = -1;
1129                     for (i = 0; label_chunk_info[i].c; ++i) {
1130                         if (label_chunk_info[i].c == tmp) {
1131                             label_focus = i;
1132                             break;
1133                         }
1134                     }
1135                     if (label_focus == -1)
1136                         label_focus = i - 1;
1137                 }
1138             }
1139             break;
1140
1141         case KEY_DC:
1142         case 'R':       /* recover space (delete w/ recover) */
1143             /*
1144              * Delete the partition w/ space recovery.
1145              */
1146             rflags = DELCHUNK_RECOVER;
1147             /* fall through */
1148         case 'D':       /* delete */
1149             if (label_chunk_info[here].type == PART_SLICE) {
1150                 msg = MSG_NOT_APPLICABLE;
1151                 break;
1152             }
1153             else if (label_chunk_info[here].type == PART_FAT) {
1154                 msg = "Use the Disk Partition Editor to delete DOS partitions";
1155                 break;
1156             }
1157             Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
1158             if (variable_cmp(DISK_LABELLED, "written"))
1159                 variable_set2(DISK_LABELLED, "yes", 0);
1160             record_label_chunks(devs, dev);
1161             break;
1162
1163         case 'M':       /* mount */
1164             switch(label_chunk_info[here].type) {
1165             case PART_SLICE:
1166                 msg = MSG_NOT_APPLICABLE;
1167                 break;
1168
1169             case PART_SWAP:
1170                 msg = "You don't need to specify a mountpoint for a swap partition.";
1171                 break;
1172
1173             case PART_FAT:
1174             case PART_EFI:
1175             case PART_FILESYSTEM:
1176                 oldp = label_chunk_info[here].c->private_data;
1177                 p = get_mountpoint(label_chunk_info[here].type, label_chunk_info[here].c);
1178                 if (p) {
1179                     if (!oldp)
1180                         p->do_newfs = FALSE;
1181                     if ((label_chunk_info[here].type == PART_FAT ||
1182                             label_chunk_info[here].type == PART_EFI) &&
1183                         (!strcmp(p->mountpoint, "/") ||
1184                             !strcmp(p->mountpoint, "/usr") ||
1185                             !strcmp(p->mountpoint, "/var"))) {
1186                         msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
1187                         strcpy(p->mountpoint, "/bogus");
1188                     }
1189                 }
1190                 if (variable_cmp(DISK_LABELLED, "written"))
1191                     variable_set2(DISK_LABELLED, "yes", 0);
1192                 record_label_chunks(devs, dev);
1193                 clear_wins();
1194                 break;
1195
1196             default:
1197                 msgFatal("Bogus partition under cursor???");
1198                 break;
1199             }
1200             break;
1201
1202         case 'N':       /* Set newfs options */
1203             if (label_chunk_info[here].c->private_data &&
1204                 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1205                 getNewfsOptionalArguments(
1206                     label_chunk_info[here].c->private_data);
1207             else
1208                 msg = MSG_NOT_APPLICABLE;
1209             clear_wins();
1210             break;
1211
1212         case 'S':       /* Toggle soft updates flag */
1213             if (label_chunk_info[here].type == PART_FILESYSTEM) {
1214                 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1215                 if (pi != NULL &&
1216                     pi->newfs_type == NEWFS_UFS)
1217                         pi->newfs_data.newfs_ufs.softupdates =
1218                             !pi->newfs_data.newfs_ufs.softupdates;
1219                 else
1220                     msg = MSG_NOT_APPLICABLE;
1221             }
1222             else
1223                 msg = MSG_NOT_APPLICABLE;
1224             break;
1225
1226         case 'T':       /* Toggle newfs state */
1227             if ((label_chunk_info[here].type == PART_FILESYSTEM ||
1228                  label_chunk_info[here].type == PART_EFI) &&
1229                 (label_chunk_info[here].c->private_data)) {
1230                 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1231                 if (!pi->do_newfs)
1232                     label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1233                 else
1234                     label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1235
1236                 label_chunk_info[here].c->private_data =
1237                     new_part(label_chunk_info[here].type, pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs
1238                     : TRUE);
1239                 if (pi != NULL &&
1240                     pi->newfs_type == NEWFS_UFS) {
1241                     PartInfo *pi_new = label_chunk_info[here].c->private_data;
1242
1243                     pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs;
1244                 }
1245                 safe_free(pi);
1246                 label_chunk_info[here].c->private_free = safe_free;
1247                 if (variable_cmp(DISK_LABELLED, "written"))
1248                     variable_set2(DISK_LABELLED, "yes", 0);
1249             }
1250             else
1251                 msg = MSG_NOT_APPLICABLE;
1252             break;
1253
1254         case 'U':
1255             clear();
1256             if (!variable_cmp(DISK_LABELLED, "written")) {
1257                 msgConfirm("You've already written out your changes -\n"
1258                            "it's too late to undo!");
1259             }
1260             else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1261                 variable_unset(DISK_PARTITIONED);
1262                 variable_unset(DISK_LABELLED);
1263                 for (i = 0; devs[i]; i++) {
1264                     Disk *d;
1265
1266                     if (!devs[i]->enabled)
1267                         continue;
1268                     else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1269                         Free_Disk(devs[i]->private);
1270                         devs[i]->private = d;
1271 #ifdef WITH_SLICES
1272                         diskPartition(devs[i]);
1273 #endif
1274                     }
1275                 }
1276                 record_label_chunks(devs, dev);
1277             }
1278             clear_wins();
1279             break;
1280
1281         case 'W':
1282             if (!variable_cmp(DISK_LABELLED, "written")) {
1283                 msgConfirm("You've already written out your changes - if you\n"
1284                            "wish to overwrite them, you'll have to restart\n"
1285                            "sysinstall first.");
1286             }
1287             else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
1288                           "installation.  If you are installing FreeBSD for the first time\n"
1289                           "then you should simply type Q when you're finished here and your\n"
1290                           "changes will be committed in one batch automatically at the end of\n"
1291                           "these questions.\n\n"
1292                           "Are you absolutely sure you want to do this now?")) {
1293                 variable_set2(DISK_LABELLED, "yes", 0);
1294                 diskLabelCommit(NULL);
1295             }
1296             clear_wins();
1297             break;
1298
1299         case 'Z':       /* Set newfs command line */
1300             if (label_chunk_info[here].c->private_data &&
1301                 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1302                 getNewfsCmd(label_chunk_info[here].c->private_data);
1303             else
1304                 msg = MSG_NOT_APPLICABLE;
1305             clear_wins();
1306             break;
1307
1308 #ifndef __ia64__
1309         case '|':
1310             if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1311                           "This is an entirely undocumented feature which you are not\n"
1312                           "expected to understand!")) {
1313                 int i;
1314                 Device **devs;
1315
1316                 dialog_clear();
1317                 end_dialog();
1318                 DialogActive = FALSE;
1319                 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1320                 if (!devs) {
1321                     msgConfirm("Can't find any disk devices!");
1322                     break;
1323                 }
1324                 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1325                     if (devs[i]->enabled)
1326                         slice_wizard(((Disk *)devs[i]->private));
1327                 }
1328                 if (variable_cmp(DISK_LABELLED, "written"))
1329                     variable_set2(DISK_LABELLED, "yes", 0);
1330                 DialogActive = TRUE;
1331                 record_label_chunks(devs, dev);
1332                 clear_wins();
1333             }
1334             else
1335                 msg = "A most prudent choice!";
1336             break;
1337 #endif
1338
1339         case '\033':    /* ESC */
1340         case 'Q':
1341             labeling = FALSE;
1342             break;
1343
1344         default:
1345             beep();
1346             sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1347             msg = _msg;
1348             break;
1349         }
1350         if (label_chunk_info[here].type == PART_SLICE)
1351             pslice_focus = here;
1352         else
1353             label_focus = here;
1354     }
1355     restorescr(w);
1356     return DITEM_SUCCESS;
1357 }
1358
1359 static __inline daddr_t
1360 requested_part_size(char *varName, daddr_t nom, int def, int perc)
1361 {
1362     char *cp;
1363     daddr_t sz;
1364
1365     if ((cp = variable_get(varName)) != NULL)
1366         sz = strtoimax(cp, NULL, 0);
1367     else
1368         sz = nom + (def - nom) * perc / 100;
1369     return(sz * ONE_MEG);
1370 }
1371
1372 /*
1373  * Attempt to auto-label the disk.  'perc' (0-100) scales
1374  * the size of the various partitions within appropriate
1375  * bounds (NOMINAL through DEFAULT sizes).  The procedure
1376  * succeeds of NULL is returned.  A non-null return message
1377  * is either a failure-status message (*req == 0), or 
1378  * a confirmation requestor (*req == 1).  *req is 0 on
1379  * entry to this call.
1380  *
1381  * As a special exception to the usual sizing rules, /var is given
1382  * additional space equal to the amount of physical memory present
1383  * if perc == 100 in order to ensure that users with large hard drives
1384  * will have enough space to store a crashdump in /var/crash.
1385  *
1386  * We autolabel the following partitions:  /, swap, /var, /tmp, /usr,
1387  * and /home.  /home receives any extra left over disk space. 
1388  */
1389 static char *
1390 try_auto_label(Device **devs, Device *dev, int perc, int *req)
1391 {
1392     daddr_t sz;
1393     Chunk *AutoHome, *AutoRoot, *AutoSwap;
1394     Chunk *AutoTmp, *AutoUsr, *AutoVar;
1395 #ifdef __ia64__
1396     Chunk *AutoEfi;
1397 #endif
1398     int mib[2];
1399     unsigned long physmem;
1400     size_t size;
1401     char *msg = NULL;
1402
1403     sz = space_free(label_chunk_info[here].c);
1404     if (sz <= FS_MIN_SIZE)
1405         return("Not enough free space to create a new partition in the slice");
1406
1407     (void)checkLabels(FALSE);
1408     AutoHome = AutoRoot = AutoSwap = NULL;
1409     AutoTmp = AutoUsr = AutoVar = NULL;
1410
1411 #ifdef __ia64__
1412     AutoEfi = NULL;
1413     if (EfiChunk == NULL) {
1414         sz = 100 * ONE_MEG;
1415         AutoEfi = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1416             label_chunk_info[here].c, sz, efi, 0, 0);
1417         if (AutoEfi == NULL) {
1418             *req = 1;
1419             msg = "Unable to create the EFI system partition. Too big?";
1420             goto done;
1421         }
1422         AutoEfi->private_data = new_part(PART_EFI, "/efi", TRUE);
1423         AutoEfi->private_free = safe_free;
1424         AutoEfi->flags |= CHUNK_NEWFS;
1425         record_label_chunks(devs, dev);
1426     }
1427 #endif
1428
1429     if (RootChunk == NULL) {
1430         sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1431
1432         AutoRoot = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1433                             label_chunk_info[here].c, sz, part,
1434                             FS_BSDFFS,  CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1435         if (!AutoRoot) {
1436             *req = 1;
1437             msg = "Unable to create the root partition. Too big?";
1438             goto done;
1439         }
1440         AutoRoot->private_data = new_part(PART_FILESYSTEM, "/", TRUE);
1441         AutoRoot->private_free = safe_free;
1442         AutoRoot->flags |= CHUNK_NEWFS;
1443         record_label_chunks(devs, dev);
1444     }
1445     if (SwapChunk == NULL) {
1446         sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1447         if (sz == 0) {
1448             daddr_t nom;
1449             daddr_t def;
1450
1451             mib[0] = CTL_HW;
1452             mib[1] = HW_PHYSMEM;
1453             size = sizeof physmem;
1454             sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1455             def = 2 * (int)(physmem / 512);
1456             if (def < SWAP_MIN_SIZE * ONE_MEG)
1457                 def = SWAP_MIN_SIZE * ONE_MEG;
1458             if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1459                 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1460             nom = (int)(physmem / 512) / 8;
1461             sz = nom + (def - nom) * perc / 100;
1462         }
1463         AutoSwap = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 
1464                             label_chunk_info[here].c, sz, part,
1465                             FS_SWAP, CHUNK_AUTO_SIZE);
1466         if (!AutoSwap) {
1467             *req = 1;
1468             msg = "Unable to create the swap partition. Too big?";
1469             goto done;
1470         }
1471         AutoSwap->private_data = 0;
1472         AutoSwap->private_free = safe_free;
1473         record_label_chunks(devs, dev);
1474     }
1475     if (VarChunk == NULL) {
1476         /* Work out how much extra space we want for a crash dump */
1477         unsigned long crashdumpsz;
1478
1479         mib[0] = CTL_HW;
1480         mib[1] = HW_PHYSMEM;
1481         size = sizeof(physmem);
1482         sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1483
1484         if (perc == 100)
1485                 crashdumpsz = physmem / 1048576;
1486         else
1487                 crashdumpsz = 0;
1488
1489         sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE,        \
1490             VAR_DEFAULT_SIZE + crashdumpsz, perc);
1491
1492         AutoVar = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 
1493                                 label_chunk_info[here].c, sz, part,
1494                                 FS_BSDFFS, CHUNK_AUTO_SIZE);
1495         if (!AutoVar) {
1496             *req = 1;
1497             msg = "Not enough free space for /var - you will need to\n"
1498                    "partition your disk manually with a custom install!";
1499             goto done;
1500         }
1501         AutoVar->private_data = new_part(PART_FILESYSTEM, "/var", TRUE);
1502         AutoVar->private_free = safe_free;
1503         AutoVar->flags |= CHUNK_NEWFS;
1504         record_label_chunks(devs, dev);
1505     }
1506     if (TmpChunk == NULL && !variable_get(VAR_NO_TMP)) {
1507         sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
1508
1509         AutoTmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 
1510                                 label_chunk_info[here].c, sz, part,
1511                                 FS_BSDFFS, CHUNK_AUTO_SIZE);
1512         if (!AutoTmp) {
1513             *req = 1;
1514             msg = "Not enough free space for /tmp - you will need to\n"
1515                    "partition your disk manually with a custom install!";
1516             goto done;
1517         }
1518         AutoTmp->private_data = new_part(PART_FILESYSTEM, "/tmp", TRUE);
1519         AutoTmp->private_free = safe_free;
1520         AutoTmp->flags |= CHUNK_NEWFS;
1521         record_label_chunks(devs, dev);
1522     }
1523     if (UsrChunk == NULL && !variable_get(VAR_NO_USR)) {
1524         sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1525 #if AUTO_HOME == 0
1526             sz = space_free(label_chunk_info[here].c);
1527 #endif
1528         if (sz) {
1529             if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1530                 *req = 1;
1531                 msg = "Not enough free space for /usr - you will need to\n"
1532                        "partition your disk manually with a custom install!";
1533             }
1534
1535             AutoUsr = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1536                                     label_chunk_info[here].c, sz, part,
1537                                     FS_BSDFFS, CHUNK_AUTO_SIZE);
1538             if (!AutoUsr) {
1539                 msg = "Unable to create the /usr partition.  Not enough space?\n"
1540                            "You will need to partition your disk manually with a custom install!";
1541                 goto done;
1542             }
1543             AutoUsr->private_data = new_part(PART_FILESYSTEM, "/usr", TRUE);
1544             AutoUsr->private_free = safe_free;
1545             AutoUsr->flags |= CHUNK_NEWFS;
1546             record_label_chunks(devs, dev);
1547         }
1548     }
1549 #if AUTO_HOME == 1
1550     if (HomeChunk == NULL && !variable_get(VAR_NO_HOME)) {
1551         sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1552         if (sz < space_free(label_chunk_info[here].c))
1553             sz = space_free(label_chunk_info[here].c);
1554         if (sz) {
1555             if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1556                 *req = 1;
1557                 msg = "Not enough free space for /home - you will need to\n"
1558                        "partition your disk manually with a custom install!";
1559                 goto done;
1560             }
1561
1562             AutoHome = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1563                                     label_chunk_info[here].c, sz, part,
1564                                     FS_BSDFFS, CHUNK_AUTO_SIZE);
1565             if (!AutoHome) {
1566                 msg = "Unable to create the /home partition.  Not enough space?\n"
1567                            "You will need to partition your disk manually with a custom install!";
1568                 goto done;
1569             }
1570             AutoHome->private_data = new_part(PART_FILESYSTEM, "/home", TRUE);
1571             AutoHome->private_free = safe_free;
1572             AutoHome->flags |= CHUNK_NEWFS;
1573             record_label_chunks(devs, dev);
1574         }
1575     }
1576 #endif
1577
1578     /* At this point, we're reasonably "labelled" */
1579     if (variable_cmp(DISK_LABELLED, "written"))
1580         variable_set2(DISK_LABELLED, "yes", 0);
1581
1582 done:
1583     if (msg) {
1584         if (AutoRoot != NULL)
1585             Delete_Chunk(AutoRoot->disk, AutoRoot);
1586         if (AutoSwap != NULL)
1587             Delete_Chunk(AutoSwap->disk, AutoSwap);
1588         if (AutoVar != NULL)
1589             Delete_Chunk(AutoVar->disk, AutoVar);
1590         if (AutoTmp != NULL)
1591             Delete_Chunk(AutoTmp->disk, AutoTmp);
1592         if (AutoUsr != NULL)
1593             Delete_Chunk(AutoUsr->disk, AutoUsr);
1594         if (AutoHome != NULL)
1595             Delete_Chunk(AutoHome->disk, AutoHome);
1596         record_label_chunks(devs, dev);
1597     }
1598     return(msg);
1599 }
1600
1601 static int
1602 diskLabelNonInteractive(Device *dev)
1603 {
1604     char *cp;
1605     PartType type;
1606     PartInfo *p;
1607     u_long flags;
1608     int i, status;
1609     Device **devs;
1610     Disk *d;
1611     
1612     status = DITEM_SUCCESS;
1613     cp = variable_get(VAR_DISK);
1614     if (!cp) {
1615         msgConfirm("diskLabel:  No disk selected - can't label automatically.");
1616         return DITEM_FAILURE;
1617     }
1618     devs = deviceFind(cp, DEVICE_TYPE_DISK);
1619     if (!devs) {
1620         msgConfirm("diskLabel: No disk device %s found!", cp);
1621         return DITEM_FAILURE;
1622     }
1623     if (dev)
1624         d = dev->private;
1625     else
1626         d = devs[0]->private;
1627     record_label_chunks(devs, dev);
1628     for (i = 0; label_chunk_info[i].c; i++) {
1629         Chunk *c1 = label_chunk_info[i].c;
1630
1631         if (label_chunk_info[i].type == PART_SLICE) {
1632             char name[512];
1633             char typ[10], mpoint[50];
1634             int entries;
1635
1636             for (entries = 1;; entries++) {
1637                 intmax_t sz;
1638                 int soft = 0;
1639                 snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1640                 if ((cp = variable_get(name)) == NULL)
1641                     break;
1642                 if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) {
1643                     msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
1644                     status = DITEM_FAILURE;
1645                     break;
1646                 } else {
1647                     Chunk *tmp;
1648
1649                     flags = 0;
1650                     if (!strcmp(typ, "swap")) {
1651                         type = PART_SWAP;
1652                         strcpy(mpoint, "SWAP");
1653                     } else {
1654                         type = PART_FILESYSTEM;
1655                         if (!strcmp(mpoint, "/"))
1656                             flags |= CHUNK_IS_ROOT;
1657                     }
1658                     if (!sz)
1659                         sz = space_free(c1);
1660                     if (sz > space_free(c1)) {
1661                         msgConfirm("Not enough free space to create partition: %s", mpoint);
1662                         status = DITEM_FAILURE;
1663                         break;
1664                     }
1665                     if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1666                         (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1667                         msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1668                         status = DITEM_FAILURE;
1669                         break;
1670                     } else {
1671                         PartInfo *pi;
1672                         pi = tmp->private_data = new_part(PART_FILESYSTEM, mpoint, TRUE);
1673                         tmp->private_free = safe_free;
1674                         pi->newfs_data.newfs_ufs.softupdates = soft;
1675                     }
1676                 }
1677             }
1678         } else {
1679             /* Must be something we can set a mountpoint for */
1680             cp = variable_get(c1->name);
1681             if (cp) {
1682                 char mpoint[50], do_newfs[8];
1683                 Boolean newfs = FALSE;
1684
1685                 do_newfs[0] = '\0';
1686                 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1687                     msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1688                     status = DITEM_FAILURE;
1689                     break;
1690                 }
1691                 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1692                 if (c1->private_data) {
1693                     p = c1->private_data;
1694                     p->do_newfs = newfs;
1695                     strcpy(p->mountpoint, mpoint);
1696                 }
1697                 else {
1698                     c1->private_data = new_part(PART_FILESYSTEM, mpoint, newfs);
1699                     c1->private_free = safe_free;
1700                 }
1701                 if (!strcmp(mpoint, "/"))
1702                     c1->flags |= CHUNK_IS_ROOT;
1703                 else
1704                     c1->flags &= ~CHUNK_IS_ROOT;
1705             }
1706         }
1707     }
1708     if (status == DITEM_SUCCESS)
1709         variable_set2(DISK_LABELLED, "yes", 0);
1710     return status;
1711 }