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