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