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