label.c revision 97667
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 97667 2002-05-31 13:38:17Z jhb $
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#ifdef __alpha__
63#define ROOT_MIN_SIZE			40
64#else
65#define ROOT_MIN_SIZE			30
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		128
84#define USR_DEFAULT_SIZE		3072
85#define VAR_DEFAULT_SIZE		256
86#define TMP_DEFAULT_SIZE		256
87#define HOME_DEFAULT_SIZE		USR_DEFAULT_SIZE
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		128
95#define USR_NOMINAL_SIZE		512
96#define VAR_NOMINAL_SIZE		64
97#define TMP_NOMINAL_SIZE		64
98#define HOME_NOMINAL_SIZE		USR_NOMINAL_SIZE
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) {
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, u_long size)
324{
325    PartInfo *ret;
326
327    if (!mpoint)
328	mpoint = "/change_me";
329
330    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
331    sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
332    strcpy(ret->newfs_cmd, "newfs ");
333    strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS));
334    ret->newfs = newfs;
335    ret->soft = strcmp(mpoint, "/") ? 1 : 0;
336    if (!size)
337	return ret;
338    return ret;
339}
340
341/* Get the mountpoint for a partition and save it away */
342static PartInfo *
343get_mountpoint(struct chunk *old)
344{
345    char *val;
346    PartInfo *tmp;
347
348    if (old && old->private_data)
349	tmp = old->private_data;
350    else
351	tmp = NULL;
352    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
353    if (!val || !*val) {
354	if (!old)
355	    return NULL;
356	else {
357	    free(old->private_data);
358	    old->private_data = NULL;
359	}
360	return NULL;
361    }
362
363    /* Is it just the same value? */
364    if (tmp && !strcmp(tmp->mountpoint, val))
365	return NULL;
366
367    /* Did we use it already? */
368    if (check_conflict(val)) {
369	msgConfirm("You already have a mount point for %s assigned!", val);
370	return NULL;
371    }
372
373    /* Is it bogus? */
374    if (*val != '/') {
375	msgConfirm("Mount point must start with a / character");
376	return NULL;
377    }
378
379    /* Is it going to be mounted on root? */
380    if (!strcmp(val, "/")) {
381	if (old)
382	    old->flags |= CHUNK_IS_ROOT;
383    }
384    else if (old)
385	old->flags &= ~CHUNK_IS_ROOT;
386
387    safe_free(tmp);
388    val = string_skipwhite(string_prune(val));
389    tmp = new_part(val, TRUE, 0);
390    if (old) {
391	old->private_data = tmp;
392	old->private_free = safe_free;
393    }
394    return tmp;
395}
396
397/* Get the type of the new partiton */
398static PartType
399get_partition_type(void)
400{
401    char selection[20];
402    int i;
403    static unsigned char *fs_types[] = {
404	"FS",
405	"A file system",
406	"Swap",
407	"A swap partition.",
408    };
409    WINDOW *w = savescr();
410
411    i = dialog_menu("Please choose a partition type",
412		    "If you want to use this partition for swap space, select Swap.\n"
413		    "If you want to put a filesystem on it, choose FS.",
414		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
415    restorescr(w);
416    if (!i) {
417	if (!strcmp(selection, "FS"))
418	    return PART_FILESYSTEM;
419	else if (!strcmp(selection, "Swap"))
420	    return PART_SWAP;
421    }
422    return PART_NONE;
423}
424
425/* If the user wants a special newfs command for this, set it */
426static void
427getNewfsCmd(PartInfo *p)
428{
429    char *val;
430
431    val = msgGetInput(p->newfs_cmd,
432		      "Please enter the newfs command and options you'd like to use in\n"
433		      "creating this file system.");
434    if (val)
435	sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
436}
437
438#define MAX_MOUNT_NAME	9
439
440#define PART_PART_COL	0
441#define PART_MOUNT_COL	10
442#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
443#define PART_NEWFS_COL	(PART_SIZE_COL + 8)
444#define PART_OFF	38
445
446#define TOTAL_AVAIL_LINES       (10)
447#define PSLICE_SHOWABLE          (4)
448
449
450/* stick this all up on the screen */
451static void
452print_label_chunks(void)
453{
454    int  i, j, srow, prow, pcol;
455    int  sz;
456    char clrmsg[80];
457    int ChunkPartStartRow;
458    WINDOW *ChunkWin;
459
460    /********************************************************/
461    /*** These values are for controling screen resources ***/
462    /*** Each label line holds up to 2 labels, so beware! ***/
463    /*** strategy will be to try to always make sure the  ***/
464    /*** highlighted label is in the active display area. ***/
465    /********************************************************/
466    int  pslice_max, label_max;
467    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
468
469    attrset(A_REVERSE);
470    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
471    attrset(A_NORMAL);
472
473    /*** Count the number of parition slices ***/
474    pslice_count = 0;
475    for (i = 0; label_chunk_info[i].c ; i++) {
476        if (label_chunk_info[i].type == PART_SLICE)
477            ++pslice_count;
478    }
479    pslice_max = pslice_count;
480
481    /*** 4 line max for partition slices ***/
482    if (pslice_max > PSLICE_SHOWABLE) {
483        pslice_max = PSLICE_SHOWABLE;
484    }
485    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
486
487    /*** View partition slices modulo pslice_max ***/
488    label_max = TOTAL_AVAIL_LINES - pslice_max;
489
490    for (i = 0; i < 2; i++) {
491	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
492	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
493
494	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
495	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
496
497	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
498	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
499
500	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
501	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
502    }
503    srow = CHUNK_SLICE_START_ROW;
504    prow = 0;
505    pcol = 0;
506
507    /*** these variables indicate that the focused item is shown currently ***/
508    label_focus_found = 0;
509    pslice_focus_found = 0;
510
511    label_count = 0;
512    pslice_count = 0;
513    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
514    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
515
516    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
517
518    wclear(ChunkWin);
519    /*** wrefresh(ChunkWin); ***/
520
521    for (i = 0; label_chunk_info[i].c; i++) {
522	/* Is it a slice entry displayed at the top? */
523	if (label_chunk_info[i].type == PART_SLICE) {
524            /*** This causes the new pslice to replace the previous display ***/
525            /*** focus must remain on the most recently active pslice       ***/
526            if (pslice_count == pslice_max) {
527                if (pslice_focus_found) {
528                    /*** This is where we can mark the more following ***/
529                    attrset(A_BOLD);
530                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
531                    attrset(A_NORMAL);
532                    continue;
533                }
534                else {
535                    /*** this is where we set the more previous ***/
536                    attrset(A_BOLD);
537                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
538                    attrset(A_NORMAL);
539                    pslice_count = 0;
540                    srow = CHUNK_SLICE_START_ROW;
541                }
542            }
543
544	    sz = space_free(label_chunk_info[i].c);
545	    if (i == here)
546		attrset(ATTR_SELECTED);
547            if (i == pslice_focus)
548                pslice_focus_found = -1;
549
550	    mvprintw(srow++, 0,
551		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
552		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
553		     sz, (sz / ONE_MEG));
554	    attrset(A_NORMAL);
555	    clrtoeol();
556	    move(0, 0);
557	    /*** refresh(); ***/
558            ++pslice_count;
559	}
560	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
561	else {
562	    char onestr[PART_OFF], num[10], *mountpoint, newfs[10];
563
564	    /*
565	     * We copy this into a blank-padded string so that it looks like
566	     * a solid bar in reverse-video
567	     */
568	    memset(onestr, ' ', PART_OFF - 1);
569	    onestr[PART_OFF - 1] = '\0';
570
571            /*** Track how many labels have been displayed ***/
572            if (label_count == ((label_max - 1 ) * 2)) {
573                if (label_focus_found) {
574                    continue;
575                }
576                else {
577                    label_count = 0;
578                    prow = 0;
579                    pcol = 0;
580                }
581            }
582
583	    /* Go for two columns if we've written one full columns worth */
584	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
585            if (label_count == label_max - 1) {
586		pcol = PART_OFF;
587		prow = 0;
588	    }
589	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
590	    /* If it's a filesystem, display the mountpoint */
591	    if (label_chunk_info[i].c->private_data
592		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
593	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
594	    else if (label_chunk_info[i].type == PART_SWAP)
595		mountpoint = "swap";
596	    else
597	        mountpoint = "<none>";
598
599	    /* Now display the newfs field */
600	    if (label_chunk_info[i].type == PART_FAT)
601	        strcpy(newfs, "DOS");
602	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
603		strcpy(newfs, "UFS");
604		strcat(newfs,
605		    ((PartInfo *)label_chunk_info[i].c->private_data)->soft ?
606		      "+S" : "  ");
607		strcat(newfs,
608		    ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ?
609		      " Y" : " N");
610	    }
611	    else if (label_chunk_info[i].type == PART_SWAP)
612		strcpy(newfs, "SWAP");
613	    else
614		strcpy(newfs, "*");
615	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
616		onestr[PART_MOUNT_COL + j] = mountpoint[j];
617	    snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
618	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
619	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
620	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
621            if (i == label_focus) {
622                label_focus_found = -1;
623                wattrset(ChunkWin, A_BOLD);
624            }
625	    if (i == here)
626		wattrset(ChunkWin, ATTR_SELECTED);
627
628            /*** lazy man's way of expensively padding this string ***/
629            while (strlen(onestr) < 37)
630                strcat(onestr, " ");
631
632	    mvwaddstr(ChunkWin, prow, pcol, onestr);
633	    wattrset(ChunkWin, A_NORMAL);
634	    move(0, 0);
635	    ++prow;
636            ++label_count;
637	}
638    }
639
640    /*** this will erase all the extra stuff ***/
641    memset(clrmsg, ' ', 37);
642    clrmsg[37] = '\0';
643
644    while (pslice_count < pslice_max) {
645        mvprintw(srow++, 0, clrmsg);
646        clrtoeol();
647        ++pslice_count;
648    }
649    while (label_count < (2 * (label_max - 1))) {
650        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
651	++label_count;
652	if (prow == (label_max - 1)) {
653	    prow = 0;
654	    pcol = PART_OFF;
655	}
656    }
657    refresh();
658    wrefresh(ChunkWin);
659}
660
661static void
662print_command_summary(void)
663{
664    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
665    mvprintw(18, 0, "C = Create        D = Delete   M = Mount pt.");
666    if (!RunningAsInit)
667	mvprintw(18, 47, "W = Write");
668    mvprintw(19, 0, "N = Newfs Opts    Q = Finish   S = Toggle SoftUpdates");
669    mvprintw(20, 0, "T = Toggle Newfs  U = Undo     A = Auto Defaults    R = Delete+Merge");
670    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
671    move(0, 0);
672}
673
674static void
675clear_wins(void)
676{
677    extern void print_label_chunks();
678    clear();
679    print_label_chunks();
680}
681
682#ifdef __alpha__
683
684/*
685 * If there isn't a freebsd chunk already (i.e. there is no label),
686 * dedicate the disk.
687 */
688static void
689maybe_dedicate(Disk* d)
690{
691    struct chunk *c;
692
693    for (c = d->chunks->part; c; c = c->next) {
694	if (c->type == freebsd)
695	    break;
696    }
697
698    if (!c) {
699	msgDebug("dedicating disk");
700	All_FreeBSD(d, 1);
701    }
702}
703
704#endif
705
706static int
707diskLabel(Device *dev)
708{
709    int sz, key = 0;
710    Boolean labeling;
711    char *msg = NULL;
712    PartInfo *p, *oldp;
713    PartType type;
714    Device **devs;
715#ifdef __alpha__
716    int i;
717#endif
718    WINDOW *w = savescr();
719
720    label_focus = 0;
721    pslice_focus = 0;
722    here = 0;
723
724    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
725    if (!devs) {
726	msgConfirm("No disks found!");
727	restorescr(w);
728	return DITEM_FAILURE;
729    }
730    labeling = TRUE;
731    keypad(stdscr, TRUE);
732#ifdef __alpha__
733    for (i = 0; devs[i]; i++) {
734	maybe_dedicate((Disk*) devs[i]->private);
735    }
736#endif
737    record_label_chunks(devs, dev);
738
739    clear();
740    while (labeling) {
741	char *cp;
742	int rflags = DELCHUNK_NORMAL;
743
744	print_label_chunks();
745	print_command_summary();
746	if (msg) {
747	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
748	    clrtoeol();
749	    beep();
750	    msg = NULL;
751	}
752	else {
753	    move(23, 0);
754	    clrtoeol();
755	}
756
757	refresh();
758	key = getch();
759	switch (toupper(key)) {
760	    int i;
761	    static char _msg[40];
762
763	case '\014':	/* ^L */
764	    clear_wins();
765	    break;
766
767	case '\020':	/* ^P */
768	case KEY_UP:
769	case '-':
770	    if (here != 0)
771		--here;
772	    else
773		while (label_chunk_info[here + 1].c)
774		    ++here;
775	    break;
776
777	case '\016':	/* ^N */
778	case KEY_DOWN:
779	case '+':
780	case '\r':
781	case '\n':
782	    if (label_chunk_info[here + 1].c)
783		++here;
784	    else
785		here = 0;
786	    break;
787
788	case KEY_HOME:
789	    here = 0;
790	    break;
791
792	case KEY_END:
793	    while (label_chunk_info[here + 1].c)
794		++here;
795	    break;
796
797	case KEY_F(1):
798	case '?':
799	    systemDisplayHelp("partition");
800	    clear_wins();
801	    break;
802
803	case 'A':
804	    if (label_chunk_info[here].type != PART_SLICE) {
805		msg = "You can only do this in a disk slice (at top of screen)";
806		break;
807	    }
808	    /*
809	     * Generate standard partitions automatically.  If we do not
810	     * have sufficient space we attempt to scale-down the size
811	     * of the partitions within certain bounds.
812	     */
813	    {
814		int perc;
815		int req = 0;
816
817		for (perc = 100; perc > 0; perc -= 5) {
818		    req = 0;	/* reset for each loop */
819		    if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
820			break;
821		}
822		if (msg) {
823		    if (req) {
824			msgConfirm(msg);
825			clear_wins();
826			msg = NULL;
827		    }
828		}
829	    }
830	    break;
831
832	case 'C':
833	    if (label_chunk_info[here].type != PART_SLICE) {
834		msg = "You can only do this in a master partition (see top of screen)";
835		break;
836	    }
837	    sz = space_free(label_chunk_info[here].c);
838	    if (sz <= FS_MIN_SIZE) {
839		msg = "Not enough space to create an additional FreeBSD partition";
840		break;
841	    }
842	    else {
843		char *val;
844		int size;
845		struct chunk *tmp;
846		char osize[80];
847		u_long flags = 0;
848
849		sprintf(osize, "%d", sz);
850		val = msgGetInput(osize,
851				  "Please specify the partition size in blocks or append a trailing G for\n"
852				  "gigabytes, M for megabytes, or C for cylinders.\n"
853				  "%d blocks (%dMB) are free.",
854				  sz, sz / ONE_MEG);
855		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
856		    clear_wins();
857		    break;
858		}
859
860		if (*cp) {
861		    if (toupper(*cp) == 'M')
862			size *= ONE_MEG;
863		    else if (toupper(*cp) == 'G')
864			size *= ONE_GIG;
865		    else if (toupper(*cp) == 'C')
866			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
867		}
868		if (size <= FS_MIN_SIZE) {
869		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
870		    clear_wins();
871		    break;
872		}
873		type = get_partition_type();
874		if (type == PART_NONE) {
875		    clear_wins();
876		    beep();
877		    break;
878		}
879
880		if (type == PART_FILESYSTEM) {
881		    if ((p = get_mountpoint(NULL)) == NULL) {
882			clear_wins();
883			beep();
884			break;
885		    }
886		    else if (!strcmp(p->mountpoint, "/"))
887			flags |= CHUNK_IS_ROOT;
888		    else
889			flags &= ~CHUNK_IS_ROOT;
890		}
891		else
892		    p = NULL;
893
894		if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
895		    msgConfirm("Warning: This is smaller than the recommended size for a\n"
896			       "root partition.  For a variety of reasons, root\n"
897			       "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
898		}
899		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
900					label_chunk_info[here].c,
901					size, part,
902					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
903					flags);
904		if (!tmp) {
905		    msgConfirm("Unable to create the partition. Too big?");
906		    clear_wins();
907		    break;
908		}
909
910#ifdef __alpha__
911		/*
912		 * SRM requires that the root partition is at the
913		 * begining of the disk and cannot boot otherwise.
914		 * Warn Alpha users if they are about to shoot themselves in
915		 * the foot in this way.
916		 *
917		 * Since partitions may not start precisely at offset 0 we
918		 * check for a "close to 0" instead. :-(
919		 */
920		if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
921		    msgConfirm("Your root partition `a' does not seem to be the first\n"
922			       "partition.  The Alpha's firmware can only boot from the\n"
923			       "first partition.  So it is unlikely that your current\n"
924			       "disk layout will be bootable boot after installation.\n"
925			       "\n"
926			       "Please allocate the root partition before allocating\n"
927			       "any others.\n");
928		}
929#endif	/* alpha */
930
931		if (type != PART_SWAP) {
932		    /* This is needed to tell the newfs -u about the size */
933		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
934		    safe_free(p);
935		}
936		else
937		    tmp->private_data = p;
938		tmp->private_free = safe_free;
939		if (variable_cmp(DISK_LABELLED, "written"))
940		    variable_set2(DISK_LABELLED, "yes", 0);
941		record_label_chunks(devs, dev);
942		clear_wins();
943                /* This is where we assign focus to new label so it shows. */
944                {
945                    int i;
946		    label_focus = -1;
947                    for (i = 0; label_chunk_info[i].c; ++i) {
948                    	if (label_chunk_info[i].c == tmp) {
949			    label_focus = i;
950			    break;
951			}
952		    }
953		    if (label_focus == -1)
954                    	label_focus = i - 1;
955                }
956	    }
957	    break;
958
959	case KEY_DC:
960	case 'R':	/* recover space (delete w/ recover) */
961	    /*
962	     * Delete the partition w/ space recovery.
963	     */
964	    rflags = DELCHUNK_RECOVER;
965	    /* fall through */
966	case 'D':	/* delete */
967	    if (label_chunk_info[here].type == PART_SLICE) {
968		msg = MSG_NOT_APPLICABLE;
969		break;
970	    }
971	    else if (label_chunk_info[here].type == PART_FAT) {
972		msg = "Use the Disk Partition Editor to delete DOS partitions";
973		break;
974	    }
975	    Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
976	    if (variable_cmp(DISK_LABELLED, "written"))
977		variable_set2(DISK_LABELLED, "yes", 0);
978	    record_label_chunks(devs, dev);
979	    break;
980
981	case 'M':	/* mount */
982	    switch(label_chunk_info[here].type) {
983	    case PART_SLICE:
984		msg = MSG_NOT_APPLICABLE;
985		break;
986
987	    case PART_SWAP:
988		msg = "You don't need to specify a mountpoint for a swap partition.";
989		break;
990
991	    case PART_FAT:
992	    case PART_FILESYSTEM:
993		oldp = label_chunk_info[here].c->private_data;
994		p = get_mountpoint(label_chunk_info[here].c);
995		if (p) {
996		    if (!oldp)
997		    	p->newfs = FALSE;
998		    if (label_chunk_info[here].type == PART_FAT
999			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
1000			    || !strcmp(p->mountpoint, "/var"))) {
1001			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
1002			strcpy(p->mountpoint, "/bogus");
1003		    }
1004		}
1005		if (variable_cmp(DISK_LABELLED, "written"))
1006		    variable_set2(DISK_LABELLED, "yes", 0);
1007		record_label_chunks(devs, dev);
1008		clear_wins();
1009		break;
1010
1011	    default:
1012		msgFatal("Bogus partition under cursor???");
1013		break;
1014	    }
1015	    break;
1016
1017	case 'N':	/* Set newfs options */
1018	    if (label_chunk_info[here].c->private_data &&
1019		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
1020		getNewfsCmd(label_chunk_info[here].c->private_data);
1021	    else
1022		msg = MSG_NOT_APPLICABLE;
1023	    clear_wins();
1024	    break;
1025
1026	case 'S':	/* Toggle soft updates flag */
1027	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
1028		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1029		if (pi)
1030		    pi->soft = !pi->soft;
1031		else
1032		    msg = MSG_NOT_APPLICABLE;
1033	    }
1034	    else
1035		msg = MSG_NOT_APPLICABLE;
1036	    break;
1037
1038	case 'T':	/* Toggle newfs state */
1039	    if ((label_chunk_info[here].type == PART_FILESYSTEM) &&
1040	        (label_chunk_info[here].c->private_data)) {
1041		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1042		if (!pi->newfs)
1043		    label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1044		else
1045		    label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1046
1047		label_chunk_info[here].c->private_data =
1048		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
1049		if (pi && pi->soft)
1050		    ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
1051		safe_free(pi);
1052		label_chunk_info[here].c->private_free = safe_free;
1053		if (variable_cmp(DISK_LABELLED, "written"))
1054		    variable_set2(DISK_LABELLED, "yes", 0);
1055	    }
1056	    else
1057		msg = MSG_NOT_APPLICABLE;
1058	    break;
1059
1060	case 'U':
1061	    clear();
1062	    if (!variable_cmp(DISK_LABELLED, "written")) {
1063		msgConfirm("You've already written out your changes -\n"
1064			   "it's too late to undo!");
1065	    }
1066	    else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1067		variable_unset(DISK_PARTITIONED);
1068		variable_unset(DISK_LABELLED);
1069		for (i = 0; devs[i]; i++) {
1070		    Disk *d;
1071
1072		    if (!devs[i]->enabled)
1073			continue;
1074		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1075			Free_Disk(devs[i]->private);
1076			devs[i]->private = d;
1077			diskPartition(devs[i]);
1078		    }
1079		}
1080		record_label_chunks(devs, dev);
1081	    }
1082	    clear_wins();
1083	    break;
1084
1085	case 'W':
1086	    if (!variable_cmp(DISK_LABELLED, "written")) {
1087		msgConfirm("You've already written out your changes - if you\n"
1088			   "wish to overwrite them, you'll have to restart\n"
1089			   "sysinstall first.");
1090	    }
1091	    else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
1092			  "installation.  If you are installing FreeBSD for the first time\n"
1093			  "then you should simply type Q when you're finished here and your\n"
1094			  "changes will be committed in one batch automatically at the end of\n"
1095			  "these questions.\n\n"
1096			  "Are you absolutely sure you want to do this now?")) {
1097		variable_set2(DISK_LABELLED, "yes", 0);
1098		diskLabelCommit(NULL);
1099	    }
1100	    clear_wins();
1101	    break;
1102
1103	case '|':
1104	    if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1105			  "This is an entirely undocumented feature which you are not\n"
1106			  "expected to understand!")) {
1107		int i;
1108		Device **devs;
1109
1110		dialog_clear();
1111		end_dialog();
1112		DialogActive = FALSE;
1113		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1114		if (!devs) {
1115		    msgConfirm("Can't find any disk devices!");
1116		    break;
1117		}
1118		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1119		    if (devs[i]->enabled)
1120		    	slice_wizard(((Disk *)devs[i]->private));
1121		}
1122		if (variable_cmp(DISK_LABELLED, "written"))
1123		    variable_set2(DISK_LABELLED, "yes", 0);
1124		DialogActive = TRUE;
1125		record_label_chunks(devs, dev);
1126		clear_wins();
1127	    }
1128	    else
1129		msg = "A most prudent choice!";
1130	    break;
1131
1132	case '\033':	/* ESC */
1133	case 'Q':
1134	    labeling = FALSE;
1135	    break;
1136
1137	default:
1138	    beep();
1139	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1140	    msg = _msg;
1141	    break;
1142	}
1143        if (label_chunk_info[here].type == PART_SLICE)
1144            pslice_focus = here;
1145        else
1146            label_focus = here;
1147    }
1148    restorescr(w);
1149    return DITEM_SUCCESS;
1150}
1151
1152static __inline int
1153requested_part_size(char *varName, int nom, int def, int perc)
1154{
1155    char *cp;
1156    int sz;
1157
1158    if ((cp = variable_get(VAR_ROOT_SIZE)) != NULL)
1159	sz = atoi(cp);
1160    else
1161	sz = nom + (def - nom) * perc / 100;
1162    return(sz * ONE_MEG);
1163}
1164
1165/*
1166 * Attempt to auto-label the disk.  'perc' (0-100) scales
1167 * the size of the various partitions within appropriate
1168 * bounds (NOMINAL through DEFAULT sizes).  The procedure
1169 * succeeds of NULL is returned.  A non-null return message
1170 * is either a failure-status message (*req == 0), or
1171 * a confirmation requestor (*req == 1).  *req is 0 on
1172 * entry to this call.
1173 *
1174 * We autolabel the following partitions:  /, swap, /var, /tmp, /usr,
1175 * and /home.  /home receives any extra left over disk space.
1176 */
1177static char *
1178try_auto_label(Device **devs, Device *dev, int perc, int *req)
1179{
1180    int sz;
1181    struct chunk *root_chunk = NULL;
1182    struct chunk *swap_chunk = NULL;
1183    struct chunk *usr_chunk = NULL;
1184    struct chunk *var_chunk = NULL;
1185    struct chunk *tmp_chunk = NULL;
1186    struct chunk *home_chunk = NULL;
1187    int mib[2];
1188    unsigned int physmem;
1189    size_t size;
1190    Chunk *rootdev, *swapdev, *usrdev, *vardev;
1191    Chunk *tmpdev, *homedev;
1192    char *msg = NULL;
1193
1194    sz = space_free(label_chunk_info[here].c);
1195    if (sz <= FS_MIN_SIZE)
1196	return("Not enough free space to create a new partition in the slice");
1197
1198    (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
1199			&vardev, &tmpdev, &homedev);
1200    if (!rootdev) {
1201	sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1202
1203	root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1204			    label_chunk_info[here].c, sz, part,
1205			    FS_BSDFFS,  CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1206	if (!root_chunk) {
1207	    *req = 1;
1208	    msg = "Unable to create the root partition. Too big?";
1209	    goto done;
1210	}
1211	root_chunk->private_data = new_part("/", TRUE, root_chunk->size);
1212	root_chunk->private_free = safe_free;
1213	root_chunk->flags |= CHUNK_NEWFS;
1214	record_label_chunks(devs, dev);
1215    }
1216    if (!swapdev) {
1217	sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1218	if (sz == 0) {
1219	    int nom;
1220	    int def;
1221
1222	    mib[0] = CTL_HW;
1223	    mib[1] = HW_PHYSMEM;
1224	    size = sizeof physmem;
1225	    sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1226	    def = 2 * (int)(physmem / 512);
1227	    if (def < SWAP_MIN_SIZE * ONE_MEG)
1228		def = SWAP_MIN_SIZE * ONE_MEG;
1229	    if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1230		def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1231	    nom = (int)(physmem / 512) / 2;
1232	    sz = nom + (def - nom) * perc / 100;
1233	}
1234	swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1235			    label_chunk_info[here].c, sz, part,
1236			    FS_SWAP, CHUNK_AUTO_SIZE);
1237	if (!swap_chunk) {
1238	    *req = 1;
1239	    msg = "Unable to create the swap partition. Too big?";
1240	    goto done;
1241	}
1242	swap_chunk->private_data = 0;
1243	swap_chunk->private_free = safe_free;
1244	record_label_chunks(devs, dev);
1245    }
1246    if (!vardev) {
1247	sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
1248
1249	var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1250				label_chunk_info[here].c, sz, part,
1251				FS_BSDFFS, CHUNK_AUTO_SIZE);
1252	if (!var_chunk) {
1253	    *req = 1;
1254	    msg = "Not enough free space for /var - you will need to\n"
1255		   "partition your disk manually with a custom install!";
1256	    goto done;
1257	}
1258	var_chunk->private_data = new_part("/var", TRUE, var_chunk->size);
1259	var_chunk->private_free = safe_free;
1260	var_chunk->flags |= CHUNK_NEWFS;
1261	record_label_chunks(devs, dev);
1262    }
1263    if (!tmpdev && !variable_get(VAR_NO_TMP)) {
1264	sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
1265
1266	tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1267				label_chunk_info[here].c, sz, part,
1268				FS_BSDFFS, CHUNK_AUTO_SIZE);
1269	if (!tmp_chunk) {
1270	    *req = 1;
1271	    msg = "Not enough free space for /tmp - you will need to\n"
1272		   "partition your disk manually with a custom install!";
1273	    goto done;
1274	}
1275	tmp_chunk->private_data = new_part("/tmp", TRUE, tmp_chunk->size);
1276	tmp_chunk->private_free = safe_free;
1277	tmp_chunk->flags |= CHUNK_NEWFS;
1278	record_label_chunks(devs, dev);
1279    }
1280    if (!usrdev && !variable_get(VAR_NO_USR)) {
1281	sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1282#if AUTO_HOME == 0
1283	    sz = space_free(label_chunk_info[here].c);
1284#endif
1285	if (sz) {
1286	    if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1287		*req = 1;
1288		msg = "Not enough free space for /usr - you will need to\n"
1289		       "partition your disk manually with a custom install!";
1290	    }
1291
1292	    usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1293				    label_chunk_info[here].c, sz, part,
1294				    FS_BSDFFS, CHUNK_AUTO_SIZE);
1295	    if (!usr_chunk) {
1296		msg = "Unable to create the /usr partition.  Not enough space?\n"
1297			   "You will need to partition your disk manually with a custom install!";
1298		goto done;
1299	    }
1300	    usr_chunk->private_data = new_part("/usr", TRUE, usr_chunk->size);
1301	    usr_chunk->private_free = safe_free;
1302	    usr_chunk->flags |= CHUNK_NEWFS;
1303	    record_label_chunks(devs, dev);
1304	}
1305    }
1306#if AUTO_HOME == 1
1307    if (!homedev && !variable_get(VAR_NO_HOME)) {
1308	sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1309	if (sz < space_free(label_chunk_info[here].c))
1310	    sz = space_free(label_chunk_info[here].c);
1311	if (sz) {
1312	    if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1313		*req = 1;
1314		msg = "Not enough free space for /home - you will need to\n"
1315		       "partition your disk manually with a custom install!";
1316		goto done;
1317	    }
1318
1319	    home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1320				    label_chunk_info[here].c, sz, part,
1321				    FS_BSDFFS, CHUNK_AUTO_SIZE);
1322	    if (!home_chunk) {
1323		msg = "Unable to create the /home partition.  Not enough space?\n"
1324			   "You will need to partition your disk manually with a custom install!";
1325		goto done;
1326	    }
1327	    home_chunk->private_data = new_part("/home", TRUE, home_chunk->size);
1328	    home_chunk->private_free = safe_free;
1329	    home_chunk->flags |= CHUNK_NEWFS;
1330	    record_label_chunks(devs, dev);
1331	}
1332    }
1333#endif
1334
1335    /* At this point, we're reasonably "labelled" */
1336    if (variable_cmp(DISK_LABELLED, "written"))
1337	variable_set2(DISK_LABELLED, "yes", 0);
1338
1339done:
1340    if (msg) {
1341	if (root_chunk)
1342	    Delete_Chunk(root_chunk->disk, root_chunk);
1343	if (swap_chunk)
1344	    Delete_Chunk(swap_chunk->disk, swap_chunk);
1345	if (var_chunk)
1346	    Delete_Chunk(var_chunk->disk, var_chunk);
1347	if (tmp_chunk)
1348	    Delete_Chunk(tmp_chunk->disk, tmp_chunk);
1349	if (usr_chunk)
1350	    Delete_Chunk(usr_chunk->disk, usr_chunk);
1351	if (home_chunk)
1352	    Delete_Chunk(home_chunk->disk, home_chunk);
1353	record_label_chunks(devs, dev);
1354    }
1355    return(msg);
1356}
1357
1358static int
1359diskLabelNonInteractive(Device *dev)
1360{
1361    char *cp;
1362    PartType type;
1363    PartInfo *p;
1364    u_long flags = 0;
1365    int i, status;
1366    Device **devs;
1367    Disk *d;
1368
1369    status = DITEM_SUCCESS;
1370    cp = variable_get(VAR_DISK);
1371    if (!cp) {
1372	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
1373	return DITEM_FAILURE;
1374    }
1375    devs = deviceFind(cp, DEVICE_TYPE_DISK);
1376    if (!devs) {
1377	msgConfirm("diskLabel: No disk device %s found!", cp);
1378	return DITEM_FAILURE;
1379    }
1380    if (dev)
1381	d = dev->private;
1382    else
1383	d = devs[0]->private;
1384#ifdef __alpha__
1385    maybe_dedicate(d);
1386#endif
1387    record_label_chunks(devs, dev);
1388    for (i = 0; label_chunk_info[i].c; i++) {
1389	Chunk *c1 = label_chunk_info[i].c;
1390
1391	if (label_chunk_info[i].type == PART_SLICE) {
1392	    char name[512];
1393	    int entries = 1;
1394
1395	    while (entries) {
1396		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1397		if ((cp = variable_get(name)) != NULL) {
1398		    int sz, soft = 0;
1399		    char typ[10], mpoint[50];
1400
1401		    if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1402			msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
1403			status = DITEM_FAILURE;
1404			continue;
1405		    }
1406		    else {
1407			Chunk *tmp;
1408
1409			if (!strcmp(typ, "swap")) {
1410			    type = PART_SWAP;
1411			    strcpy(mpoint, "SWAP");
1412			}
1413			else {
1414			    type = PART_FILESYSTEM;
1415			    if (!strcmp(mpoint, "/"))
1416				flags |= CHUNK_IS_ROOT;
1417			    else
1418				flags &= ~CHUNK_IS_ROOT;
1419			}
1420			if (!sz)
1421			    sz = space_free(c1);
1422			if (sz > space_free(c1)) {
1423			    msgConfirm("Not enough free space to create partition: %s", mpoint);
1424			    status = DITEM_FAILURE;
1425			    continue;
1426			}
1427			if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1428						      (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1429			    msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1430			    status = DITEM_FAILURE;
1431			    break;
1432			}
1433			else {
1434			    tmp->private_data = new_part(mpoint, TRUE, sz);
1435			    tmp->private_free = safe_free;
1436			    ((PartInfo *)tmp->private_data)->soft = soft;
1437			    status = DITEM_SUCCESS;
1438			}
1439		    }
1440		    entries++;
1441		}
1442		else {
1443		    /* No more matches, leave the loop */
1444		    entries = 0;
1445		}
1446	    }
1447	}
1448	else {
1449	    /* Must be something we can set a mountpoint for */
1450	    cp = variable_get(c1->name);
1451	    if (cp) {
1452		char mpoint[50], do_newfs[8];
1453		Boolean newfs = FALSE;
1454
1455		do_newfs[0] = '\0';
1456		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1457		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1458		    status = DITEM_FAILURE;
1459		    continue;
1460		}
1461		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1462		if (c1->private_data) {
1463		    p = c1->private_data;
1464		    p->newfs = newfs;
1465		    strcpy(p->mountpoint, mpoint);
1466		}
1467		else {
1468		    c1->private_data = new_part(mpoint, newfs, 0);
1469		    c1->private_free = safe_free;
1470		}
1471		if (!strcmp(mpoint, "/"))
1472		    c1->flags |= CHUNK_IS_ROOT;
1473		else
1474		    c1->flags &= ~CHUNK_IS_ROOT;
1475	    }
1476	}
1477    }
1478    if (status == DITEM_SUCCESS)
1479	variable_set2(DISK_LABELLED, "yes", 0);
1480    return status;
1481}
1482