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