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