Fixed a potential strict aliasing bug.
[AROS.git] / workbench / c / Install-grub2-i386-pc.c
blob27ee87297344c6fd697ed6058ce53babdaacbbb4
1 /*
2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /******************************************************************************
8 NAME
10 Install-grub2-i386-pc
12 SYNOPSIS
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
16 LOCATION
20 FUNCTION
22 Installs the GRUB 2 bootloader to the boot block of the specified
23 disk or partition.
25 INPUTS
27 DEVICE -- Device name (e.g. ata.device)
28 UNIT -- Unit number
29 PN -- Specifies a partition number. If specified, GRUB is installed
30 to this partition's boot block. Otherwise, GRUB is installed to
31 the disk's boot block.
32 GRUB -- Path to GRUB directory.
33 FORCELBA -- Force use of LBA mode.
35 RESULT
37 NOTES
39 EXAMPLE
41 Install-grub2-i386-pc DEVICE ata.device UNIT 0 GRUB DH0:boot/grub
43 BUGS
45 SEE ALSO
47 Partition, SYS:System/Format
49 INTERNALS
51 ******************************************************************************/
53 #define DEBUG 0
54 #include <aros/debug.h>
56 #include <string.h>
57 #include <proto/exec.h>
58 #include <proto/dos.h>
59 #include <proto/partition.h>
60 #include <proto/utility.h>
61 #include <aros/macros.h>
62 #include <devices/hardblocks.h>
63 #include <devices/newstyle.h>
64 #include <exec/errors.h>
65 #include <exec/memory.h>
66 #include <libraries/partition.h>
70 /* Defines for grub2 data */
71 /* boot.img pointers */
72 #define GRUB_BOOT_MACHINE_BPB_START 0x03
73 #define GRUB_BOOT_MACHINE_BPB_END 0x5a
74 #define GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC 0x01b8 /* Following grub2 grub-setup sources */
75 #define GRUB_BOOT_MACHINE_PART_START 0x01be
76 #define GRUB_BOOT_MACHINE_PART_END 0x01fe
77 #define GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x5c
78 #define GRUB_BOOT_MACHINE_BOOT_DRIVE 0x64
79 #define GRUB_BOOT_MACHINE_DRIVE_CHECK 0x66
81 /* core.img pointers */
82 #define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART 0x14
83 #define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18
85 /* BIOS drive flag */
86 #define BIOS_HDISK_FLAG 0x80
88 #define MBR_MAX_PARTITIONS 4
89 #define MBRT_EXTENDED 0x05
90 #define MBRT_EXTENDED2 0x0f
91 #define BLCKLIST_ELEMENTS 14
93 struct Volume
95 struct MsgPort *mp;
96 struct IOExtTD *iotd;
97 ULONG readcmd;
98 ULONG writecmd;
99 ULONG startblock;
100 ULONG countblock;
101 CONST_STRPTR device;
102 ULONG unitnum;
103 UWORD SizeBlock;
104 UBYTE flags;
105 BYTE partnum;
106 ULONG *blockbuffer;
107 ULONG dos_id;
110 #define VF_IS_TRACKDISK (1<<0)
111 #define VF_IS_RDB (1<<1)
113 struct BlockNode
115 ULONG sector_lo;
116 ULONG sector_hi;
117 UWORD count;
118 UWORD seg_adr;
121 const TEXT version[] = "$VER: Install-grub2-i386-pc 41.3 (3.9.2009)";
123 CONST_STRPTR CORE_IMG_FILE_NAME = "core.img";
125 STRPTR template =
126 (STRPTR) ("DEVICE/A," "UNIT/N/K/A," "PARTITIONNUMBER=PN/K/N," "GRUB/K/A,"
127 "FORCELBA/S");
129 IPTR myargs[7] = { 0, 0, 0, 0, 0, 0 };
131 struct FileSysStartupMsg *getDiskFSSM(CONST_STRPTR path)
133 struct DosList *dl;
134 struct DeviceNode *dn;
135 TEXT dname[32];
136 UBYTE i;
138 D(bug("[install] getDiskFSSM('%s')\n", path));
140 for (i = 0; (path[i]) && (path[i] != ':'); i++)
141 dname[i] = path[i];
142 if (path[i] == ':')
144 dname[i] = 0;
145 dl = LockDosList(LDF_READ);
146 if (dl)
148 dn = (struct DeviceNode *) FindDosEntry(dl, dname, LDF_DEVICES);
149 UnLockDosList(LDF_READ);
150 if (dn)
152 dname[i] = ':';
153 dname[i + 1] = '\0';
154 if (IsFileSystem(dname))
156 return (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
158 else
159 Printf("device '%s' doesn't contain a file system\n",
160 dname);
162 else
163 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
166 else
167 Printf("'%s' doesn't contain a device name\n", path);
168 return 0;
171 void fillGeometry(struct Volume *volume, struct DosEnvec *de)
173 ULONG spc;
175 D(bug("[install] fillGeometry(%x)\n", volume));
177 spc = de->de_Surfaces * de->de_BlocksPerTrack;
178 volume->SizeBlock = de->de_SizeBlock;
179 volume->startblock = de->de_LowCyl * spc;
180 volume->countblock =
181 ((de->de_HighCyl - de->de_LowCyl + 1) * spc) - 1 + de->de_Reserved;
184 void nsdCheck(struct Volume *volume)
186 struct NSDeviceQueryResult nsdq;
187 UWORD *cmdcheck;
189 D(bug("[install] nsdCheck(%x)\n", volume));
191 if (((volume->startblock + volume->countblock) * /* last block */
192 ((volume->SizeBlock << 2) / 512) /* 1 portion (block) equals 512 (bytes) */
193 ) > 8388608)
195 nsdq.SizeAvailable = 0;
196 nsdq.DevQueryFormat = 0;
197 volume->iotd->iotd_Req.io_Command = NSCMD_DEVICEQUERY;
198 volume->iotd->iotd_Req.io_Data = &nsdq;
199 volume->iotd->iotd_Req.io_Length = sizeof(struct NSDeviceQueryResult);
200 if (DoIO((struct IORequest *) &volume->iotd->iotd_Req) == IOERR_NOCMD)
202 Printf("Device doesn't understand NSD-Query\n");
204 else
206 if ((volume->iotd->iotd_Req.io_Actual >
207 sizeof(struct NSDeviceQueryResult))
208 || (volume->iotd->iotd_Req.io_Actual == 0)
209 || (volume->iotd->iotd_Req.io_Actual != nsdq.SizeAvailable))
211 Printf("WARNING wrong io_Actual using NSD\n");
213 else
215 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
216 Printf("WARNING no trackdisk type\n");
217 for (cmdcheck = nsdq.SupportedCommands; *cmdcheck; cmdcheck++)
219 if (*cmdcheck == NSCMD_TD_READ64)
220 volume->readcmd = NSCMD_TD_READ64;
221 if (*cmdcheck == NSCMD_TD_WRITE64);
222 volume->writecmd = NSCMD_TD_WRITE64;
224 if ((volume->readcmd != NSCMD_TD_READ64) ||
225 (volume->writecmd != NSCMD_TD_WRITE64))
226 Printf("WARNING no READ64/WRITE64\n");
232 struct Volume *initVolume(CONST_STRPTR device, ULONG unit, ULONG flags,
233 struct DosEnvec *de)
235 struct Volume *volume;
236 LONG error = 0;
238 D(bug("[install] initVolume(%s:%d)\n", device, unit));
240 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
241 if (volume)
243 volume->mp = CreateMsgPort();
244 if (volume->mp)
246 volume->iotd =
247 (struct IOExtTD *) CreateIORequest(volume->mp,
248 sizeof(struct IOExtTD));
249 if (volume->iotd)
251 volume->blockbuffer =
252 AllocVec(de->de_SizeBlock << 2, MEMF_PUBLIC | MEMF_CLEAR);
253 if (volume->blockbuffer)
255 if (OpenDevice
256 (device,
257 unit, (struct IORequest *) volume->iotd, flags) == 0)
259 if (strcmp((const char *) device, TD_NAME) == 0)
260 volume->flags |= VF_IS_TRACKDISK;
261 else
262 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
263 volume->readcmd = CMD_READ;
264 volume->writecmd = CMD_WRITE;
265 volume->device = device;
266 volume->unitnum = unit;
267 volume->dos_id = 0;
268 fillGeometry(volume, de);
269 nsdCheck(volume);
270 return volume;
272 else
273 error = ERROR_NO_FREE_STORE;
274 FreeVec(volume->blockbuffer);
276 else
277 error = ERROR_NO_FREE_STORE;
278 DeleteIORequest((struct IORequest *) volume->iotd);
280 else
281 error = ERROR_NO_FREE_STORE;
282 DeleteMsgPort(volume->mp);
284 else
285 error = ERROR_NO_FREE_STORE;
286 FreeVec(volume);
288 else
289 error = ERROR_NO_FREE_STORE;
291 PrintFault(error, NULL);
292 return NULL;
295 void uninitVolume(struct Volume *volume)
297 D(bug("[install] uninitVolume(%x)\n", volume));
299 CloseDevice((struct IORequest *) volume->iotd);
300 FreeVec(volume->blockbuffer);
301 DeleteIORequest((struct IORequest *) volume->iotd);
302 DeleteMsgPort(volume->mp);
303 FreeVec(volume);
306 static ULONG _readwriteBlock(struct Volume *volume,
307 ULONG block, APTR buffer, ULONG length,
308 ULONG command)
310 UQUAD offset;
311 ULONG retval = 0;
313 volume->iotd->iotd_Req.io_Command = command;
314 volume->iotd->iotd_Req.io_Length = length;
315 volume->iotd->iotd_Req.io_Data = buffer;
316 offset = (UQUAD) (volume->startblock + block) * (volume->SizeBlock << 2);
317 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
318 volume->iotd->iotd_Req.io_Actual = offset >> 32;
319 retval = DoIO((struct IORequest *) &volume->iotd->iotd_Req);
320 if (volume->flags & VF_IS_TRACKDISK)
322 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
323 volume->iotd->iotd_Req.io_Length = 0;
324 DoIO((struct IORequest *) &volume->iotd->iotd_Req);
326 return retval;
329 ULONG readBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
331 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
332 volume, block, size));
334 return _readwriteBlock(volume, block, buffer, size, volume->readcmd);
337 ULONG writeBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
339 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
340 volume, block, size));
342 return _readwriteBlock(volume, block, buffer, size, volume->writecmd);
345 static BOOL isKnownFs(ULONG dos_id)
347 switch (dos_id)
349 case ID_FFS_DISK:
350 case ID_INTER_DOS_DISK:
351 case ID_INTER_FFS_DISK:
352 case ID_FASTDIR_DOS_DISK:
353 case ID_FASTDIR_FFS_DISK:
354 case ID_SFS_BE_DISK:
355 case ID_SFS_LE_DISK:
356 return TRUE;
359 return FALSE;
362 BOOL isvalidFileSystem(struct Volume * volume, CONST_STRPTR device,
363 ULONG unit)
365 BOOL retval = FALSE;
366 struct PartitionBase *PartitionBase;
367 struct PartitionHandle *ph;
368 ULONG dos_id;
370 D(bug("[install] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
372 if (readBlock(volume, 0, volume->blockbuffer, 512))
374 Printf("Read Error\n");
375 return FALSE;
378 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
380 if (!isKnownFs(dos_id))
382 /* first block has no DOS\x so we don't have RDB for sure */
383 volume->flags &= ~VF_IS_RDB;
384 if (readBlock(volume, 1, volume->blockbuffer, 512))
386 Printf("Read Error\n");
387 return FALSE;
390 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
392 if (!isKnownFs(dos_id))
393 return FALSE;
394 else
395 volume->dos_id = dos_id;
397 else
398 volume->dos_id = dos_id;
400 volume->partnum = -1;
402 PartitionBase =
403 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
404 "partition.library", 1);
405 if (PartitionBase)
407 ph = OpenRootPartition(device, unit);
408 if (ph)
410 if (OpenPartitionTable(ph) == 0)
412 struct TagItem tags[3];
413 IPTR type;
415 tags[1].ti_Tag = TAG_DONE;
416 tags[0].ti_Tag = PTT_TYPE;
417 tags[0].ti_Data = (STACKIPTR) & type;
418 GetPartitionTableAttrs(ph, tags);
419 if (type == PHPTT_MBR)
421 struct PartitionHandle *pn;
422 struct DosEnvec de;
423 struct PartitionHandle *extph = NULL;
424 struct PartitionType ptype = { };
426 tags[0].ti_Tag = PT_DOSENVEC;
427 tags[0].ti_Data = (STACKIPTR) & de;
428 tags[1].ti_Tag = PT_TYPE;
429 tags[1].ti_Data = (STACKIPTR) & ptype;
430 tags[2].ti_Tag = TAG_DONE;
431 pn = (struct PartitionHandle *) ph->table->list.lh_Head;
432 while (pn->ln.ln_Succ)
434 ULONG scp;
436 GetPartitionAttrs(pn, tags);
437 if (ptype.id[0] == MBRT_EXTENDED
438 || ptype.id[0] == MBRT_EXTENDED2)
439 extph = pn;
440 else
442 scp = de.de_Surfaces * de.de_BlocksPerTrack;
443 if ((volume->startblock >= (de.de_LowCyl * scp))
444 && (volume->startblock <=
445 (((de.de_HighCyl + 1) * scp) - 1)))
446 break;
448 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
450 if (pn->ln.ln_Succ)
452 tags[0].ti_Tag = PT_POSITION;
453 tags[0].ti_Data = (STACKIPTR) & type;
454 tags[1].ti_Tag = TAG_DONE;
455 GetPartitionAttrs(pn, tags);
456 volume->partnum = (UBYTE) type;
457 retval = TRUE;
458 D(bug
459 ("[install] Primary partition found: partnum=%d\n",
460 volume->partnum));
462 else if (extph != NULL)
464 if (OpenPartitionTable(extph) == 0)
466 tags[0].ti_Tag = PTT_TYPE;
467 tags[0].ti_Data = (STACKIPTR) & type;
468 tags[1].ti_Tag = TAG_DONE;
469 GetPartitionTableAttrs(extph, tags);
470 if (type == PHPTT_EBR)
472 tags[0].ti_Tag = PT_DOSENVEC;
473 tags[0].ti_Data = (STACKIPTR) & de;
474 tags[1].ti_Tag = TAG_DONE;
475 pn = (struct PartitionHandle *) extph->table->
476 list.lh_Head;
477 while (pn->ln.ln_Succ)
479 ULONG offset, scp;
481 offset = extph->de.de_LowCyl
482 * extph->de.de_Surfaces
483 * extph->de.de_BlocksPerTrack;
484 GetPartitionAttrs(pn, tags);
485 scp =
486 de.de_Surfaces * de.de_BlocksPerTrack;
487 if ((volume->startblock >=
488 offset + (de.de_LowCyl * scp))
489 && (volume->startblock <=
490 offset +
491 (((de.de_HighCyl + 1) * scp) -
492 1)))
493 break;
494 pn = (struct PartitionHandle *) pn->ln.
495 ln_Succ;
497 if (pn->ln.ln_Succ)
499 tags[0].ti_Tag = PT_POSITION;
500 tags[0].ti_Data = (STACKIPTR) & type;
501 GetPartitionAttrs(pn, tags);
502 volume->partnum =
503 MBR_MAX_PARTITIONS + (UBYTE) type;
504 retval = TRUE;
505 D(bug
506 ("[install] Logical partition found: partnum=%d\n",
507 (int) volume->partnum));
510 ClosePartitionTable(extph);
514 else
516 if (type == PHPTT_RDB)
518 /* just use whole hard disk */
519 retval = TRUE;
521 else
522 Printf
523 ("only MBR and RDB partition tables are supported\n");
525 ClosePartitionTable(ph);
527 else
529 /* just use whole hard disk */
530 retval = TRUE;
532 CloseRootPartition(ph);
534 else
535 Printf("Error OpenRootPartition(%s,%lu)\n", device, (long)unit);
536 CloseLibrary((struct Library *) PartitionBase);
538 else
539 Printf("Couldn't open partition.library\n");
540 return retval;
543 struct Volume *getGrubStageVolume(CONST_STRPTR device, ULONG unit,
544 ULONG flags, struct DosEnvec *de)
546 struct Volume *volume;
548 volume = initVolume(device, unit, flags, de);
550 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume));
552 if (volume)
554 if (isvalidFileSystem(volume, device, unit))
555 return volume;
556 else
558 Printf("stage2 is on an unsupported file system\n");
559 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
561 uninitVolume(volume);
563 return 0;
566 BOOL isvalidPartition(CONST_STRPTR device, ULONG unit, LONG * pnum,
567 struct DosEnvec * de)
569 struct PartitionBase *PartitionBase;
570 struct PartitionHandle *ph;
571 ULONG type;
572 BOOL retval = FALSE;
574 D(bug
575 ("[install] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
577 PartitionBase =
578 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
579 "partition.library", 1);
580 if (PartitionBase)
582 ph = OpenRootPartition(device, unit);
583 if (ph)
585 struct TagItem tags[2];
587 tags[1].ti_Tag = TAG_DONE;
588 /* is there a partition table? */
589 if (OpenPartitionTable(ph) == 0)
591 if (pnum)
593 /* install into partition bootblock */
594 tags[0].ti_Tag = PTT_TYPE;
595 tags[0].ti_Data = (STACKIPTR) & type;
596 GetPartitionTableAttrs(ph, tags);
597 if (type == PHPTT_MBR)
599 struct PartitionHandle *pn;
601 /* search for partition */
602 tags[0].ti_Tag = PT_POSITION;
603 tags[0].ti_Data = (STACKIPTR) & type;
604 pn = (struct PartitionHandle *) ph->table->list.
605 lh_Head;
606 while (pn->ln.ln_Succ)
608 GetPartitionAttrs(pn, tags);
609 if (type == *pnum)
610 break;
611 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
613 if (pn->ln.ln_Succ)
615 struct PartitionType ptype;
617 /* is it an AROS partition? */
618 tags[0].ti_Tag = PT_TYPE;
619 tags[0].ti_Data = (STACKIPTR) & ptype;
620 GetPartitionAttrs(pn, tags);
621 if (ptype.id[0] == 0x30)
623 tags[0].ti_Tag = PT_DOSENVEC;
624 tags[0].ti_Data = (STACKIPTR) de;
625 GetPartitionAttrs(pn, tags);
626 retval = TRUE;
628 else
629 Printf
630 ("partition is not of type AROS (0x30)\n");
632 else
634 Printf
635 ("partition %ld not found on device %s unit %lu\n",
636 (long)*pnum, device, (long)unit);
639 else
640 Printf
641 ("you can only install in partitions which are MBR partitioned\n");
643 else
645 /* install into MBR */
646 tags[0].ti_Tag = PTT_TYPE;
647 tags[0].ti_Data = (STACKIPTR) & type;
648 GetPartitionTableAttrs(ph, tags);
649 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
651 tags[0].ti_Tag = PT_DOSENVEC;
652 tags[0].ti_Data = (STACKIPTR) de;
653 GetPartitionAttrs(ph, tags);
654 retval = TRUE;
656 else
657 Printf
658 ("partition table type must be either MBR or RDB\n");
660 ClosePartitionTable(ph);
662 else
664 /* FIXME: GetPartitionAttr() should always work for root partition */
665 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
666 retval = TRUE;
668 CloseRootPartition(ph);
670 else
671 Printf("Error OpenRootPartition(%s,%lu)\n", device, (long)unit);
672 CloseLibrary((struct Library *) PartitionBase);
674 else
675 Printf("Couldn't open partition.library\n");
676 return retval;
679 struct Volume *getBBVolume(CONST_STRPTR device, ULONG unit, LONG * partnum)
681 struct Volume *volume;
682 struct DosEnvec de;
684 D(bug("[install] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
686 if (isvalidPartition(device, unit, partnum, &de))
688 volume = initVolume(device, unit, 0, &de);
689 volume->partnum = partnum ? *partnum : -1;
690 readBlock(volume, 0, volume->blockbuffer, 512);
691 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
693 /* Clear the boot sector region! */
694 memset(volume->blockbuffer, 0x00, 446);
695 return volume;
697 else
698 Printf("no space for bootblock (RDB is on block 0)\n");
700 return NULL;
703 /* Convert a unit number into a drive number as understood by GRUB */
704 UWORD getDriveNumber(CONST_STRPTR device, ULONG unit)
706 struct PartitionHandle *ph;
707 ULONG i;
708 UWORD hd_count = 0;
710 for (i = 0; i < unit; i++)
712 ph = OpenRootPartition(device, i);
713 if (ph != NULL)
715 hd_count++;
716 CloseRootPartition(ph);
720 return hd_count;
723 BOOL writeBootIMG(STRPTR bootimgpath, struct Volume * bootimgvol, struct Volume * coreimgvol,
724 ULONG block /* first block of core.img file */, ULONG unit)
726 BOOL retval = FALSE;
727 LONG error = 0;
728 BPTR fh;
730 D(bug("[install] writeBootIMG(%x)\n", bootimgvol));
732 fh = Open(bootimgpath, MODE_OLDFILE);
733 if (fh)
735 if (Read(fh, bootimgvol->blockbuffer, 512) == 512)
737 /* install into MBR ? */
738 if ((bootimgvol->startblock == 0)
739 && (!(bootimgvol->flags & VF_IS_TRACKDISK)))
741 APTR boot_img = bootimgvol->blockbuffer;
743 UBYTE *boot_drive =
744 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
745 UWORD *boot_drive_check =
746 (UWORD *) (boot_img + GRUB_BOOT_MACHINE_DRIVE_CHECK);
748 if (unit == bootimgvol->unitnum)
749 *boot_drive = 0xFF;
750 else
751 *boot_drive = getDriveNumber(coreimgvol->device, unit)
752 | BIOS_HDISK_FLAG;
753 *boot_drive_check = 0x9090;
755 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
757 /* read old MBR */
758 error = readBlock(bootimgvol, 0, coreimgvol->blockbuffer, 512);
760 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol->blockbuffer));
761 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
762 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START));
763 /* copy BPB (BIOS Parameter Block) */
764 CopyMem
765 ((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
766 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
767 (GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START));
769 /* copy partition table - [Overwrites Floppy boot code] */
770 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
771 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
772 CopyMem((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
773 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
774 (GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
776 /* Store the core.img pointer .. */
777 ULONG * coreimg_sector_start = (ULONG *) (boot_img
778 + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
779 coreimg_sector_start[0] = block;
780 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block));
782 else
784 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
787 if (error == 0)
789 error = writeBlock(bootimgvol, 0, bootimgvol->blockbuffer, 512);
791 if (error)
792 Printf("WriteError %lu\n", (long)error);
793 else
794 retval = TRUE;
796 else
797 Printf("WriteError %lu\n", (long)error);
799 else
800 Printf("%s: Read Error\n", bootimgpath);
801 Close(fh);
803 else
804 PrintFault(IoErr(), bootimgpath);
806 return retval;
809 /* Collects the list of blocks that a file occupies on FFS filesystem */
810 ULONG collectBlockListFFS(struct Volume *volume, ULONG block, struct BlockNode *blocklist)
812 ULONG retval, first_block;
813 WORD blk_count,count;
814 UWORD i;
816 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume, block, blocklist));
819 /* Clear the core.img sector pointers region! */
820 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
823 The number of first block of core.img will be stored in boot.img
824 so skip the first filekey in the first loop
827 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
828 volume->readcmd);
830 if (retval)
832 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval));
833 Printf("ReadError %lu\n", (long)retval);
834 return 0;
837 i = volume->SizeBlock - 52;
838 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
839 blk_count=0;
841 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block, i));
846 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
847 volume->readcmd);
848 if (retval)
850 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval));
851 Printf("ReadError %lu\n", (long)retval);
852 return 0;
855 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block, i));
856 while ((i>=6) && (volume->blockbuffer[i]))
858 D(bug("[install] collectBlockListFFS: i = %d\n", i));
860 if current sector follows right after last sector
861 then we don't need a new element
863 if ((blocklist[blk_count].sector_lo) &&
864 ((blocklist[blk_count].sector_lo+blocklist[blk_count].count)==
865 AROS_BE2LONG(volume->blockbuffer[i])))
867 blocklist[blk_count].count += 1;
868 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
869 i, blk_count, blocklist[blk_count].count));
871 else
873 blk_count--; /* decrement first */
874 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count));
876 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
878 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
879 i, blk_count));
880 Printf("There is no more space to save blocklist in core.img\n");
881 return 0;
883 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
884 i, blk_count));
885 blocklist[blk_count].sector_lo = AROS_BE2LONG(volume->blockbuffer[i]);
886 blocklist[blk_count].sector_hi = 0;
887 blocklist[blk_count].count = 1;
889 i--;
891 i = volume->SizeBlock - 51;
892 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
893 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block, i));
894 } while (block);
898 blocks in blocklist are relative to the first
899 sector of the HD (not partition)
902 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count));
904 i = 0;
905 for (count=-1;count>=blk_count;count--)
907 blocklist[count].sector_lo += volume->startblock;
908 blocklist[count].seg_adr = 0x820 + (i*32);
909 i += blocklist[count].count;
910 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
911 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
912 blocklist[count].sector_lo, blocklist[count].seg_adr));
915 first_block += volume->startblock;
916 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block));
918 return first_block;
921 /* Collects the list of blocks that a file occupies on SFS filesystem */
922 ULONG collectBlockListSFS(struct Volume *volume, ULONG objectnode, struct BlockNode *blocklist)
924 ULONG retval, first_block = 0;
925 WORD blk_count = 0, count = 0;
926 ULONG block_objectnoderoot = 0, block_sfsobjectcontainer = 0, block_extentbnoderoot = 0;
927 ULONG nextblock = 0, searchedblock = 0;
928 WORD i = 0;
929 UBYTE * tmpBytePtr = NULL;
931 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume->startblock, objectnode));
932 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume->countblock, volume->SizeBlock, volume->partnum));
934 /* Clear the core.img sector pointers region! */
935 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
937 /* Description of actions:
938 * 1. Load SFS root block
939 * 2. From root block find the block containing root of objectnodes
940 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
941 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
942 * first block of file
943 * 5. Having first file block, find the extentbnode for that block and read number
944 * of blocks. Put first block and number of blocks into BlockList.
945 * 6. If the file has more blocks than this exntentbnode hold, find first file
946 * block in next extentbnode. Go to step 5.
947 * Use the SFS source codes for reference. They operate on structures not pointers
948 * and are much easier to understand.
951 /* Read root block */
952 retval = _readwriteBlock(volume, 0, volume->blockbuffer, volume->SizeBlock<<2,
953 volume->readcmd);
955 if (retval)
957 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval));
958 Printf("ReadError %lu\n", (long)retval);
959 return 0;
962 /* Get block pointers from root block */
963 block_objectnoderoot = AROS_BE2LONG(volume->blockbuffer[28]); /* objectnoderoot - 29th ULONG */
964 block_extentbnoderoot = AROS_BE2LONG(volume->blockbuffer[27]); /* extentbnoderoot - 28th ULONG */
966 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
967 block_objectnoderoot, block_extentbnoderoot));
971 /* Find the SFSObjectContainer block for given objectnode */
972 /* Reference: SFS, nodes.c, function findnode */
973 nextblock = block_objectnoderoot;
974 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
975 nextblock, objectnode));
976 while(1)
978 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
979 volume->readcmd);
981 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
982 if (AROS_BE2LONG(volume->blockbuffer[4]) == 1)
984 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
985 tmpBytePtr = (UBYTE*)volume->blockbuffer;
986 ULONG index = 20 + 10 * (objectnode - AROS_BE2LONG(volume->blockbuffer[3]));
987 block_sfsobjectcontainer = AROS_BE2LONG(((ULONG*)(tmpBytePtr + index))[0]);
988 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
989 nextblock, block_sfsobjectcontainer));
990 break;
992 else
994 UWORD containerentry =
995 (objectnode - AROS_BE2LONG(volume->blockbuffer[3]))/AROS_BE2LONG(volume->blockbuffer[4]);
996 nextblock = AROS_BE2LONG(volume->blockbuffer[containerentry + 5]) >> 4; /* 9-5 (2^9 = 512) */;
997 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock));
1001 if (block_sfsobjectcontainer == 0)
1003 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
1004 Printf("SFSObjectContainer not found\n");
1005 return 0;
1010 /* Find the SFSObject in SFSObjectContainer for given objectnode */
1011 first_block = 0;
1012 while((block_sfsobjectcontainer != 0) && (first_block == 0))
1014 /* Read next SFS container block */
1015 retval = _readwriteBlock(volume, block_sfsobjectcontainer, volume->blockbuffer, volume->SizeBlock<<2,
1016 volume->readcmd);
1018 if (retval)
1020 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval));
1021 Printf("ReadError %lu\n", (long)retval);
1022 return 0;
1025 /* Iterate over SFS objects and match the objectnode */
1027 * The first offset comes from :
1028 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
1029 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
1031 tmpBytePtr = ((UBYTE*)volume->blockbuffer) + 12 + 12; /* tmpBytePtr points to first object in container */
1033 while (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) > 0) /* check on the objectnode field */
1036 /* Compare objectnode */
1037 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) == objectnode)
1039 /* Found! */
1040 first_block = AROS_BE2LONG(((ULONG*)(tmpBytePtr + 12))[0]); /* data */
1041 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block));
1042 break;
1045 /* Move to next object */
1046 /* Find end of name and end of comment */
1047 tmpBytePtr += 25; /* Point to name */
1048 count = 0;
1049 for (i = 2; i > 0; tmpBytePtr++, count++)
1050 if (*tmpBytePtr == '\0')
1051 i--;
1053 /* Correction for aligment */
1054 if ((count & 0x01) == 0 )
1055 tmpBytePtr++;
1058 /* Move to next sfs object container block */
1059 block_sfsobjectcontainer = AROS_BE2LONG(volume->blockbuffer[4]); /* next field */
1063 if (first_block == 0)
1065 D(bug("[install] collectBlockListSFS: First block not found\n"));
1066 Printf("First block not found\n");
1067 return 0;
1072 /* First file block found. Find all blocks of file */
1073 searchedblock = first_block;
1074 blk_count = 0;
1076 while(1)
1078 nextblock = block_extentbnoderoot;
1079 UBYTE * BNodePtr = NULL;
1081 while(1)
1083 /* Find the extentbnode for this block */
1085 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
1086 nextblock, searchedblock));
1088 UBYTE * BTreeContainerPtr = NULL;
1089 BNodePtr = NULL;
1091 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
1092 volume->readcmd);
1094 BTreeContainerPtr = (UBYTE*)(volume->blockbuffer + 3); /* Starts right after the header */
1096 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
1097 AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0])));
1099 for (i = AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0]) - 1; i >=0; i--) /* Start from last element */
1101 /* Read the BNode */
1102 tmpBytePtr = BTreeContainerPtr + 4 + i * BTreeContainerPtr[3];
1104 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr))[0]) <= searchedblock) /* Check on the key field */
1106 BNodePtr = tmpBytePtr;
1107 break;
1111 /* Fail if BNodePtr still NULL */
1112 if (BNodePtr == NULL)
1114 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
1115 Printf("Failed to travers extentbnode tree.\n");
1116 return 0;
1119 /* If we are at the leaf, stop */
1120 if (BTreeContainerPtr[2])
1121 break;
1123 /* Else search further */
1124 nextblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1127 /* Found. Add BlockList entry */
1128 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
1129 searchedblock, AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0])));
1131 /* Add blocklist entry */
1132 blk_count--;
1134 /* Check if we still have spece left to add data to BlockList */
1135 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
1137 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
1138 Printf("There is no more space to save blocklist in core.img\n");
1139 return 0;
1142 blocklist[blk_count].sector_lo = searchedblock;
1143 blocklist[blk_count].sector_hi = 0;
1144 blocklist[blk_count].count = AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0]);
1146 /* Handling of special situations */
1147 if (searchedblock == first_block)
1149 /* Writting first pack of blocks. Pointer needs to point to second file block */
1150 blocklist[blk_count].sector_lo++;
1151 blocklist[blk_count].count--;
1152 if (blocklist[blk_count].count == 0)
1154 /* This means that the first pack of blocks contained only one block - first block */
1155 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
1156 /* so that next iteration will overwrite the current results */
1157 blk_count++;
1161 /* Are there more blocks to read? */
1162 if (AROS_BE2LONG(((ULONG*)(BNodePtr))[1]) == 0)
1164 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
1165 break;
1167 else
1168 searchedblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1172 /* Correct blocks for volume start */
1174 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1175 i = 0;
1176 for (count=-1;count>=blk_count;count--)
1178 blocklist[count].sector_lo += volume->startblock;
1179 blocklist[count].seg_adr = 0x820 + (i*32);
1180 i += blocklist[count].count;
1181 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
1182 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1183 blocklist[count].sector_lo, blocklist[count].seg_adr));
1186 first_block += volume->startblock;
1188 return first_block;
1191 /* Flushes the cache on the volume containing the specified path. */
1192 VOID flushFS(CONST_STRPTR path)
1194 TEXT devname[256];
1195 UWORD i;
1197 for (i = 0; path[i] != ':'; i++)
1198 devname[i] = path[i];
1199 devname[i++] = ':';
1200 devname[i] = '\0';
1202 /* Try to flush 10 times. 5 seconds total */
1204 /* Failsafe in case first Inhibit fails in some way (was needed
1205 * for SFS because non flushed data was failing Inhibit) */
1207 for (i = 0; i < 10; i++)
1209 if (Inhibit(devname, DOSTRUE))
1211 Inhibit(devname, DOSFALSE);
1212 break;
1214 else
1215 Delay(25);
1219 BOOL writeCoreIMG(BPTR fh, UBYTE *buffer, struct Volume *volume)
1221 BOOL retval = FALSE;
1223 D(bug("[install] writeCoreIMG(%x)\n", volume));
1225 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
1227 D(bug("[install] writeCoreIMG - write first block\n"));
1229 /* write back first block */
1230 if (Write(fh, buffer, 512) == 512)
1234 /* read second core.img block */
1235 if (Read(fh, buffer, 512) == 512)
1237 /* set partition number where core.img is on */
1238 LONG dos_part = 0;
1239 LONG bsd_part = 0; /*?? to fix = RDB part number of DH? */
1240 LONG *install_dos_part =
1241 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART);
1242 LONG *install_bsd_part =
1243 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
1245 dos_part = volume->partnum;
1247 D(bug("[install] set dos part = %d\n", dos_part));
1248 D(bug("[install] set bsd part = %d\n", bsd_part));
1250 *install_dos_part = dos_part;
1251 *install_bsd_part = bsd_part;
1253 /* write second core.img block back */
1254 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
1256 if (Write(fh, buffer, 512) == 512)
1258 retval = TRUE;
1260 else
1261 Printf("Write Error\n");
1263 else
1264 Printf("Seek Error\n");
1266 else
1267 Printf("Read Error\n");
1269 else
1270 Printf("Write Error\n");
1272 else
1274 Printf("Seek Error\n");
1275 PrintFault(IoErr(), NULL);
1277 return retval;
1280 ULONG updateCoreIMG(CONST_STRPTR grubpath, /* path of grub dir */
1281 struct Volume *volume, /* volume core.img is on */
1282 ULONG *buffer /* a buffer of at least 512 bytes */)
1284 ULONG block = 0;
1285 struct FileInfoBlock fib;
1286 BPTR fh;
1287 TEXT coreimgpath[256];
1289 D(bug("[install] updateCoreIMG(%x)\n", volume));
1291 AddPart(coreimgpath, grubpath, 256);
1292 AddPart(coreimgpath, CORE_IMG_FILE_NAME, 256);
1293 fh = Open(coreimgpath, MODE_OLDFILE);
1294 if (fh)
1296 if (ExamineFH(fh, &fib))
1298 if (Read(fh, buffer, 512) == 512)
1301 Get and store all blocks of core.img in first block of core.img.
1302 First block of core.img will be returned.
1303 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1304 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1305 collectBlockList assumes it receives one pointer after first element(upwards).
1308 if (volume->dos_id == ID_SFS_BE_DISK)
1310 D(bug("[install] core.img on SFS file system\n"));
1311 block = collectBlockListSFS
1312 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1314 else
1315 if ((volume->dos_id == ID_FFS_DISK) || (volume->dos_id == ID_INTER_DOS_DISK) ||
1316 (volume->dos_id == ID_INTER_FFS_DISK) || (volume->dos_id == ID_FASTDIR_DOS_DISK) ||
1317 (volume->dos_id == ID_FASTDIR_FFS_DISK))
1319 D(bug("[install] core.img on FFS file system\n"));
1320 block = collectBlockListFFS
1321 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1323 else
1325 block = 0;
1326 D(bug("[install] core.img on unsupported file system\n"));
1327 Printf("Unsupported file system\n");
1330 D(bug("[install] core.img first block: %ld\n", block));
1332 if (block)
1334 if (!writeCoreIMG(fh, (UBYTE *)buffer, volume))
1335 block = 0;
1338 else
1339 Printf("%s: Read Error\n", coreimgpath);
1341 else
1342 PrintFault(IoErr(), coreimgpath);
1344 Close(fh);
1347 else
1348 PrintFault(IoErr(), coreimgpath);
1349 return block;
1352 /* Installs boot.img to MBR and updates core.img */
1353 BOOL installGrubFiles(struct Volume *coreimgvol, /* core.img volume */
1354 CONST_STRPTR grubpath, /* path to grub files */
1355 ULONG unit, /* unit core.img is on */
1356 struct Volume *bootimgvol) /* boot device for boot.img */
1358 BOOL retval = FALSE;
1359 TEXT bootimgpath[256];
1360 ULONG block;
1362 D(bug("[install] installStageFiles(%x)\n", bootimgvol));
1364 /* Flush GRUB volume's cache */
1365 flushFS(grubpath);
1367 block = updateCoreIMG(grubpath, coreimgvol, bootimgvol->blockbuffer);
1369 if (block)
1371 AddPart(bootimgpath, grubpath, 256);
1372 AddPart(bootimgpath, (CONST_STRPTR) "boot.img", 256);
1373 if (writeBootIMG(bootimgpath, bootimgvol, coreimgvol, block, unit))
1374 retval = TRUE;
1376 else
1377 bug("failed %d\n", IoErr());
1379 return retval;
1382 int main(int argc, char **argv)
1384 struct RDArgs *rdargs;
1385 struct Volume *grubvol;
1386 struct Volume *bbvol;
1387 struct FileSysStartupMsg *fssm;
1388 int ret = RETURN_OK;
1390 D(bug("[install] main()\n"));
1392 rdargs = ReadArgs(template, myargs, NULL);
1393 if (rdargs)
1395 CONST_STRPTR bootDevice = (CONST_STRPTR) myargs[0];
1396 LONG unit = *(LONG *) myargs[1];
1397 LONG *partnum = (LONG *) myargs[2];
1398 CONST_STRPTR grubpath = (CONST_STRPTR) myargs[3];
1400 D(bug("[install] FORCELBA = %d\n", myargs[4]));
1401 if (myargs[4])
1402 Printf("FORCELBA ignored\n");
1404 if (partnum)
1406 Printf("PARTITIONNUMBER not supported yet\n");
1407 FreeArgs(rdargs);
1408 return RETURN_ERROR;
1411 fssm = getDiskFSSM(grubpath);
1412 if (fssm != NULL)
1414 CONST_STRPTR grubDevice = AROS_BSTR_ADDR(fssm->fssm_Device);
1416 if (!strcmp((const char *) grubDevice, (const char *) bootDevice))
1418 struct DosEnvec *dosEnvec;
1419 dosEnvec = (struct DosEnvec *) BADDR(fssm->fssm_Environ);
1421 grubvol = getGrubStageVolume(grubDevice, fssm->fssm_Unit,
1422 fssm->fssm_Flags, dosEnvec);
1423 if (grubvol)
1426 bbvol = getBBVolume(bootDevice, unit, partnum);
1427 if (bbvol)
1429 if (!installGrubFiles(grubvol, grubpath,
1430 fssm->fssm_Unit, bbvol))
1431 ret = RETURN_ERROR;
1433 uninitVolume(bbvol);
1435 else
1437 D(bug("getBBVolume failed miserably\n"));
1438 ret = RETURN_ERROR;
1441 uninitVolume(grubvol);
1444 else
1446 Printf("%s is not on device %s unit %ld\n",
1447 grubpath, bootDevice, (long)unit);
1448 ret = RETURN_ERROR;
1451 else if (fssm)
1453 Printf("kernel path must begin with a device name\n");
1454 FreeArgs(rdargs);
1455 ret = RETURN_ERROR;
1458 FreeArgs(rdargs);
1460 else
1461 PrintFault(IoErr(), (STRPTR) argv[0]);
1463 return ret;