2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 /******************************************************************************
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
22 Installs the GRUB 2 bootloader to the boot block of the specified
27 DEVICE -- Device name (e.g. ata.device)
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.
39 EFI machines don't need this utility because EFI doesn't need a bootblock.
40 It is capable of loading files directly from the filesystem.
44 Install-grub2 DEVICE ata.device UNIT 0 GRUB DH0:boot/grub
50 Partition, SYS:System/Format
54 ******************************************************************************/
57 #include <aros/debug.h>
60 #include <proto/debug.h>
61 #include <proto/exec.h>
62 #include <proto/dos.h>
63 #include <proto/partition.h>
64 #include <proto/utility.h>
65 #include <aros/macros.h>
66 #include <devices/hardblocks.h>
67 #include <devices/newstyle.h>
68 #include <exec/errors.h>
69 #include <exec/memory.h>
70 #include <libraries/partition.h>
72 /* These define some offsets */
73 #define ASM_FILE /* Omit grub_uint64_t reference */
74 #define GRUB_MACHINE I386_PC
76 #include <grub/i386/pc/boot.h>
77 #include <grub/offsets.h>
80 #define BIOS_HDISK_FLAG 0x80
82 #define MBR_MAX_PARTITIONS 4
83 #define MBRT_EXTENDED 0x05
84 #define MBRT_EXTENDED2 0x0f
85 #define BLCKLIST_ELEMENTS 14
89 struct PartitionHandle
*root
; /* Device root handle */
90 struct PartitionHandle
*part
; /* The actual partition */
91 ULONG startblock
; /* Offset, for stage volume */
93 CONST_STRPTR device
; /* Informative, for error messages */
95 UWORD SizeBlock
; /* In bytes */
97 LONG partnum
; /* -1 for device root */
102 #define VF_IS_TRACKDISK (1<<0)
103 #define VF_IS_RDB (1<<1)
113 const TEXT version
[] = "$VER: Install-grub2 41.3 " ADATE
;
115 static CONST_STRPTR CORE_IMG_FILE_NAME
= "core.img";
116 static CONST_STRPTR
template ="DEVICE/A,UNIT/N/K/A,PARTITIONNUMBER=PN/K/N,GRUB/K/A,FORCELBA/S,TEST/S";
118 struct PartitionBase
*PartitionBase
;
119 IPTR myargs
[7] = { 0, 0, 0, 0, 0, 0, 0 };
121 #define ARG_TESTING 5
123 struct FileSysStartupMsg
*getDiskFSSM(CONST_STRPTR path
)
126 struct DeviceNode
*dn
;
130 D(bug("[install] getDiskFSSM('%s')\n", path
));
132 for (i
= 0; (path
[i
]) && (path
[i
] != ':'); i
++)
137 dl
= LockDosList(LDF_READ
);
140 dn
= (struct DeviceNode
*) FindDosEntry(dl
, dname
, LDF_DEVICES
);
141 UnLockDosList(LDF_READ
);
146 if (IsFileSystem(dname
))
148 return (struct FileSysStartupMsg
*) BADDR(dn
->dn_Startup
);
151 Printf("device '%s' doesn't contain a file system\n",
155 PrintFault(ERROR_OBJECT_NOT_FOUND
, dname
);
159 Printf("'%s' doesn't contain a device name\n", path
);
163 static BOOL
AllocBuffer(struct Volume
*volume
)
165 volume
->blockbuffer
= AllocMem(volume
->SizeBlock
, MEMF_PUBLIC
| MEMF_CLEAR
);
166 if (!volume
->blockbuffer
)
168 Printf("Failed to allocate data buffer!\n");
174 BOOL
fillGeometry(struct Volume
*volume
, struct DosEnvec
*de
)
178 D(bug("[install] fillGeometry(%x)\n", volume
));
180 spc
= de
->de_Surfaces
* de
->de_BlocksPerTrack
;
181 volume
->SizeBlock
= de
->de_SizeBlock
<< 2;
182 volume
->startblock
= de
->de_LowCyl
* spc
;
184 ((de
->de_HighCyl
- de
->de_LowCyl
+ 1) * spc
) - 1 + de
->de_Reserved
;
185 volume
->part
= volume
->root
;
186 return AllocBuffer(volume
);
189 void DumpVolume(struct Volume
*volume
, const char *header
)
191 if (!myargs
[ARG_TESTING
])
194 Printf("%s: %s unit %lu partition %ld\n", header
, volume
->device
, volume
->unitnum
, volume
->partnum
);
197 struct Volume
*initVolume(CONST_STRPTR device
, ULONG unit
)
199 struct Volume
*volume
;
201 D(bug("[install] initVolume(%s:%d)\n", device
, unit
));
203 volume
= AllocMem(sizeof(struct Volume
), MEMF_PUBLIC
| MEMF_CLEAR
);
206 volume
->root
= OpenRootPartition(device
, unit
);
209 if (strcmp((const char *) device
, TD_NAME
) == 0)
210 volume
->flags
|= VF_IS_TRACKDISK
;
212 volume
->flags
|= VF_IS_RDB
; /* just assume we have RDB */
214 volume
->device
= device
;
215 volume
->unitnum
= unit
;
216 volume
->startblock
= 0;
217 volume
->partnum
= -1;
223 Printf("Failed to open device %s unit %ld!\n", device
, unit
);
225 FreeMem(volume
, sizeof(struct Volume
));
228 PrintFault(ERROR_NO_FREE_STORE
, NULL
);
233 void uninitVolume(struct Volume
*volume
)
235 D(bug("[install] uninitVolume(%x)\n", volume
));
237 if (volume
->blockbuffer
)
238 FreeMem(volume
->blockbuffer
, volume
->SizeBlock
);
241 ClosePartitionTable(volume
->root
);
242 CloseRootPartition(volume
->root
);
244 FreeMem(volume
, sizeof (struct Volume
));
247 ULONG
readBlock(struct Volume
* volume
, ULONG block
, APTR buffer
, ULONG size
)
249 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
250 volume
, block
, size
));
252 return ReadPartitionData(volume
->startblock
+ block
, volume
->part
, buffer
, size
);
255 ULONG
writeBlock(struct Volume
* volume
, ULONG block
, APTR buffer
, ULONG size
)
257 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
258 volume
, block
, size
));
260 if (myargs
[ARG_TESTING
])
263 return WritePartitionData(volume
->startblock
+ block
, volume
->part
, buffer
, size
);
266 static BOOL
isKnownFs(ULONG dos_id
)
271 case ID_INTER_DOS_DISK
:
272 case ID_INTER_FFS_DISK
:
273 case ID_FASTDIR_DOS_DISK
:
274 case ID_FASTDIR_FFS_DISK
:
283 static BOOL
GetPartitionNum(struct Volume
*volume
, struct PartitionHandle
*parent
,
284 struct PartitionHandle
**extph
)
286 struct PartitionHandle
*pn
;
287 UQUAD offset
, start
, end
;
289 GetPartitionAttrsTags(parent
, PT_STARTBLOCK
, &offset
, TAG_DONE
);
291 for (pn
= (struct PartitionHandle
*) parent
->table
->list
.lh_Head
;
293 pn
= (struct PartitionHandle
*) pn
->ln
.ln_Succ
)
297 struct PartitionType ptype
= { };
299 GetPartitionAttrsTags(pn
, PT_TYPE
, &ptype
, TAG_DONE
);
300 if (ptype
.id
[0] == MBRT_EXTENDED
|| ptype
.id
[0] == MBRT_EXTENDED2
)
307 GetPartitionAttrsTags(pn
, PT_STARTBLOCK
, &start
, PT_ENDBLOCK
, &end
, TAG_DONE
);
311 D(KPrintF("[install] checking partition start %llu end %llu\n", start
, end
));
312 if ((volume
->startblock
>= start
) && (volume
->startblock
<= end
))
314 GetPartitionAttrsTags(pn
, PT_POSITION
, &volume
->partnum
, TAG_DONE
);
321 BOOL
isvalidFileSystem(struct Volume
*volume
)
326 D(bug("[install] isvalidFileSystem(%s, %d)\n", volume
->device
, volume
->unitnum
));
328 if (readBlock(volume
, 0, volume
->blockbuffer
, volume
->SizeBlock
))
330 Printf("Read Error\n");
334 dos_id
= AROS_BE2LONG(volume
->blockbuffer
[0]);
336 if (!isKnownFs(dos_id
))
338 /* first block has no DOS\x so we don't have RDB for sure */
339 volume
->flags
&= ~VF_IS_RDB
;
340 if (readBlock(volume
, 1, volume
->blockbuffer
, volume
->SizeBlock
))
342 Printf("Read Error\n");
346 dos_id
= AROS_BE2LONG(volume
->blockbuffer
[0]);
348 if (!isKnownFs(dos_id
))
351 D(bug("[install] Detected known DOSType 0x%08X\n", dos_id
));
352 volume
->dos_id
= dos_id
;
354 D(bug("[install] Looking for partition startblock %lu\n", volume
->startblock
));
355 if (OpenPartitionTable(volume
->root
) == 0)
357 struct TagItem tags
[2];
360 tags
[1].ti_Tag
= TAG_DONE
;
361 tags
[0].ti_Tag
= PTT_TYPE
;
362 tags
[0].ti_Data
= (STACKIPTR
) & type
;
363 GetPartitionTableAttrs(volume
->root
, tags
);
365 if (type
== PHPTT_MBR
)
367 struct PartitionHandle
*extph
= NULL
;
369 D(bug("[install] Found MBR table\n"));
370 if (GetPartitionNum(volume
, volume
->root
, &extph
))
373 D(bug("[install] Primary partition found: partnum=%d\n", volume
->partnum
));
375 else if (extph
!= NULL
)
377 if (OpenPartitionTable(extph
) == 0)
379 GetPartitionTableAttrs(extph
, tags
);
380 if (type
== PHPTT_EBR
)
382 D(bug("[install] Found EBR table\n"));
383 if (GetPartitionNum(volume
, extph
, NULL
))
385 volume
->partnum
+= MBR_MAX_PARTITIONS
;
387 D(bug("[install] Logical partition found: partnum=%d\n", volume
->partnum
));
390 ClosePartitionTable(extph
);
394 else if (type
== PHPTT_RDB
)
396 /* just use whole hard disk */
400 Printf("only MBR and RDB partition tables are supported\n");
402 ClosePartitionTable(volume
->root
);
406 /* just use whole hard disk */
412 struct Volume
*getGrubStageVolume(CONST_STRPTR device
, ULONG unit
,
413 ULONG flags
, struct DosEnvec
*de
)
415 struct Volume
*volume
;
417 volume
= initVolume(device
, unit
);
419 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume
));
423 if (fillGeometry(volume
, de
))
425 if (isvalidFileSystem(volume
))
429 Printf("stage2 is on an unsupported file system\n");
430 PrintFault(ERROR_OBJECT_WRONG_TYPE
, NULL
);
433 uninitVolume(volume
);
438 BOOL
isvalidPartition(struct Volume
*volume
, LONG
*pnum
)
441 struct TagItem tags
[2];
444 D(bug("[install] isvalidPartition(%d)\n", pnum
));
446 tags
[1].ti_Tag
= TAG_DONE
;
450 /* install into partition bootblock */
451 /* is there a partition table? */
452 if (OpenPartitionTable(volume
->root
) == 0)
454 tags
[0].ti_Tag
= PTT_TYPE
;
455 tags
[0].ti_Data
= (STACKIPTR
) & type
;
456 GetPartitionTableAttrs(volume
->root
, tags
);
457 if (type
== PHPTT_MBR
)
459 struct PartitionHandle
*pn
;
461 /* search for partition */
462 tags
[0].ti_Tag
= PT_POSITION
;
463 tags
[0].ti_Data
= (STACKIPTR
) & type
;
464 pn
= (struct PartitionHandle
*) volume
->root
->table
->list
.lh_Head
;
465 while (pn
->ln
.ln_Succ
)
467 GetPartitionAttrs(pn
, tags
);
470 pn
= (struct PartitionHandle
*) pn
->ln
.ln_Succ
;
474 struct PartitionType ptype
;
476 /* is it an AROS partition? */
477 tags
[0].ti_Tag
= PT_TYPE
;
478 tags
[0].ti_Data
= (STACKIPTR
) & ptype
;
479 GetPartitionAttrs(pn
, tags
);
480 if (ptype
.id
[0] == 0x30)
486 Printf("partition is not of type AROS (0x30)\n");
489 Printf("partition %ld not found on device %s unit %lu\n", *pnum
, volume
->device
, volume
->unitnum
);
492 Printf("you can only install in partitions which are MBR partitioned\n");
495 Printf("Failed to open partition table on device %s unit %lu\n", *pnum
, volume
->device
, volume
->unitnum
);
499 /* install into MBR */
500 volume
->part
= volume
->root
;
506 volume
->SizeBlock
= volume
->part
->de
.de_SizeBlock
<< 2;
507 retval
= AllocBuffer(volume
);
513 struct Volume
*getBBVolume(CONST_STRPTR device
, ULONG unit
, LONG
* partnum
)
515 struct Volume
*volume
;
517 D(bug("[install] getBBVolume(%s:%d, %d)\n", device
, unit
, partnum
));
519 volume
= initVolume(device
, unit
);
523 if (isvalidPartition(volume
, partnum
))
525 volume
->partnum
= partnum
? *partnum
: -1;
526 readBlock(volume
, 0, volume
->blockbuffer
, volume
->SizeBlock
);
527 if (AROS_BE2LONG(volume
->blockbuffer
[0]) != IDNAME_RIGIDDISK
)
529 /* Clear the boot sector region! */
530 memset(volume
->blockbuffer
, 0x00, 446);
534 Printf("no space for bootblock (RDB is on block 0)\n");
536 uninitVolume(volume
);
540 /* Convert a unit number into a drive number as understood by GRUB */
541 UWORD
getDriveNumber(CONST_STRPTR device
, ULONG unit
)
543 struct PartitionHandle
*ph
;
547 for (i
= 0; i
< unit
; i
++)
549 ph
= OpenRootPartition(device
, i
);
553 CloseRootPartition(ph
);
560 BOOL
writeBootIMG(STRPTR bootimgpath
, struct Volume
* bootimgvol
, struct Volume
* coreimgvol
,
561 ULONG block
/* first block of core.img file */, ULONG unit
)
567 D(bug("[install] writeBootIMG(%x)\n", bootimgvol
));
569 fh
= Open(bootimgpath
, MODE_OLDFILE
);
572 if (Read(fh
, bootimgvol
->blockbuffer
, 512) == 512)
574 /* install into MBR ? */
575 if ((bootimgvol
->startblock
== 0)
576 && (!(bootimgvol
->flags
& VF_IS_TRACKDISK
)))
578 APTR boot_img
= bootimgvol
->blockbuffer
;
581 (UBYTE
*) (boot_img
+ GRUB_BOOT_MACHINE_BOOT_DRIVE
);
582 UWORD
*boot_drive_check
=
583 (UWORD
*) (boot_img
+ GRUB_BOOT_MACHINE_DRIVE_CHECK
);
585 if (unit
== bootimgvol
->unitnum
)
588 *boot_drive
= getDriveNumber(coreimgvol
->device
, unit
)
590 *boot_drive_check
= 0x9090;
592 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
595 error
= readBlock(bootimgvol
, 0, coreimgvol
->blockbuffer
, 512);
597 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol
->blockbuffer
));
598 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
599 (char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
));
600 /* copy BPB (BIOS Parameter Block) */
602 ((APTR
) ((char *) coreimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
),
603 (APTR
) ((char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
),
604 (GRUB_BOOT_MACHINE_BPB_END
- GRUB_BOOT_MACHINE_BPB_START
));
606 /* copy partition table - [Overwrites Floppy boot code] */
607 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
608 (char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
));
609 CopyMem((APTR
) ((char *) coreimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
),
610 (APTR
) ((char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
),
611 (GRUB_BOOT_MACHINE_PART_END
- GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
));
613 /* Store the core.img pointer .. */
614 ULONG
* coreimg_sector_start
= (ULONG
*) (boot_img
615 + GRUB_BOOT_MACHINE_KERNEL_SECTOR
);
616 coreimg_sector_start
[0] = block
;
617 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block
));
621 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
626 error
= writeBlock(bootimgvol
, 0, bootimgvol
->blockbuffer
, 512);
629 Printf("WriteError %lu\n", (long)error
);
634 Printf("WriteError %lu\n", (long)error
);
637 Printf("%s: Read Error\n", bootimgpath
);
641 PrintFault(IoErr(), bootimgpath
);
646 /* Collects the list of blocks that a file occupies on FFS filesystem */
647 ULONG
collectBlockListFFS(struct Volume
*volume
, ULONG block
, struct BlockNode
*blocklist
)
649 ULONG retval
, first_block
;
650 WORD blk_count
,count
;
653 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume
, block
, blocklist
));
656 /* Clear the core.img sector pointers region! */
657 memset((UBYTE
*)&blocklist
[-BLCKLIST_ELEMENTS
],0x00, BLCKLIST_ELEMENTS
*sizeof(struct BlockNode
));
660 The number of first block of core.img will be stored in boot.img
661 so skip the first filekey in the first loop
664 retval
= readBlock(volume
, block
, volume
->blockbuffer
, volume
->SizeBlock
);
668 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval
));
669 Printf("ReadError %lu\n", (long)retval
);
673 i
= volume
->SizeBlock
- 52;
674 first_block
= AROS_BE2LONG(volume
->blockbuffer
[volume
->SizeBlock
-51]);
677 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block
, i
));
682 retval
= readBlock(volume
, block
, volume
->blockbuffer
, volume
->SizeBlock
);
685 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval
));
686 Printf("ReadError %lu\n", (long)retval
);
690 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block
, i
));
691 while ((i
>=6) && (volume
->blockbuffer
[i
]))
693 D(bug("[install] collectBlockListFFS: i = %d\n", i
));
695 if current sector follows right after last sector
696 then we don't need a new element
698 if ((blocklist
[blk_count
].sector_lo
) &&
699 ((blocklist
[blk_count
].sector_lo
+blocklist
[blk_count
].count
)==
700 AROS_BE2LONG(volume
->blockbuffer
[i
])))
702 blocklist
[blk_count
].count
+= 1;
703 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
704 i
, blk_count
, blocklist
[blk_count
].count
));
708 blk_count
--; /* decrement first */
709 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count
));
711 if ((blk_count
-1) <= -BLCKLIST_ELEMENTS
)
713 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
715 Printf("There is no more space to save blocklist in core.img\n");
718 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
720 blocklist
[blk_count
].sector_lo
= AROS_BE2LONG(volume
->blockbuffer
[i
]);
721 blocklist
[blk_count
].sector_hi
= 0;
722 blocklist
[blk_count
].count
= 1;
726 i
= volume
->SizeBlock
- 51;
727 block
= AROS_BE2LONG(volume
->blockbuffer
[volume
->SizeBlock
- 2]);
728 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block
, i
));
733 blocks in blocklist are relative to the first
734 sector of the HD (not partition)
737 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count
));
740 for (count
=-1;count
>=blk_count
;count
--)
742 blocklist
[count
].sector_lo
+= volume
->startblock
;
743 blocklist
[count
].seg_adr
= 0x820 + (i
*32);
744 i
+= blocklist
[count
].count
;
745 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count
));
746 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
747 blocklist
[count
].sector_lo
, blocklist
[count
].seg_adr
));
750 first_block
+= volume
->startblock
;
751 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block
));
756 /* Collects the list of blocks that a file occupies on SFS filesystem */
757 ULONG
collectBlockListSFS(struct Volume
*volume
, ULONG objectnode
, struct BlockNode
*blocklist
)
759 ULONG retval
, first_block
= 0;
760 WORD blk_count
= 0, count
= 0;
761 ULONG block_objectnoderoot
= 0, block_sfsobjectcontainer
= 0, block_extentbnoderoot
= 0;
762 ULONG nextblock
= 0, searchedblock
= 0;
764 UBYTE
* tmpBytePtr
= NULL
;
766 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume
->startblock
, objectnode
));
767 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume
->countblock
, volume
->SizeBlock
, volume
->partnum
));
769 /* Clear the core.img sector pointers region! */
770 memset((UBYTE
*)&blocklist
[-BLCKLIST_ELEMENTS
],0x00, BLCKLIST_ELEMENTS
*sizeof(struct BlockNode
));
772 /* Description of actions:
773 * 1. Load SFS root block
774 * 2. From root block find the block containing root of objectnodes
775 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
776 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
777 * first block of file
778 * 5. Having first file block, find the extentbnode for that block and read number
779 * of blocks. Put first block and number of blocks into BlockList.
780 * 6. If the file has more blocks than this exntentbnode hold, find first file
781 * block in next extentbnode. Go to step 5.
782 * Use the SFS source codes for reference. They operate on structures not pointers
783 * and are much easier to understand.
786 /* Read root block */
787 retval
= readBlock(volume
, 0, volume
->blockbuffer
, volume
->SizeBlock
);
791 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval
));
792 Printf("ReadError %lu\n", (long)retval
);
796 /* Get block pointers from root block */
797 block_objectnoderoot
= AROS_BE2LONG(volume
->blockbuffer
[28]); /* objectnoderoot - 29th ULONG */
798 block_extentbnoderoot
= AROS_BE2LONG(volume
->blockbuffer
[27]); /* extentbnoderoot - 28th ULONG */
800 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
801 block_objectnoderoot
, block_extentbnoderoot
));
805 /* Find the SFSObjectContainer block for given objectnode */
806 /* Reference: SFS, nodes.c, function findnode */
807 nextblock
= block_objectnoderoot
;
808 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
809 nextblock
, objectnode
));
812 readBlock(volume
, nextblock
, volume
->blockbuffer
, volume
->SizeBlock
);
814 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
815 if (AROS_BE2LONG(volume
->blockbuffer
[4]) == 1)
817 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
818 tmpBytePtr
= (UBYTE
*)volume
->blockbuffer
;
819 ULONG index
= 20 + 10 * (objectnode
- AROS_BE2LONG(volume
->blockbuffer
[3]));
820 block_sfsobjectcontainer
= AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ index
))[0]);
821 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
822 nextblock
, block_sfsobjectcontainer
));
827 UWORD containerentry
=
828 (objectnode
- AROS_BE2LONG(volume
->blockbuffer
[3]))/AROS_BE2LONG(volume
->blockbuffer
[4]);
829 nextblock
= AROS_BE2LONG(volume
->blockbuffer
[containerentry
+ 5]) >> 4; /* 9-5 (2^9 = 512) */;
830 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock
));
834 if (block_sfsobjectcontainer
== 0)
836 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
837 Printf("SFSObjectContainer not found\n");
843 /* Find the SFSObject in SFSObjectContainer for given objectnode */
845 while((block_sfsobjectcontainer
!= 0) && (first_block
== 0))
847 /* Read next SFS container block */
848 retval
= readBlock(volume
, block_sfsobjectcontainer
, volume
->blockbuffer
, volume
->SizeBlock
);
852 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval
));
853 Printf("ReadError %lu\n", (long)retval
);
857 /* Iterate over SFS objects and match the objectnode */
859 * The first offset comes from :
860 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
861 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
863 tmpBytePtr
= ((UBYTE
*)volume
->blockbuffer
) + 12 + 12; /* tmpBytePtr points to first object in container */
865 while (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 4))[0]) > 0) /* check on the objectnode field */
868 /* Compare objectnode */
869 if (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 4))[0]) == objectnode
)
872 first_block
= AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 12))[0]); /* data */
873 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block
));
877 /* Move to next object */
878 /* Find end of name and end of comment */
879 tmpBytePtr
+= 25; /* Point to name */
881 for (i
= 2; i
> 0; tmpBytePtr
++, count
++)
882 if (*tmpBytePtr
== '\0')
885 /* Correction for aligment */
886 if ((count
& 0x01) == 0 )
890 /* Move to next sfs object container block */
891 block_sfsobjectcontainer
= AROS_BE2LONG(volume
->blockbuffer
[4]); /* next field */
895 if (first_block
== 0)
897 D(bug("[install] collectBlockListSFS: First block not found\n"));
898 Printf("First block not found\n");
904 /* First file block found. Find all blocks of file */
905 searchedblock
= first_block
;
910 nextblock
= block_extentbnoderoot
;
911 UBYTE
* BNodePtr
= NULL
;
915 /* Find the extentbnode for this block */
917 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
918 nextblock
, searchedblock
));
920 UBYTE
* BTreeContainerPtr
= NULL
;
923 readBlock(volume
, nextblock
, volume
->blockbuffer
, volume
->SizeBlock
);
925 BTreeContainerPtr
= (UBYTE
*)(volume
->blockbuffer
+ 3); /* Starts right after the header */
927 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
928 AROS_BE2WORD(((UWORD
*)BTreeContainerPtr
)[0])));
930 for (i
= AROS_BE2WORD(((UWORD
*)BTreeContainerPtr
)[0]) - 1; i
>=0; i
--) /* Start from last element */
933 tmpBytePtr
= BTreeContainerPtr
+ 4 + i
* BTreeContainerPtr
[3];
935 if (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
))[0]) <= searchedblock
) /* Check on the key field */
937 BNodePtr
= tmpBytePtr
;
942 /* Fail if BNodePtr still NULL */
943 if (BNodePtr
== NULL
)
945 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
946 Printf("Failed to travers extentbnode tree.\n");
950 /* If we are at the leaf, stop */
951 if (BTreeContainerPtr
[2])
954 /* Else search further */
955 nextblock
= AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]); /* data / next field */
958 /* Found. Add BlockList entry */
959 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
960 searchedblock
, AROS_BE2WORD(((UWORD
*)(BNodePtr
+ 12))[0])));
962 /* Add blocklist entry */
965 /* Check if we still have spece left to add data to BlockList */
966 if ((blk_count
-1) <= -BLCKLIST_ELEMENTS
)
968 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
969 Printf("There is no more space to save blocklist in core.img\n");
973 blocklist
[blk_count
].sector_lo
= searchedblock
;
974 blocklist
[blk_count
].sector_hi
= 0;
975 blocklist
[blk_count
].count
= AROS_BE2WORD(((UWORD
*)(BNodePtr
+ 12))[0]);
977 /* Handling of special situations */
978 if (searchedblock
== first_block
)
980 /* Writting first pack of blocks. Pointer needs to point to second file block */
981 blocklist
[blk_count
].sector_lo
++;
982 blocklist
[blk_count
].count
--;
983 if (blocklist
[blk_count
].count
== 0)
985 /* This means that the first pack of blocks contained only one block - first block */
986 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
987 /* so that next iteration will overwrite the current results */
992 /* Are there more blocks to read? */
993 if (AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]) == 0)
995 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
999 searchedblock
= AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]); /* data / next field */
1003 /* Correct blocks for volume start */
1005 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1007 for (count
=-1;count
>=blk_count
;count
--)
1009 blocklist
[count
].sector_lo
+= volume
->startblock
;
1010 blocklist
[count
].seg_adr
= 0x820 + (i
*32);
1011 i
+= blocklist
[count
].count
;
1012 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count
));
1013 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1014 blocklist
[count
].sector_lo
, blocklist
[count
].seg_adr
));
1017 first_block
+= volume
->startblock
;
1022 /* Flushes the cache on the volume containing the specified path. */
1023 VOID
flushFS(CONST_STRPTR path
)
1028 for (i
= 0; path
[i
] != ':'; i
++)
1029 devname
[i
] = path
[i
];
1033 /* Try to flush 10 times. 5 seconds total */
1035 /* Failsafe in case first Inhibit fails in some way (was needed
1036 * for SFS because non flushed data was failing Inhibit) */
1038 for (i
= 0; i
< 10; i
++)
1040 if (Inhibit(devname
, DOSTRUE
))
1042 Inhibit(devname
, DOSFALSE
);
1050 BOOL
writeCoreIMG(BPTR fh
, UBYTE
*buffer
, struct Volume
*volume
)
1052 BOOL retval
= FALSE
;
1054 if (myargs
[ARG_TESTING
])
1057 D(bug("[install] writeCoreIMG(%x)\n", volume
));
1059 if (Seek(fh
, 0, OFFSET_BEGINNING
) != -1)
1061 D(bug("[install] writeCoreIMG - write first block\n"));
1063 /* write back first block */
1064 if (Write(fh
, buffer
, 512) == 512)
1068 /* read second core.img block */
1069 if (Read(fh
, buffer
, 512) == 512)
1071 /* set partition number where core.img is on */
1073 LONG bsd_part
= 0; /*?? to fix = RDB part number of DH? */
1074 LONG
*install_dos_part
=
1075 (LONG
*) (buffer
+ GRUB_KERNEL_MACHINE_INSTALL_DOS_PART
);
1076 LONG
*install_bsd_part
=
1077 (LONG
*) (buffer
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART
);
1079 dos_part
= volume
->partnum
;
1081 D(bug("[install] set dos part = %d\n", dos_part
));
1082 D(bug("[install] set bsd part = %d\n", bsd_part
));
1084 *install_dos_part
= dos_part
;
1085 *install_bsd_part
= bsd_part
;
1087 /* write second core.img block back */
1088 if (Seek(fh
, -512, OFFSET_CURRENT
) != -1)
1090 if (Write(fh
, buffer
, 512) == 512)
1095 Printf("Write Error\n");
1098 Printf("Seek Error\n");
1101 Printf("Read Error\n");
1104 Printf("Write Error\n");
1108 Printf("Seek Error\n");
1109 PrintFault(IoErr(), NULL
);
1114 ULONG
updateCoreIMG(CONST_STRPTR grubpath
, /* path of grub dir */
1115 struct Volume
*volume
, /* volume core.img is on */
1116 ULONG
*buffer
/* a buffer of at least 512 bytes */)
1119 struct FileInfoBlock fib
;
1121 TEXT coreimgpath
[256];
1123 D(bug("[install] updateCoreIMG(%x)\n", volume
));
1125 AddPart(coreimgpath
, grubpath
, 256);
1126 AddPart(coreimgpath
, CORE_IMG_FILE_NAME
, 256);
1127 fh
= Open(coreimgpath
, MODE_OLDFILE
);
1130 if (ExamineFH(fh
, &fib
))
1132 if (Read(fh
, buffer
, 512) == 512)
1135 Get and store all blocks of core.img in first block of core.img.
1136 First block of core.img will be returned.
1137 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1138 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1139 collectBlockList assumes it receives one pointer after first element(upwards).
1142 if (volume
->dos_id
== ID_SFS_BE_DISK
)
1144 D(bug("[install] core.img on SFS file system\n"));
1145 block
= collectBlockListSFS
1146 (volume
, fib
.fib_DiskKey
, (struct BlockNode
*)&buffer
[128]);
1149 if ((volume
->dos_id
== ID_FFS_DISK
) || (volume
->dos_id
== ID_INTER_DOS_DISK
) ||
1150 (volume
->dos_id
== ID_INTER_FFS_DISK
) || (volume
->dos_id
== ID_FASTDIR_DOS_DISK
) ||
1151 (volume
->dos_id
== ID_FASTDIR_FFS_DISK
))
1153 D(bug("[install] core.img on FFS file system\n"));
1154 block
= collectBlockListFFS
1155 (volume
, fib
.fib_DiskKey
, (struct BlockNode
*)&buffer
[128]);
1160 D(bug("[install] core.img on unsupported file system\n"));
1161 Printf("Unsupported file system\n");
1164 D(bug("[install] core.img first block: %ld\n", block
));
1168 if (!writeCoreIMG(fh
, (UBYTE
*)buffer
, volume
))
1173 Printf("%s: Read Error\n", coreimgpath
);
1176 PrintFault(IoErr(), coreimgpath
);
1182 PrintFault(IoErr(), coreimgpath
);
1186 /* Installs boot.img to MBR and updates core.img */
1187 BOOL
installGrubFiles(struct Volume
*coreimgvol
, /* core.img volume */
1188 CONST_STRPTR grubpath
, /* path to grub files */
1189 ULONG unit
, /* unit core.img is on */
1190 struct Volume
*bootimgvol
) /* boot device for boot.img */
1192 BOOL retval
= FALSE
;
1193 TEXT bootimgpath
[256];
1196 D(bug("[install] installStageFiles(%x)\n", bootimgvol
));
1198 /* Flush GRUB volume's cache */
1201 block
= updateCoreIMG(grubpath
, coreimgvol
, bootimgvol
->blockbuffer
);
1205 AddPart(bootimgpath
, grubpath
, 256);
1206 AddPart(bootimgpath
, (CONST_STRPTR
) "boot.img", 256);
1207 if (writeBootIMG(bootimgpath
, bootimgvol
, coreimgvol
, block
, unit
))
1211 bug("failed %d\n", IoErr());
1216 int main(int argc
, char **argv
)
1218 struct RDArgs
*rdargs
;
1219 struct Volume
*grubvol
;
1220 struct Volume
*bbvol
;
1221 struct FileSysStartupMsg
*fssm
;
1222 int ret
= RETURN_OK
;
1224 PartitionBase
= (struct PartitionBase
*)OpenLibrary("partition.library", 3);
1227 Printf("Failed to open partition.library v3!\n");
1231 D(bug("[install] main()\n"));
1233 rdargs
= ReadArgs(template, myargs
, NULL
);
1236 CONST_STRPTR bootDevice
= (CONST_STRPTR
) myargs
[0];
1237 LONG unit
= *(LONG
*) myargs
[1];
1238 LONG
*partnum
= (LONG
*) myargs
[2];
1239 CONST_STRPTR grubpath
= (CONST_STRPTR
) myargs
[3];
1241 D(bug("[install] FORCELBA = %d\n", myargs
[4]));
1243 Printf("FORCELBA ignored\n");
1244 if (myargs
[ARG_TESTING
])
1245 Printf("Test mode. No data will be changed!\n");
1249 Printf("PARTITIONNUMBER not supported yet\n");
1251 return RETURN_ERROR
;
1254 fssm
= getDiskFSSM(grubpath
);
1257 CONST_STRPTR grubDevice
= AROS_BSTR_ADDR(fssm
->fssm_Device
);
1259 if (!strcmp((const char *) grubDevice
, (const char *) bootDevice
))
1261 struct DosEnvec
*dosEnvec
;
1262 dosEnvec
= (struct DosEnvec
*) BADDR(fssm
->fssm_Environ
);
1264 grubvol
= getGrubStageVolume(grubDevice
, fssm
->fssm_Unit
,
1265 fssm
->fssm_Flags
, dosEnvec
);
1268 DumpVolume(grubvol
, "GRUB volume");
1270 bbvol
= getBBVolume(bootDevice
, unit
, partnum
);
1273 DumpVolume(bbvol
, "Bootblock volume");
1275 if (!installGrubFiles(grubvol
, grubpath
,
1276 fssm
->fssm_Unit
, bbvol
))
1279 uninitVolume(bbvol
);
1283 D(bug("getBBVolume failed miserably\n"));
1287 uninitVolume(grubvol
);
1292 Printf("%s is not on device %s unit %ld\n",
1293 grubpath
, bootDevice
, (long)unit
);
1299 Printf("kernel path must begin with a device name\n");
1307 PrintFault(IoErr(), (STRPTR
) argv
[0]);
1309 CloseLibrary(&PartitionBase
->lib
);