Deleted Added
full compact
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 * $Id: label.c,v 1.19 1995/05/21 17:53:27 jkh Exp $
7 * $Id: label.c,v 1.20 1995/05/21 18:24:33 jkh Exp $
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 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by Jordan Hubbard
25 * for the FreeBSD Project.
26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27 * endorse or promote products derived from this software without specific
28 * prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44#include "sysinstall.h"
45#include <ctype.h>
46#include <sys/disklabel.h>
47
48/*
49 * Everything to do with editing the contents of disk labels.
50 */
51
52/* A nice message we use a lot in the disklabel editor */
53#define MSG_NOT_APPLICABLE "That option is not applicable here"
54
55/*
56 * I make some pretty gross assumptions about having a max of 50 chunks
57 * total - 8 slices and 42 partitions. I can't easily display many more
58 * than that on the screen at once!
59 *
60 * For 2.1 I'll revisit this and try to make it more dynamic, but since
61 * this will catch 99.99% of all possible cases, I'm not too worried.
62 */
63#define MAX_CHUNKS 50
64
65/* Where to start printing the freebsd slices */
66#define CHUNK_SLICE_START_ROW 2
67#define CHUNK_PART_START_ROW 11
68
69/* One MB worth of blocks */
70#define ONE_MEG 2048
71
72/* The smallest filesystem we're willing to create */
70#define FS_MIN_SIZE 2048
73#define FS_MIN_SIZE ONE_MEG
74
75/* The smallest root filesystem we're willing to create */
73#define ROOT_MIN_SIZE 40960 /* 20MB */
76#define ROOT_MIN_SIZE (20 * ONE_MEG)
77
78/* All the chunks currently displayed on the screen */
79static struct {
80 struct disk *d;
81 struct chunk *c;
82 PartType type;
83} label_chunk_info[MAX_CHUNKS + 1];
84static int here;
85
86/* See if we're already using a desired partition name */
87static Boolean
88check_conflict(char *name)
89{
90 int i;
91
92 for (i = 0; label_chunk_info[i].d; i++)
93 if (label_chunk_info[i].type == PART_FILESYSTEM
94 && label_chunk_info[i].c->private
95 && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name))
96 return TRUE;
97 return FALSE;
98}
99
100/* How much space is in this FreeBSD slice? */
101static int
102space_free(struct chunk *c)
103{
104 struct chunk *c1 = c->part;
105 int sz = c->size;
106
107 while (c1) {
108 if (c1->type != unused)
109 sz -= c1->size;
110 c1 = c1->next;
111 }
112 if (sz < 0)
113 msgFatal("Partitions are larger than actual chunk??");
114 return sz;
115}
116
117/* Snapshot the current situation into the displayed chunks structure */
118static void
119record_label_chunks()
120{
121 int i, j, p;
122 struct chunk *c1, *c2;
123 Device **devs;
124 Disk *d;
125
126 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
127 if (!devs) {
128 msgConfirm("No disks found!");
129 return;
130 }
131
132 j = p = 0;
133 /* First buzz through and pick up the FreeBSD slices */
134 for (i = 0; devs[i]; i++) {
135 if (!devs[i]->enabled)
136 continue;
137 d = (Disk *)devs[i]->private;
138 if (!d->chunks)
139 msgFatal("No chunk list found for %s!", d->name);
140
141 /* Put the slice entries first */
142 for (c1 = d->chunks->part; c1; c1 = c1->next) {
143 if (c1->type == freebsd) {
144 label_chunk_info[j].type = PART_SLICE;
145 label_chunk_info[j].d = d;
146 label_chunk_info[j].c = c1;
147 ++j;
148 }
149 }
150 }
151 /* Now run through again and get the FreeBSD partition entries */
152 for (i = 0; devs[i]; i++) {
153 if (!devs[i]->enabled)
154 continue;
155 d = (Disk *)devs[i]->private;
156 /* Then buzz through and pick up the partitions */
157 for (c1 = d->chunks->part; c1; c1 = c1->next) {
158 if (c1->type == freebsd) {
159 for (c2 = c1->part; c2; c2 = c2->next) {
160 if (c2->type == part) {
161 if (c2->subtype == FS_SWAP)
162 label_chunk_info[j].type = PART_SWAP;
163 else
164 label_chunk_info[j].type = PART_FILESYSTEM;
165 label_chunk_info[j].d = d;
166 label_chunk_info[j].c = c2;
167 ++j;
168 }
169 }
170 }
171 else if (c1->type == fat) {
172 label_chunk_info[j].type = PART_FAT;
173 label_chunk_info[j].d = d;
174 label_chunk_info[j].c = c1;
175 ++j;
176 }
177 }
178 }
179 label_chunk_info[j].d = NULL;
180 label_chunk_info[j].c = NULL;
181 if (here >= j)
182 here = j ? j - 1 : 0;
183}
184
185/* A new partition entry */
186static PartInfo *
187new_part(char *mpoint, Boolean newfs, u_long size)
188{
189 PartInfo *ret;
190 u_long target,divisor;
191
192 ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
193 strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
194 strcpy(ret->newfs_cmd, "newfs");
195 ret->newfs = newfs;
196 if (!size)
197 return ret;
198 for(target = size; target; target--) {
199 for(divisor = 4096 ; divisor > 1023; divisor--) {
200 if (!(target % divisor)) {
201 sprintf(ret->newfs_cmd+strlen(ret->newfs_cmd),
202 " -u %ld",divisor);
203 return ret;
204 }
205 }
206 }
207 return ret;
208}
209
210/* Get the mountpoint for a partition and save it away */
211PartInfo *
212get_mountpoint(struct chunk *old)
213{
214 char *val;
215 PartInfo *tmp;
216
213 dialog_clear(); clear();
217 val = msgGetInput(old && old->private ? ((PartInfo *)old->private)->mountpoint : NULL,
218 "Please specify a mount point for the partition");
219 if (!val)
220 return NULL;
221
222 /* Is it just the same value? */
223 if (old && old->private && !strcmp(((PartInfo *)old->private)->mountpoint, val))
224 return NULL;
225 if (check_conflict(val)) {
226 msgConfirm("You already have a mount point for %s assigned!", val);
227 return NULL;
228 }
229 if (*val != '/') {
230 msgConfirm("Mount point must start with a / character");
231 return NULL;
232 }
233 if (!strcmp(val, "/")) {
234 if (old)
235 old->flags |= CHUNK_IS_ROOT;
236 } else if (old) {
237 old->flags &= ~CHUNK_IS_ROOT;
238 }
239 safe_free(old ? old->private : NULL);
240 tmp = new_part(val, TRUE, 0);
241 if (old) {
242 old->private = tmp;
243 old->private_free = safe_free;
244 }
245 return tmp;
246}
247
248/* Get the type of the new partiton */
249static PartType
250get_partition_type(void)
251{
252 char selection[20];
253 int i;
254
255 static unsigned char *fs_types[] = {
256 "FS",
257 "A file system",
258 "Swap",
259 "A swap partition.",
260 };
258 dialog_clear(); clear();
261 i = dialog_menu("Please choose a partition type",
262 "If you want to use this partition for swap space, select Swap.\nIf you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL);
263 if (!i) {
264 if (!strcmp(selection, "FS"))
265 return PART_FILESYSTEM;
266 else if (!strcmp(selection, "Swap"))
267 return PART_SWAP;
268 }
269 return PART_NONE;
270}
271
272/* If the user wants a special newfs command for this, set it */
273static void
274getNewfsCmd(PartInfo *p)
275{
276 char *val;
277
278 val = msgGetInput(p->newfs_cmd,
279 "Please enter the newfs command and options you'd like to use in\ncreating this file system.");
280 if (val)
281 strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
282}
283
284
285#define MAX_MOUNT_NAME 12
286
287#define PART_PART_COL 0
288#define PART_MOUNT_COL 8
289#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
290#define PART_NEWFS_COL (PART_SIZE_COL + 7)
291#define PART_OFF 38
292
293/* How many mounted partitions to display in column before going to next */
294#define CHUNK_COLUMN_MAX 5
295
296/* stick this all up on the screen */
297static void
298print_label_chunks(void)
299{
300 int i, j, srow, prow, pcol;
301 int sz;
302
303 attrset(A_REVERSE);
304 mvaddstr(0, 25, "FreeBSD Disklabel Editor");
305 clrtobot();
306 attrset(A_NORMAL);
307
308 for (i = 0; i < 2; i++) {
309 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part");
310 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----");
311
312 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
313 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
314
315 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
316 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
317
318 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
319 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
320 }
321 srow = CHUNK_SLICE_START_ROW;
322 prow = CHUNK_PART_START_ROW;
323 pcol = 0;
324
325 for (i = 0; label_chunk_info[i].d; i++) {
326 if (i == here)
327 attrset(A_REVERSE);
328 /* Is it a slice entry displayed at the top? */
329 if (label_chunk_info[i].type == PART_SLICE) {
330 sz = space_free(label_chunk_info[i].c);
331 mvprintw(srow++, 0,
332 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
333 label_chunk_info[i].d->name,
332 label_chunk_info[i].c->name, sz, (sz / 2048));
334 label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
335 }
336 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */
337 else {
338 char onestr[PART_OFF], num[10], *mountpoint, *newfs;
339
340 /*
341 * We copy this into a blank-padded string so that it looks like
342 * a solid bar in reverse-video
343 */
344 memset(onestr, ' ', PART_OFF - 1);
345 onestr[PART_OFF - 1] = '\0';
346 /* Go for two columns */
347 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) {
348 pcol = PART_OFF;
349 prow = CHUNK_PART_START_ROW;
350 }
351 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name,
352 strlen(label_chunk_info[i].c->name));
353 /* If it's a filesystem, display the mountpoint */
354 if (label_chunk_info[i].type == PART_FILESYSTEM) {
355 if (label_chunk_info[i].c->private == NULL) {
356 static int mnt = 0;
357 char foo[10];
358
359 /*
360 * Hmm! A partition that must have already been here.
361 * Fill in a fake mountpoint and register it
362 */
363 sprintf(foo, "/mnt%d", mnt++);
364 label_chunk_info[i].c->private =
365 new_part(foo, FALSE,label_chunk_info[i].c->size);
366 label_chunk_info[i].c->private_free = safe_free;
367 }
368 mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint;
369 newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "Y" : "N";
370 }
371 else if (label_chunk_info[i].type == PART_SWAP) {
372 mountpoint = "swap";
373 newfs = " ";
374 }
375 else if (label_chunk_info[i].type == PART_FAT) {
376 mountpoint = "DOS FAT";
377 newfs = "*";
378 }
379 else {
380 mountpoint = "<unknown>";
381 newfs = "*";
382 }
383 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
384 onestr[PART_MOUNT_COL + j] = mountpoint[j];
385 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ?
384 label_chunk_info[i].c->size / 2048 : 0);
386 label_chunk_info[i].c->size / ONE_MEG : 0);
387 memcpy(onestr + PART_SIZE_COL, num, strlen(num));
388 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
389 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
390 mvaddstr(prow, pcol, onestr);
391 ++prow;
392 }
393 if (i == here)
394 attrset(A_NORMAL);
395 }
396}
397
398static void
399print_command_summary()
400{
401 mvprintw(17, 0,
402 "The following commands are valid here (upper or lower case):");
403 mvprintw(19, 0, "C = Create Partition D = Delete Partition M = Mount Partition");
404 mvprintw(20, 0, "N = Newfs Options T = Toggle Newfs ESC = Exit this screen");
405 mvprintw(21, 0, "The default target will be displayed in ");
406
407 attrset(A_REVERSE);
408 addstr("reverse video.");
409 attrset(A_NORMAL);
410 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to move.");
411 move(0, 0);
412}
413
414int
415diskLabelEditor(char *str)
416{
417 int sz, key = 0;
418 Boolean labeling;
419 char *msg = NULL;
420 PartInfo *p;
421 PartType type;
422
423 labeling = TRUE;
424 keypad(stdscr, TRUE);
425 record_label_chunks();
426
427 if (!getenv(DISK_PARTITIONED)) {
428 msgConfirm("You need to partition your disk(s) before you can assign disk labels.");
429 return 0;
430 }
429 clear();
431 dialog_clear(); clear();
432 while (labeling) {
433 clear();
434 print_label_chunks();
435 print_command_summary();
436 if (msg) {
437 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
438 beep();
439 msg = NULL;
440 }
441 refresh();
442 key = toupper(getch());
443 switch (key) {
444
445 case KEY_UP:
446 case '-':
447 if (here != 0)
448 --here;
449 break;
450
451 case KEY_DOWN:
452 case '+':
453 case '\r':
454 case '\n':
455 if (label_chunk_info[here + 1].d)
456 ++here;
457 break;
458
459 case KEY_HOME:
460 here = 0;
461 break;
462
463 case KEY_END:
464 while (label_chunk_info[here + 1].d)
465 ++here;
466 break;
467
468 case KEY_F(1):
469 case '?':
470 systemDisplayFile("disklabel.hlp");
471 break;
472
473 case 'C':
474 if (label_chunk_info[here].type != PART_SLICE) {
475 msg = "You can only do this in a master partition (see top of screen)";
476 break;
477 }
478 sz = space_free(label_chunk_info[here].c);
479 if (sz <= FS_MIN_SIZE) {
480 msg = "Not enough space to create additional FreeBSD partition";
481 break;
482 }
483 {
481 char *val, *cp, tmpb[20];
482 int size;
483 struct chunk *tmp;
484 u_long flags = 0;
484 char *val, *cp, tmpb[20];
485 int size;
486 struct chunk *tmp;
487 u_long flags = 0;
488
486 snprintf(tmpb, 20, "%d", sz);
487 val = msgGetInput(tmpb, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
488 if (!val || (size = strtol(val, &cp, 0)) <= 0)
489 break;
489 snprintf(tmpb, 20, "%d", sz);
490 val = msgGetInput(tmpb, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
491 if (!val || (size = strtol(val, &cp, 0)) <= 0)
492 break;
493
491 if (*cp && toupper(*cp) == 'M')
492 size *= 2048;
494 if (sz <= FS_MIN_SIZE) {
495 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
496 break;
497 }
498 if (*cp && toupper(*cp) == 'M')
499 size *= ONE_MEG;
500
494 type = get_partition_type();
495 if (type == PART_NONE)
496 break;
497
498 if (type == PART_FILESYSTEM) {
499 if ((p = get_mountpoint(NULL)) == NULL)
501 type = get_partition_type();
502 if (type == PART_NONE)
503 break;
501 else if (!strcmp(p->mountpoint, "/"))
502 flags |= CHUNK_IS_ROOT;
503 else
504 flags &= ~CHUNK_IS_ROOT;
505 } else
506 p = NULL;
504
508 if ((flags & CHUNK_IS_ROOT)) {
509 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
510 msgConfirm("This region cannot be used for your root partition as\nthe FreeBSD boot code cannot deal with a root partition created in\nsuch a location. Please choose another location for your root\npartition and try again!");
511 break;
505 if (type == PART_FILESYSTEM) {
506 if ((p = get_mountpoint(NULL)) == NULL)
507 break;
508 else if (!strcmp(p->mountpoint, "/"))
509 flags |= CHUNK_IS_ROOT;
510 else
511 flags &= ~CHUNK_IS_ROOT;
512 } else
513 p = NULL;
514
515 if ((flags & CHUNK_IS_ROOT)) {
516 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
517 msgConfirm("This region cannot be used for your root partition as\nthe FreeBSD boot code cannot deal with a root partition created in\nsuch a location. Please choose another location for your root\npartition and try again!");
518 break;
519 }
520 if (size < ROOT_MIN_SIZE) {
521 msgConfirm("This is too small a size for a root partition. For a variety of\nreasons, root partitions should be at least %dMB in size", ROOT_MIN_SIZE / ONE_MEG);
522 break;
523 }
524 }
513 if (size < ROOT_MIN_SIZE) {
514 msgConfirm("This is too small a size for a root partition. For a variety of\nreasons, root partitions should be at least %dMB in size", ROOT_MIN_SIZE / 2048);
525 tmp = Create_Chunk_DWIM(label_chunk_info[here].d,
526 label_chunk_info[here].c,
527 size, part,
528 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
529 flags);
530 if (!tmp) {
531 msgConfirm("Unable to create the partition. Too big?");
532 break;
533 }
517 }
518 tmp = Create_Chunk_DWIM(label_chunk_info[here].d,
519 label_chunk_info[here].c,
520 size, part,
521 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
522 flags);
523 if (!tmp) {
524 msgConfirm("Unable to create the partition. Too big?");
525 break;
526 }
527 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
534 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
535 msgConfirm("This region cannot be used for your root partition as it starts\nor extends past the 1024'th cylinder mark and is thus a\npoor location to boot from. Please choose another\nlocation for your root partition and try again!");
536 Delete_Chunk(label_chunk_info[here].d, tmp);
537 break;
531 }
532 if (type != PART_SWAP) {
538 }
539 if (type != PART_SWAP) {
540 /* This is needed to tell the newfs -u about the size */
541 tmp->private = new_part(p->mountpoint,p->newfs,tmp->size);
542 safe_free(p);
536 } else {
543 } else {
544 tmp->private = p;
538 }
539 tmp->private_free = safe_free;
540 record_label_chunks();
545 }
546 tmp->private_free = safe_free;
547 record_label_chunks();
548 }
549 break;
550
551 case 'D': /* delete */
552 if (label_chunk_info[here].type == PART_SLICE) {
553 msg = MSG_NOT_APPLICABLE;
554 break;
555 }
556 else if (label_chunk_info[here].type == PART_FAT) {
557 msg = "Use the Disk Partition Editor to delete this";
558 break;
559 }
560 Delete_Chunk(label_chunk_info[here].d, label_chunk_info[here].c);
561 record_label_chunks();
562 break;
563
564 case 'M': /* mount */
565 switch(label_chunk_info[here].type) {
566 case PART_SLICE:
567 msg = MSG_NOT_APPLICABLE;
568 break;
569
570 case PART_SWAP:
571 msg = "You don't need to specify a mountpoint for a swap partition.";
572 break;
573
574 case PART_FAT:
575 case PART_FILESYSTEM:
576 p = get_mountpoint(label_chunk_info[here].c);
577 if (p) {
578 p->newfs = FALSE;
579 record_label_chunks();
580 }
581 break;
582
583 default:
584 msgFatal("Bogus partition under cursor???");
585 break;
586 }
587 break;
588
589 case 'N': /* Set newfs options */
590 if (label_chunk_info[here].c->private &&
591 ((PartInfo *)label_chunk_info[here].c->private)->newfs)
592 getNewfsCmd(label_chunk_info[here].c->private);
593 else
594 msg = MSG_NOT_APPLICABLE;
595 break;
596
597 case 'T': /* Toggle newfs state */
598 if (label_chunk_info[here].type == PART_FILESYSTEM &&
599 label_chunk_info[here].c->private) {
600 PartInfo *pi = ((PartInfo *)
601 label_chunk_info[here].c->private);
602 label_chunk_info[here].c->private = new_part(
603 pi->mountpoint,
604 !pi->newfs,
605 label_chunk_info[here].c->size);
606 safe_free(pi);
607 }
608 else
609 msg = MSG_NOT_APPLICABLE;
610 break;
611
612 case 'W':
613 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\nThis is an entirely undocumented feature which you are not\nexpected to understand!")) {
614 int i;
615 Device **devs;
616
617 dialog_clear();
618 end_dialog();
619 DialogActive = FALSE;
620 devs = deviceFind(NULL, DEVICE_TYPE_DISK);
621 if (!devs) {
622 msgConfirm("Can't find any disk devicse!");
623 break;
624 }
625 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
626 if (devs[i]->enabled)
627 slice_wizard(((Disk *)devs[i]->private));
628 }
629 DialogActive = TRUE;
630 dialog_clear();
631 record_label_chunks();
632 }
633 else
634 msg = "A most prudent choice!";
635 break;
636
637 case 27: /* ESC */
638 labeling = FALSE;
639 break;
640
641 default:
642 beep();
643 msg = "Type F1 or ? for help";
644 break;
645 }
646 }
647 variable_set2(DISK_LABELLED, "yes");
648 dialog_clear();
642 refresh();
649 return 0;
650}
651
652
653