]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/disks.c
Oh bollocks, I really screwed up the "auto" check here. Time
[FreeBSD/FreeBSD.git] / release / sysinstall / disks.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last program in the `sysinstall' line - the next
5  * generation being essentially a complete rewrite.
6  *
7  * $FreeBSD$
8  *
9  * Copyright (c) 1995
10  *      Jordan Hubbard.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer,
17  *    verbatim and that no modifications are made prior to this
18  *    point in the file.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36
37 #include "sysinstall.h"
38 #include <ctype.h>
39 #include <fcntl.h>
40 #include <sys/stat.h>
41 #include <sys/disklabel.h>
42
43 /* Where we start displaying chunk information on the screen */
44 #define CHUNK_START_ROW         5
45
46 /* Where we keep track of MBR chunks */
47 static struct chunk *chunk_info[16];
48 static int current_chunk;
49
50 static void     diskPartitionNonInteractive(Device *dev);
51
52 static void
53 record_chunks(Disk *d)
54 {
55     struct chunk *c1 = NULL;
56     int i = 0;
57     int last_free = 0;
58
59     if (!d->chunks)
60         msgFatal("No chunk list found for %s!", d->name);
61
62     for (c1 = d->chunks->part; c1; c1 = c1->next) {
63         if (c1->type == unused && c1->size > last_free) {
64             last_free = c1->size;
65             current_chunk = i;
66         }
67         chunk_info[i++] = c1;
68     }
69     chunk_info[i] = NULL;
70     if (current_chunk >= i)
71         current_chunk = i - 1;
72 }
73
74 static int Total;
75
76 static void
77 print_chunks(Disk *d)
78 {
79     int row;
80     int i;
81
82     for (i = Total = 0; chunk_info[i]; i++)
83         Total += chunk_info[i]->size;
84     if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) {
85         dialog_clear_norefresh();
86         msgConfirm("WARNING:  A geometry of %d/%d/%d for %s is incorrect.  Using\n"
87                    "a more likely geometry.  If this geometry is incorrect or you\n"
88                    "are unsure as to whether or not it's correct, please consult\n"
89                    "the Hardware Guide in the Documentation submenu or use the\n"
90                    "(G)eometry command to change it now.\n\n"
91                    "Remember: you need to enter whatever your BIOS thinks the\n"
92                    "geometry is!  For IDE, it's what you were told in the BIOS\n"
93                    "setup. For SCSI, it's the translation mode your controller is\n"
94                    "using.  Do NOT use a ``physical geometry''.",
95           d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
96         Sanitize_Bios_Geom(d);
97     }
98     attrset(A_NORMAL);
99     mvaddstr(0, 0, "Disk name:\t");
100     clrtobot();
101     attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
102     attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
103     mvprintw(1, 0,
104              "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors",
105              d->bios_cyl, d->bios_hd, d->bios_sect,
106              d->bios_cyl * d->bios_hd * d->bios_sect);
107     mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s",
108              "Offset", "Size", "End", "Name", "PType", "Desc",
109              "Subtype", "Flags");
110     for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
111         if (i == current_chunk)
112             attrset(ATTR_SELECTED);
113         mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s",
114                  chunk_info[i]->offset, chunk_info[i]->size,
115                  chunk_info[i]->end, chunk_info[i]->name,
116                  chunk_info[i]->type, 
117                  slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype),
118                  chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
119         if (i == current_chunk)
120             attrset(A_NORMAL);
121     }
122 }
123
124 static void
125 print_command_summary()
126 {
127     mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
128     mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan       C = Create Slice");
129     mvprintw(17, 0, "D = Delete Slice       G = Set Drive Geometry   S = Set Bootable");
130     mvprintw(18, 0, "T = Change Type        U = Undo All Changes     Q = Finish");
131     if (!RunningAsInit)
132         mvprintw(18, 48, "W = Write Changes");
133     mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
134     move(0, 0);
135 }
136
137 static u_char *
138 getBootMgr(char *dname)
139 {
140 #ifndef __alpha__       /* only meaningful on x86 */
141     extern u_char mbr[], boot0[];
142     char str[80];
143     char *cp;
144     int i = 0;
145
146     cp = variable_get(VAR_BOOTMGR);
147     if (!cp) {
148         /* Figure out what kind of MBR the user wants */
149         sprintf(str, "Install Boot Manager for drive %s?", dname);
150         MenuMBRType.title = str;
151         i = dmenuOpenSimple(&MenuMBRType, FALSE);
152     }
153     else {
154         if (!strncmp(cp, "boot", 4))
155             BootMgr = 0;
156         else if (!strcmp(cp, "standard"))
157             BootMgr = 1;
158         else
159             BootMgr = 2;
160     }
161     if (cp || i) {
162         switch (BootMgr) {
163         case 0:
164             return boot0;
165
166         case 1:
167             return mbr;
168
169         case 2:
170         default:
171             break;
172         }
173     }
174 #endif
175     return NULL;
176 }
177
178 int
179 diskGetSelectCount(Device ***devs)
180 {
181     int i, cnt, enabled;
182     char *cp;
183     Device **dp;
184
185     cp = variable_get(VAR_DISK);
186     dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK);
187     cnt = deviceCount(dp);
188     if (!cnt)
189         return -1;
190     for (i = 0, enabled = 0; i < cnt; i++) {
191         if (dp[i]->enabled)
192             ++enabled;
193     }
194     return enabled;
195 }
196
197 void
198 diskPartition(Device *dev)
199 {
200     char *cp, *p;
201     int rv, key = 0;
202     Boolean chunking;
203     char *msg = NULL;
204     u_char *mbrContents;
205     WINDOW *w = savescr();
206     Disk *d = (Disk *)dev->private;
207
208     chunking = TRUE;
209     keypad(stdscr, TRUE);
210
211     /* Flush both the dialog and curses library views of the screen
212        since we don't always know who called us */
213     dialog_clear_norefresh(), clear();
214     current_chunk = 0;
215
216     /* Set up the chunk array */
217     record_chunks(d);
218
219     while (chunking) {
220         char *val, geometry[80];
221             
222         /* Now print our overall state */
223         if (d)
224             print_chunks(d);
225         print_command_summary();
226         if (msg) {
227             attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
228             beep();
229             msg = NULL;
230         }
231         else {
232             move(23, 0);
233             clrtoeol();
234         }
235
236         /* Get command character */
237         key = getch();
238         switch (toupper(key)) {
239         case '\014':    /* ^L (redraw) */
240             clear();
241             msg = NULL;
242             break;
243             
244         case '\020':    /* ^P */
245         case KEY_UP:
246         case '-':
247             if (current_chunk != 0)
248                 --current_chunk;
249             break;
250             
251         case '\016':    /* ^N */
252         case KEY_DOWN:
253         case '+':
254         case '\r':
255         case '\n':
256             if (chunk_info[current_chunk + 1])
257                 ++current_chunk;
258             break;
259
260         case KEY_HOME:
261             current_chunk = 0;
262             break;
263
264         case KEY_END:
265             while (chunk_info[current_chunk + 1])
266                 ++current_chunk;
267             break;
268
269         case KEY_F(1):
270         case '?':
271             systemDisplayHelp("slice");
272             clear();
273             break;
274
275         case 'A':
276 #ifdef __alpha__
277             rv = 1;
278 #else       /* The rest is only relevant on x86 */
279             cp = variable_get(VAR_DEDICATE_DISK);
280             if (cp && !strcasecmp(cp, "always"))
281                 rv = 1;
282             else {
283                 rv = msgYesNo("Do you want to do this with a true partition entry\n"
284                               "so as to remain cooperative with any future possible\n"
285                               "operating systems on the drive(s)?\n"
286                               "(See also the section about ``dangerously dedicated''\n"
287                               "disks in the FreeBSD FAQ.)");
288                 if (rv == -1)
289                     rv = 0;
290             }
291 #endif
292             All_FreeBSD(d, rv);
293             variable_set2(DISK_PARTITIONED, "yes", 0);
294             record_chunks(d);
295             clear();
296             break;
297             
298         case 'B':
299             if (chunk_info[current_chunk]->type != freebsd)
300                 msg = "Can only scan for bad blocks in FreeBSD slice.";
301             else if (strncmp(d->name, "sd", 2) ||
302                      strncmp(d->name, "da", 2) ||
303                      !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
304                                "Are you sure you want to do this on a SCSI disk?")) {
305                 if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
306                     chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
307                 else
308                     chunk_info[current_chunk]->flags |= CHUNK_BAD144;
309             }
310             clear();
311             break;
312             
313         case 'C':
314             if (chunk_info[current_chunk]->type != unused)
315                 msg = "Slice in use, delete it first or move to an unused one.";
316             else {
317                 char *val, tmp[20], *cp;
318                 int size, subtype;
319                 chunk_e partitiontype;
320                 
321                 snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size);
322                 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
323                                   "or append a trailing `M' for megabytes (e.g. 20M).");
324                 if (val && (size = strtol(val, &cp, 0)) > 0) {
325                     if (*cp && toupper(*cp) == 'M')
326                         size *= ONE_MEG;
327                     strcpy(tmp, "165");
328                     val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
329                                       "Pressing Enter will choose the default, a native FreeBSD\n"
330                                       "slice (type 165).  You can choose other types, 6 for a\n"
331                                       "DOS partition or 131 for a Linux partition, for example.\n\n"
332                                       "Note:  If you choose a non-FreeBSD partition type, it will not\n"
333                                       "be formatted or otherwise prepared, it will simply reserve space\n"
334                                       "for you to use another tool, such as DOS FORMAT, to later format\n"
335                                       "and use the partition.");
336                     if (val && (subtype = strtol(val, NULL, 0)) > 0) {
337                         if (subtype == 165)
338                             partitiontype = freebsd;
339                         else if (subtype == 6)
340                             partitiontype = fat;
341                         else
342                             partitiontype = unknown;
343 #ifdef __alpha__
344                         if (partitiontype == freebsd && size == chunk_info[current_chunk]->size)
345                             All_FreeBSD(d, 1);
346                         else
347 #endif
348                         Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
349                                      (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
350                         variable_set2(DISK_PARTITIONED, "yes", 0);
351                         record_chunks(d);
352                     }
353                 }
354                 clear();
355             }
356             break;
357             
358         case KEY_DC:
359         case 'D':
360             if (chunk_info[current_chunk]->type == unused)
361                 msg = "Slice is already unused!";
362             else {
363                 Delete_Chunk(d, chunk_info[current_chunk]);
364                 variable_set2(DISK_PARTITIONED, "yes", 0);
365                 record_chunks(d);
366             }
367             break;
368             
369         case 'T':
370             if (chunk_info[current_chunk]->type == unused)
371                 msg = "Slice is currently unused (use create instead)";
372             else {
373                 char *val, tmp[20];
374                 int subtype;
375                 chunk_e partitiontype;
376                 WINDOW *save = savescr();
377
378                 strcpy(tmp, "165");
379                 val = msgGetInput(tmp, "New partition type:\n\n"
380                                   "Pressing Enter will choose the default, a native FreeBSD\n"
381                                   "slice (type 165).  Other popular values are 6 for\n"
382                                   "DOS FAT partition, 131 for a Linux ext2fs partition or\n"
383                                   "130 for a Linux swap partition.\n\n"
384                                   "Note:  If you choose a non-FreeBSD partition type, it will not\n"
385                                   "be formatted or otherwise prepared, it will simply reserve space\n"
386                                   "for you to use another tool, such as DOS format, to later format\n"
387                                   "and actually use the partition.");
388                 if (val && (subtype = strtol(val, NULL, 0)) > 0) {
389                     if (subtype == 165)
390                         partitiontype = freebsd;
391                     else if (subtype == 6)
392                         partitiontype = fat;
393                     else
394                         partitiontype = unknown;
395                     chunk_info[current_chunk]->type = partitiontype;
396                     chunk_info[current_chunk]->subtype = subtype;
397                 }
398                 restorescr(save);
399             }
400             break;
401             
402         case 'G':
403             snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
404             val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
405                               "Don't forget to use the two slash (/) separator characters!\n"
406                               "It's not possible to parse the field without them.");
407             if (val) {
408                 long nc, nh, ns;
409                 nc = strtol(val, &val, 0);
410                 nh = strtol(val + 1, &val, 0);
411                 ns = strtol(val + 1, 0, 0);
412                 Set_Bios_Geom(d, nc, nh, ns);
413             }
414             clear();
415             break;
416         
417         case 'S':
418             /* Set Bootable */
419             chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
420             break;
421         
422         case 'U':
423             if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
424                 msgConfirm("You've already written this information out - you\n"
425                            "can't undo it.");
426             }
427             else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
428                 char cp[BUFSIZ];
429
430                 sstrncpy(cp, d->name, sizeof cp);
431                 Free_Disk(dev->private);
432                 d = Open_Disk(cp);
433                 if (!d)
434                     msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
435                 dev->private = d;
436                 variable_unset(DISK_PARTITIONED);
437                 variable_unset(DISK_LABELLED);
438                 if (d)
439                     record_chunks(d);
440             }
441             clear();
442             break;
443
444         case 'W':
445             if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
446                                "installation.  If you are installing FreeBSD for the first time\n"
447                                "then you should simply type Q when you're finished here and your\n"
448                                "changes will be committed in one batch automatically at the end of\n"
449                                "these questions.  If you're adding a disk, you should NOT write\n"
450                                "from this screen, you should do it from the label editor.\n\n"
451                                "Are you absolutely sure you want to do this now?")) {
452                 variable_set2(DISK_PARTITIONED, "yes", 0);
453                 
454                 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
455                  * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
456                  * booteasy or a "standard" MBR -- both would be fatal in this case.
457                  */
458                 /*
459                  * Don't offer to update the MBR on this disk if the first "real" chunk looks like
460                  * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
461                  */
462                 if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)))
463                     mbrContents = getBootMgr(d->name);
464                 else
465                     mbrContents = NULL;
466                 Set_Boot_Mgr(d, mbrContents);
467
468                 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
469                     msgConfirm("Disk partition write returned an error status!");
470                 else
471                     msgConfirm("Wrote FDISK partition information out successfully.");
472             }
473             clear();
474             break;
475             
476         case '|':
477             if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
478                           "No seat belts whatsoever are provided!")) {
479                 clear();
480                 refresh();
481                 slice_wizard(d);
482                 variable_set2(DISK_PARTITIONED, "yes", 0);
483                 record_chunks(d);
484             }
485             else
486                 msg = "Wise choice!";
487             clear();
488             break;
489
490         case '\033':    /* ESC */
491         case 'Q':
492             chunking = FALSE;
493             /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
494              * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
495              * booteasy or a "standard" MBR -- both would be fatal in this case.
496              */
497 #if 0
498             if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
499                 && (mbrContents = getBootMgr(d->name)) != NULL)
500                 Set_Boot_Mgr(d, mbrContents);
501 #else
502             /*
503              * Don't offer to update the MBR on this disk if the first "real" chunk looks like
504              * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD. 
505              */
506             if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
507                 (mbrContents = getBootMgr(d->name)) != NULL)
508                 Set_Boot_Mgr(d, mbrContents);
509 #endif
510             break;
511             
512         default:
513             beep();
514             msg = "Type F1 or ? for help";
515             break;
516         }
517     }
518     p = CheckRules(d);
519     if (p) {
520         char buf[FILENAME_MAX];
521         
522         dialog_clear_norefresh();
523         use_helpline("Press F1 to read more about disk slices.");
524         use_helpfile(systemHelpFile("partition", buf));
525         if (!variable_get(VAR_NO_WARN))
526             dialog_mesgbox("Disk slicing warning:", p, -1, -1);
527         free(p);
528     }
529     restorescr(w);
530 }
531
532 static u_char *
533 bootalloc(char *name)
534 {
535     char buf[FILENAME_MAX];
536     struct stat sb;
537
538     snprintf(buf, sizeof buf, "/boot/%s", name);
539     if (stat(buf, &sb) != -1) {
540         int fd;
541
542         fd = open(buf, O_RDONLY);
543         if (fd != -1) {
544             u_char *cp;
545
546             cp = malloc(sb.st_size);
547             if (read(fd, cp, sb.st_size) != sb.st_size) {
548                 free(cp);
549                 close(fd);
550                 msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf);
551                 return NULL;
552             }
553             close(fd);
554             return cp;
555         }
556         msgDebug("bootalloc: couldn't open %s\n", buf);
557     }
558     else
559         msgDebug("bootalloc: can't stat %s\n", buf);
560     return NULL;
561 }
562         
563 static int
564 partitionHook(dialogMenuItem *selected)
565 {
566     Device **devs = NULL;
567
568     devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
569     if (!devs) {
570         msgConfirm("Unable to find disk %s!", selected->prompt);
571         return DITEM_FAILURE;
572     }
573     /* Toggle enabled status? */
574     if (!devs[0]->enabled) {
575         devs[0]->enabled = TRUE;
576         diskPartition(devs[0]);
577     }
578     else
579         devs[0]->enabled = FALSE;
580     return DITEM_SUCCESS | DITEM_RESTORE;
581 }
582
583 static int
584 partitionCheck(dialogMenuItem *selected)
585 {
586     Device **devs = NULL;
587
588     devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
589     if (!devs || devs[0]->enabled == FALSE)
590         return FALSE;
591     return TRUE;
592 }
593
594 int
595 diskPartitionEditor(dialogMenuItem *self)
596 {
597     DMenu *menu;
598     Device **devs;
599     int i, cnt, devcnt;
600
601     cnt = diskGetSelectCount(&devs);
602     devcnt = deviceCount(devs);
603     if (cnt == -1) {
604         msgConfirm("No disks found!  Please verify that your disk controller is being\n"
605                    "properly probed at boot time.  See the Hardware Guide on the\n"
606                    "Documentation menu for clues on diagnosing this type of problem.");
607         return DITEM_FAILURE;
608     }
609     else if (cnt) {
610         /* Some are already selected */
611         for (i = 0; i < devcnt; i++) {
612             if (devs[i]->enabled) {
613                 if (variable_get(VAR_NONINTERACTIVE))
614                     diskPartitionNonInteractive(devs[i]);
615                 else
616                     diskPartition(devs[i]);
617             }
618         }
619     }
620     else {
621         /* No disks are selected, fall-back case now */
622         if (devcnt == 1) {
623             devs[0]->enabled = TRUE;
624             if (variable_get(VAR_NONINTERACTIVE))
625                 diskPartitionNonInteractive(devs[0]);
626             else
627                 diskPartition(devs[0]);
628             return DITEM_SUCCESS;
629         }
630         else {
631             menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
632             if (!menu) {
633                 msgConfirm("No devices suitable for installation found!\n\n"
634                            "Please verify that your disk controller (and attached drives)\n"
635                            "were detected properly.  This can be done by pressing the\n"
636                            "[Scroll Lock] key and using the Arrow keys to move back to\n"
637                            "the boot messages.  Press [Scroll Lock] again to return.");
638                 return DITEM_FAILURE;
639             }
640             else {
641                 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
642                 free(menu);
643             }
644             return i | DITEM_RESTORE;
645         }
646     }
647     return DITEM_SUCCESS;
648 }
649
650 int
651 diskPartitionWrite(dialogMenuItem *self)
652 {
653     Device **devs;
654     int i;
655     char *cp;
656
657     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
658     if (!devs) {
659         msgConfirm("Unable to find any disks to write to??");
660         return DITEM_FAILURE;
661     }
662     if (isDebug())
663         msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
664     cp = variable_get(DISK_PARTITIONED);
665     if (cp && !strcmp(cp, "written"))
666         return DITEM_SUCCESS;
667
668     for (i = 0; devs[i]; i++) {
669         Chunk *c1;
670         Disk *d = (Disk *)devs[i]->private;
671         static u_char *boot1;
672 #ifndef __alpha__
673         static u_char *boot2;
674 #endif
675
676         if (!devs[i]->enabled)
677             continue;
678
679 #ifdef __alpha__
680         if (!boot1) boot1 = bootalloc("boot1");
681         Set_Boot_Blocks(d, boot1, NULL);
682 #else
683         if (!boot1) boot1 = bootalloc("boot1");
684         if (!boot2) boot2 = bootalloc("boot2");
685         Set_Boot_Blocks(d, boot1, boot2);
686 #endif
687
688         msgNotify("Writing partition information to drive %s", d->name);
689         if (!Fake && Write_Disk(d)) {
690             msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
691             return DITEM_FAILURE;
692         }
693
694         /* If we've been through here before, we don't need to do the rest */
695         if (cp && !strcmp(cp, "written"))
696             return DITEM_SUCCESS;
697
698         /* Now scan for bad blocks, if necessary */
699         for (c1 = d->chunks->part; c1; c1 = c1->next) {
700             if (c1->flags & CHUNK_BAD144) {
701                 int ret;
702
703                 msgNotify("Running bad block scan on slice %s", c1->name);
704                 if (!Fake) {
705                     ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
706                     if (ret)
707                         msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
708                     ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
709                     if (ret)
710                         msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
711                 }
712             }
713         }
714     }
715     /* Now it's not "yes", but "written" */
716     variable_set2(DISK_PARTITIONED, "written", 0);
717     return DITEM_SUCCESS;
718 }
719
720 /* Partition a disk based wholly on which variables are set */
721 static void
722 diskPartitionNonInteractive(Device *dev)
723 {
724     char *cp;
725     int i, sz, all_disk = 0;
726     u_char *mbrContents;
727     Disk *d = (Disk *)dev->private;
728
729     record_chunks(d);
730     cp = variable_get(VAR_GEOMETRY);
731     if (cp) {
732         msgDebug("Setting geometry from script to: %s\n", cp);
733         d->bios_cyl = strtol(cp, &cp, 0);
734         d->bios_hd = strtol(cp + 1, &cp, 0);
735         d->bios_sect = strtol(cp + 1, 0, 0);
736     }
737
738     cp = variable_get(VAR_PARTITION);
739     if (cp) {
740         if (!strcmp(cp, "free")) {
741             /* Do free disk space case */
742             for (i = 0; chunk_info[i]; i++) {
743                 /* If a chunk is at least 10MB in size, use it. */
744                 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
745                     Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
746                                  (chunk_info[i]->flags & CHUNK_ALIGN));
747                     variable_set2(DISK_PARTITIONED, "yes", 0);
748                     break;
749                 }
750             }
751             if (!chunk_info[i]) {
752                 dialog_clear();
753                 msgConfirm("Unable to find any free space on this disk!");
754                 return;
755             }
756         }
757         else if (!strcmp(cp, "all")) {
758             /* Do all disk space case */
759             msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
760
761             All_FreeBSD(d, FALSE);
762         }
763         else if (!strcmp(cp, "exclusive")) {
764             /* Do really-all-the-disk-space case */
765             msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
766
767             All_FreeBSD(d, all_disk = TRUE);
768         }
769         else if ((sz = strtol(cp, &cp, 0))) {
770             /* Look for sz bytes free */
771             if (*cp && toupper(*cp) == 'M')
772                 sz *= ONE_MEG;
773             for (i = 0; chunk_info[i]; i++) {
774                 /* If a chunk is at least sz MB, use it. */
775                 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
776                     Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
777                     variable_set2(DISK_PARTITIONED, "yes", 0);
778                     break;
779                 }
780             }
781             if (!chunk_info[i]) {
782                 dialog_clear();
783                 msgConfirm("Unable to find %d free blocks on this disk!", sz);
784                 return;
785             }
786         }
787         else if (!strcmp(cp, "existing")) {
788             /* Do existing FreeBSD case */
789             for (i = 0; chunk_info[i]; i++) {
790                 if (chunk_info[i]->type == freebsd)
791                     break;
792             }
793             if (!chunk_info[i]) {
794                 dialog_clear();
795                 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
796                 return;
797             }
798         }
799         else {
800             dialog_clear();
801             msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
802             return;
803         }
804         if (!all_disk) {
805             mbrContents = getBootMgr(d->name);
806             Set_Boot_Mgr(d, mbrContents);
807         }
808         variable_set2(DISK_PARTITIONED, "yes", 0);
809     }
810 }