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