label.c revision 87557
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 87557 2001-12-09 09:47:09Z 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 VARTMP_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 VARTMP_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 VARTMP_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		label_chunk_info[here].c->private_data =
1031		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
1032		if (pi && pi->soft)
1033		    ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
1034		safe_free(pi);
1035		label_chunk_info[here].c->private_free = safe_free;
1036		if (variable_cmp(DISK_LABELLED, "written"))
1037		    variable_set2(DISK_LABELLED, "yes", 0);
1038	    }
1039	    else
1040		msg = MSG_NOT_APPLICABLE;
1041	    break;
1042
1043	case 'U':
1044	    clear();
1045	    if (!variable_cmp(DISK_LABELLED, "written")) {
1046		msgConfirm("You've already written out your changes -\n"
1047			   "it's too late to undo!");
1048	    }
1049	    else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
1050		variable_unset(DISK_PARTITIONED);
1051		variable_unset(DISK_LABELLED);
1052		for (i = 0; devs[i]; i++) {
1053		    Disk *d;
1054
1055		    if (!devs[i]->enabled)
1056			continue;
1057		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
1058			Free_Disk(devs[i]->private);
1059			devs[i]->private = d;
1060			diskPartition(devs[i]);
1061		    }
1062		}
1063		record_label_chunks(devs, dev);
1064	    }
1065	    clear_wins();
1066	    break;
1067
1068	case 'W':
1069	    if (!variable_cmp(DISK_LABELLED, "written")) {
1070		msgConfirm("You've already written out your changes - if you\n"
1071			   "wish to overwrite them, you'll have to restart\n"
1072			   "sysinstall first.");
1073	    }
1074	    else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
1075			  "installation.  If you are installing FreeBSD for the first time\n"
1076			  "then you should simply type Q when you're finished here and your\n"
1077			  "changes will be committed in one batch automatically at the end of\n"
1078			  "these questions.\n\n"
1079			  "Are you absolutely sure you want to do this now?")) {
1080		variable_set2(DISK_LABELLED, "yes", 0);
1081		diskLabelCommit(NULL);
1082	    }
1083	    clear_wins();
1084	    break;
1085
1086	case '|':
1087	    if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
1088			  "This is an entirely undocumented feature which you are not\n"
1089			  "expected to understand!")) {
1090		int i;
1091		Device **devs;
1092
1093		dialog_clear();
1094		end_dialog();
1095		DialogActive = FALSE;
1096		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1097		if (!devs) {
1098		    msgConfirm("Can't find any disk devices!");
1099		    break;
1100		}
1101		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
1102		    if (devs[i]->enabled)
1103		    	slice_wizard(((Disk *)devs[i]->private));
1104		}
1105		if (variable_cmp(DISK_LABELLED, "written"))
1106		    variable_set2(DISK_LABELLED, "yes", 0);
1107		DialogActive = TRUE;
1108		record_label_chunks(devs, dev);
1109		clear_wins();
1110	    }
1111	    else
1112		msg = "A most prudent choice!";
1113	    break;
1114
1115	case '\033':	/* ESC */
1116	case 'Q':
1117	    labeling = FALSE;
1118	    break;
1119
1120	default:
1121	    beep();
1122	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
1123	    msg = _msg;
1124	    break;
1125	}
1126        if (label_chunk_info[here].type == PART_SLICE)
1127            pslice_focus = here;
1128        else
1129            label_focus = here;
1130    }
1131    restorescr(w);
1132    return DITEM_SUCCESS;
1133}
1134
1135static __inline int
1136requested_part_size(char *varName, int nom, int def, int perc)
1137{
1138    char *cp;
1139    int sz;
1140
1141    if ((cp = variable_get(VAR_ROOT_SIZE)) != NULL)
1142	sz = atoi(cp);
1143    else
1144	sz = nom + (def - nom) * perc / 100;
1145    return(sz * ONE_MEG);
1146}
1147
1148/*
1149 * Attempt to auto-label the disk.  'perc' (0-100) scales
1150 * the size of the various partitions within appropriate
1151 * bounds (NOMINAL through DEFAULT sizes).  The procedure
1152 * succeeds of NULL is returned.  A non-null return message
1153 * is either a failure-status message (*req == 0), or
1154 * a confirmation requestor (*req == 1).  *req is 0 on
1155 * entry to this call.
1156 *
1157 * We autolabel the following partitions:  /, swap, /var, /var/tmp, /usr,
1158 * and /home.  /home receives any extra left over disk space.
1159 */
1160static char *
1161try_auto_label(Device **devs, Device *dev, int perc, int *req)
1162{
1163    int sz;
1164    struct chunk *root_chunk = NULL;
1165    struct chunk *swap_chunk = NULL;
1166    struct chunk *usr_chunk = NULL;
1167    struct chunk *var_chunk = NULL;
1168    struct chunk *vartmp_chunk = NULL;
1169    struct chunk *home_chunk = NULL;
1170    int mib[2];
1171    unsigned int physmem;
1172    size_t size;
1173    Chunk *rootdev, *swapdev, *usrdev, *vardev;
1174    Chunk *vartmpdev, *homedev;
1175    char *msg = NULL;
1176
1177    sz = space_free(label_chunk_info[here].c);
1178    if (sz <= FS_MIN_SIZE)
1179	return("Not enough free space to create a new partition in the slice");
1180
1181    (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
1182			&vardev, &vartmpdev, &homedev);
1183    if (!rootdev) {
1184	sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
1185
1186	root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
1187				sz, part, FS_BSDFFS,  CHUNK_IS_ROOT);
1188	if (!root_chunk) {
1189	    *req = 1;
1190	    msg = "Unable to create the root partition. Too big?";
1191	    goto done;
1192	}
1193	root_chunk->private_data = new_part("/", TRUE, root_chunk->size);
1194	root_chunk->private_free = safe_free;
1195	record_label_chunks(devs, dev);
1196    }
1197    if (!swapdev) {
1198	sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
1199	if (sz == 0) {
1200	    int nom;
1201	    int def;
1202
1203	    mib[0] = CTL_HW;
1204	    mib[1] = HW_PHYSMEM;
1205	    size = sizeof physmem;
1206	    sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1207	    def = 2 * (int)(physmem / 512);
1208	    if (def < SWAP_MIN_SIZE * ONE_MEG)
1209		def = SWAP_MIN_SIZE * ONE_MEG;
1210	    if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
1211		def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1212	    nom = (int)(physmem / 512) / 2;
1213	    sz = nom + (def - nom) * perc / 100;
1214	}
1215	swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
1216				sz, part, FS_SWAP, 0);
1217	if (!swap_chunk) {
1218	    *req = 1;
1219	    msg = "Unable to create the swap partition. Too big?";
1220	    goto done;
1221	}
1222	swap_chunk->private_data = 0;
1223	swap_chunk->private_free = safe_free;
1224	record_label_chunks(devs, dev);
1225    }
1226    if (!vardev) {
1227	sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
1228
1229	var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
1230				sz, part, FS_BSDFFS, 0);
1231	if (!var_chunk) {
1232	    *req = 1;
1233	    msg = "Not enough free space for /var - you will need to\n"
1234		   "partition your disk manually with a custom install!";
1235	    goto done;
1236	}
1237	var_chunk->private_data = new_part("/var", TRUE, var_chunk->size);
1238	var_chunk->private_free = safe_free;
1239	record_label_chunks(devs, dev);
1240    }
1241    if (!vartmpdev && !variable_get(VAR_NO_VARTMP)) {
1242	sz = requested_part_size(VAR_VARTMP_SIZE, VARTMP_NOMINAL_SIZE, VARTMP_DEFAULT_SIZE, perc);
1243
1244	vartmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
1245				sz, part, FS_BSDFFS, 0);
1246	if (!vartmp_chunk) {
1247	    *req = 1;
1248	    msg = "Not enough free space for /var/tmp - you will need to\n"
1249		   "partition your disk manually with a custom install!";
1250	    goto done;
1251	}
1252	vartmp_chunk->private_data = new_part("/var/tmp", TRUE, vartmp_chunk->size);
1253	vartmp_chunk->private_free = safe_free;
1254	record_label_chunks(devs, dev);
1255    }
1256    if (!usrdev && !variable_get(VAR_NO_USR)) {
1257	sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
1258#if 0
1259	    sz = space_free(label_chunk_info[here].c);
1260#endif
1261	if (sz) {
1262	    if (sz < (USR_MIN_SIZE * ONE_MEG)) {
1263		*req = 1;
1264		msg = "Not enough free space for /usr - you will need to\n"
1265		       "partition your disk manually with a custom install!";
1266	    }
1267
1268	    usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1269				    label_chunk_info[here].c,
1270				    sz, part, FS_BSDFFS, 0);
1271	    if (!usr_chunk) {
1272		msg = "Unable to create the /usr partition.  Not enough space?\n"
1273			   "You will need to partition your disk manually with a custom install!";
1274		goto done;
1275	    }
1276	    usr_chunk->private_data = new_part("/usr", TRUE, usr_chunk->size);
1277	    usr_chunk->private_free = safe_free;
1278	    record_label_chunks(devs, dev);
1279	}
1280    }
1281    if (!homedev && !variable_get(VAR_NO_HOME)) {
1282	sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
1283	if (sz < space_free(label_chunk_info[here].c))
1284	    sz = space_free(label_chunk_info[here].c);
1285	if (sz) {
1286	    if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
1287		*req = 1;
1288		msg = "Not enough free space for /home - you will need to\n"
1289		       "partition your disk manually with a custom install!";
1290		goto done;
1291	    }
1292
1293	    home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1294				    label_chunk_info[here].c,
1295				    sz, part, FS_BSDFFS, 0);
1296	    if (!home_chunk) {
1297		msg = "Unable to create the /home partition.  Not enough space?\n"
1298			   "You will need to partition your disk manually with a custom install!";
1299		goto done;
1300	    }
1301	    home_chunk->private_data = new_part("/home", TRUE, home_chunk->size);
1302	    home_chunk->private_free = safe_free;
1303	    record_label_chunks(devs, dev);
1304	}
1305    }
1306
1307    /* At this point, we're reasonably "labelled" */
1308    if (variable_cmp(DISK_LABELLED, "written"))
1309	variable_set2(DISK_LABELLED, "yes", 0);
1310
1311done:
1312    if (msg) {
1313	if (root_chunk)
1314	    Delete_Chunk(root_chunk->disk, root_chunk);
1315	if (swap_chunk)
1316	    Delete_Chunk(swap_chunk->disk, swap_chunk);
1317	if (var_chunk)
1318	    Delete_Chunk(var_chunk->disk, var_chunk);
1319	if (vartmp_chunk)
1320	    Delete_Chunk(vartmp_chunk->disk, vartmp_chunk);
1321	if (usr_chunk)
1322	    Delete_Chunk(usr_chunk->disk, usr_chunk);
1323	if (home_chunk)
1324	    Delete_Chunk(home_chunk->disk, home_chunk);
1325	record_label_chunks(devs, dev);
1326    }
1327    return(msg);
1328}
1329
1330static int
1331diskLabelNonInteractive(Device *dev)
1332{
1333    char *cp;
1334    PartType type;
1335    PartInfo *p;
1336    u_long flags = 0;
1337    int i, status;
1338    Device **devs;
1339    Disk *d;
1340
1341    status = DITEM_SUCCESS;
1342    cp = variable_get(VAR_DISK);
1343    if (!cp) {
1344	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
1345	return DITEM_FAILURE;
1346    }
1347    devs = deviceFind(cp, DEVICE_TYPE_DISK);
1348    if (!devs) {
1349	msgConfirm("diskLabel: No disk device %s found!", cp);
1350	return DITEM_FAILURE;
1351    }
1352    if (dev)
1353	d = dev->private;
1354    else
1355	d = devs[0]->private;
1356#ifdef __alpha__
1357    maybe_dedicate(d);
1358#endif
1359    record_label_chunks(devs, dev);
1360    for (i = 0; label_chunk_info[i].c; i++) {
1361	Chunk *c1 = label_chunk_info[i].c;
1362
1363	if (label_chunk_info[i].type == PART_SLICE) {
1364	    char name[512];
1365	    int entries = 1;
1366
1367	    while (entries) {
1368		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1369		if ((cp = variable_get(name)) != NULL) {
1370		    int sz, soft = 0;
1371		    char typ[10], mpoint[50];
1372
1373		    if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1374			msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
1375			status = DITEM_FAILURE;
1376			continue;
1377		    }
1378		    else {
1379			Chunk *tmp;
1380
1381			if (!strcmp(typ, "swap")) {
1382			    type = PART_SWAP;
1383			    strcpy(mpoint, "SWAP");
1384			}
1385			else {
1386			    type = PART_FILESYSTEM;
1387			    if (!strcmp(mpoint, "/"))
1388				flags |= CHUNK_IS_ROOT;
1389			    else
1390				flags &= ~CHUNK_IS_ROOT;
1391			}
1392			if (!sz)
1393			    sz = space_free(c1);
1394			if (sz > space_free(c1)) {
1395			    msgConfirm("Not enough free space to create partition: %s", mpoint);
1396			    status = DITEM_FAILURE;
1397			    continue;
1398			}
1399			if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1400						      (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1401			    msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1402			    status = DITEM_FAILURE;
1403			    break;
1404			}
1405			else {
1406			    tmp->private_data = new_part(mpoint, TRUE, sz);
1407			    tmp->private_free = safe_free;
1408			    ((PartInfo *)tmp->private_data)->soft = soft;
1409			    status = DITEM_SUCCESS;
1410			}
1411		    }
1412		    entries++;
1413		}
1414		else {
1415		    /* No more matches, leave the loop */
1416		    entries = 0;
1417		}
1418	    }
1419	}
1420	else {
1421	    /* Must be something we can set a mountpoint for */
1422	    cp = variable_get(c1->name);
1423	    if (cp) {
1424		char mpoint[50], do_newfs[8];
1425		Boolean newfs = FALSE;
1426
1427		do_newfs[0] = '\0';
1428		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
1429		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
1430		    status = DITEM_FAILURE;
1431		    continue;
1432		}
1433		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
1434		if (c1->private_data) {
1435		    p = c1->private_data;
1436		    p->newfs = newfs;
1437		    strcpy(p->mountpoint, mpoint);
1438		}
1439		else {
1440		    c1->private_data = new_part(mpoint, newfs, 0);
1441		    c1->private_free = safe_free;
1442		}
1443		if (!strcmp(mpoint, "/"))
1444		    c1->flags |= CHUNK_IS_ROOT;
1445		else
1446		    c1->flags &= ~CHUNK_IS_ROOT;
1447	    }
1448	}
1449    }
1450    if (status == DITEM_SUCCESS)
1451	variable_set2(DISK_LABELLED, "yes", 0);
1452    return status;
1453}
1454