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