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