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