Dereference symlinks when copying.
[tangerine.git] / workbench / c / install-i386-pc.c
blob4964d501067c0f6c054781dc7d7abefe9cc31e82
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /******************************************************************************
8 NAME
10 Install-i386-pc
12 SYNOPSIS
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
16 LOCATION
18 SYS:C
20 FUNCTION
22 Installs the GRUB bootloader to the bootblock of the specified disk.
24 INPUTS
26 DEVICE -- Device name (eg. ata.device)
27 UNIT -- Unit number
28 PN -- Partition number (advice: the first AROS FFS partition)
29 GRUB -- Path to GRUB directory.
30 FORCELBA -- Force use of LBA mode.
32 RESULT
34 NOTES
36 EXAMPLE
38 install-i386-pc device ata.device unit 0 PN 1 grub dh0:boot/grub
40 BUGS
42 SEE ALSO
44 Partition, Format
46 INTERNALS
48 ******************************************************************************/
50 #include <stdio.h>
51 #include <string.h>
52 #include <proto/dos.h>
53 #include <proto/exec.h>
54 #include <proto/partition.h>
55 #include <aros/macros.h>
56 #include <devices/hardblocks.h>
57 #include <devices/newstyle.h>
58 #include <dos/dos.h>
59 #include <exec/errors.h>
60 #include <exec/memory.h>
61 #include <libraries/partition.h>
63 #define DEBUG 0
64 #include <aros/debug.h>
66 /* Defines for grub data */
67 /* Stage 1 pointers */
68 #define MBR_BPBEND 0x3e
69 #define GRUB_BOOT_DRIVE 0x40
70 #define GRUB_FORCE_LBA 0x41
71 #define GRUB_STAGE2_SECTOR 0x44
72 #define MBR_PARTSTART 0x1be
73 #define MBR_PARTEND 0x1fe
74 /* Stage 2 pointers */
76 /* BIOS drive flag */
77 #define BIOS_HDISK_FLAG 0x80
79 #define MBR_MAX_PARTITIONS 4
80 #define MBRT_EXTENDED 0x05
81 #define MBRT_EXTENDED2 0x0f
83 struct Volume {
84 struct MsgPort *mp;
85 struct IOExtTD *iotd;
86 ULONG readcmd;
87 ULONG writecmd;
88 ULONG startblock;
89 ULONG countblock;
90 ULONG unitnum;
91 UWORD SizeBlock;
92 UBYTE flags;
93 BYTE partnum;
94 ULONG *blockbuffer;
97 #define VF_IS_TRACKDISK (1<<0)
98 #define VF_IS_RDB (1<<1)
100 struct BlockNode {
101 ULONG sector;
102 UWORD count;
103 UWORD seg_adr;
106 char *template =
107 "DEVICE/A,"
108 "UNIT/N/K/A,"
109 "PARTITIONNUMBER=PN/K/N," /* Partition whose boot block we should install stage1 in */
110 "GRUB/K/A,"
111 "FORCELBA/S";
112 IPTR myargs[7] = {0,0,0,0,0,0};
114 struct FileSysStartupMsg *getDiskFSSM(STRPTR path) {
115 struct DosList *dl;
116 struct DeviceNode *dn;
117 char dname[32];
118 UBYTE i;
120 D(bug("[install-i386] getDiskFSSM('%s')\n", path));
122 for (i=0;(path[i]) && (path[i]!=':');i++)
123 dname[i] = path[i];
124 if (path[i] == ':')
126 dname[i] = 0;
127 dl = LockDosList(LDF_READ);
128 if (dl)
130 dn = (struct DeviceNode *)FindDosEntry(dl, dname, LDF_DEVICES);
131 UnLockDosList(LDF_READ);
132 if (dn)
134 if (IsFileSystem(dname))
136 return (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);
138 else
139 printf("device '%s' doesn't contain a file system\n", dname);
141 else
142 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
145 else
146 printf("'%s' doesn't contain a device name\n",path);
147 return 0;
150 void fillGeometry(struct Volume *volume, struct DosEnvec *de) {
151 ULONG spc;
153 D(bug("[install-i386] fillGeometry(%x)\n", volume));
155 spc = de->de_Surfaces*de->de_BlocksPerTrack;
156 volume->SizeBlock = de->de_SizeBlock;
157 volume->startblock = de->de_LowCyl*spc;
158 volume->countblock =((de->de_HighCyl-de->de_LowCyl+1)*spc)-1+de->de_Reserved;
161 void nsdCheck(struct Volume *volume) {
162 struct NSDeviceQueryResult nsdq;
163 UWORD *cmdcheck;
165 D(bug("[install-i386] nsdCheck(%x)\n", volume));
167 if (
169 (volume->startblock+volume->countblock)* /* last block */
170 ((volume->SizeBlock<<2)/512) /* 1 portion (block) equals 512 (bytes) */
171 )>8388608)
173 nsdq.SizeAvailable=0;
174 nsdq.DevQueryFormat=0;
175 volume->iotd->iotd_Req.io_Command=NSCMD_DEVICEQUERY;
176 volume->iotd->iotd_Req.io_Data=&nsdq;
177 volume->iotd->iotd_Req.io_Length=sizeof(struct NSDeviceQueryResult);
178 if (DoIO((struct IORequest *)&volume->iotd->iotd_Req)==IOERR_NOCMD)
180 printf("Device doesn't understand NSD-Query\n");
182 else
184 if (
185 (volume->iotd->iotd_Req.io_Actual>sizeof(struct NSDeviceQueryResult)) ||
186 (volume->iotd->iotd_Req.io_Actual==0) ||
187 (volume->iotd->iotd_Req.io_Actual!=nsdq.SizeAvailable)
190 printf("WARNING wrong io_Actual using NSD\n");
192 else
194 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
195 printf("WARNING no trackdisk type\n");
196 for (cmdcheck=nsdq.SupportedCommands;*cmdcheck;cmdcheck++)
198 if (*cmdcheck == NSCMD_TD_READ64)
199 volume->readcmd = NSCMD_TD_READ64;
200 if (*cmdcheck == NSCMD_TD_WRITE64);
201 volume->writecmd = NSCMD_TD_WRITE64;
203 if (
204 (volume->readcmd!=NSCMD_TD_READ64) ||
205 (volume->writecmd!=NSCMD_TD_WRITE64)
207 printf("WARNING no READ64/WRITE64\n");
214 struct Volume *initVolume(STRPTR device, ULONG unit, ULONG flags, struct DosEnvec *de) {
215 struct Volume *volume;
216 LONG error=0;
218 D(bug("[install-i386] initVolume(%s:%d)\n", device, unit));
220 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
221 if (volume)
223 volume->mp = CreateMsgPort();
224 if (volume->mp)
226 volume->iotd = (struct IOExtTD *)CreateIORequest(volume->mp, sizeof(struct IOExtTD));
227 if (volume->iotd)
229 volume->blockbuffer = AllocVec(de->de_SizeBlock<<2, MEMF_PUBLIC | MEMF_CLEAR);
230 if (volume->blockbuffer)
232 if (
233 OpenDevice
235 device,
236 unit,
237 (struct IORequest *)volume->iotd,
238 flags
239 ) == 0
242 if (strcmp(device, "trackdisk.device")==0)
243 volume->flags |= VF_IS_TRACKDISK;
244 else
245 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
246 volume->readcmd = CMD_READ;
247 volume->writecmd = CMD_WRITE;
248 volume->unitnum = unit;
249 fillGeometry(volume, de);
250 nsdCheck(volume);
251 return volume;
253 else
254 error = ERROR_NO_FREE_STORE;
255 FreeVec(volume->blockbuffer);
257 else
258 error = ERROR_NO_FREE_STORE;
259 DeleteIORequest((struct IORequest *)volume->iotd);
261 else
262 error = ERROR_NO_FREE_STORE;
263 DeleteMsgPort(volume->mp);
265 else
266 error = ERROR_NO_FREE_STORE;
267 FreeVec(volume);
269 else
270 error = ERROR_NO_FREE_STORE;
271 PrintFault(error, NULL);
272 return 0;
275 void uninitVolume(struct Volume *volume)
278 D(bug("[install-i386] uninitVolume(%x)\n", volume));
280 CloseDevice((struct IORequest *)volume->iotd);
281 FreeVec(volume->blockbuffer);
282 DeleteIORequest((struct IORequest *)volume->iotd);
283 DeleteMsgPort(volume->mp);
284 FreeVec(volume);
287 ULONG readwriteBlock
289 struct Volume *volume,
290 ULONG block, APTR buffer, ULONG length,
291 ULONG command
294 UQUAD offset;
295 ULONG retval=0;
297 D(bug("[install-i386] readwriteBlock(vol:%x, block:%d, %d bytes)\n", volume, block, length));
299 volume->iotd->iotd_Req.io_Command = command;
300 volume->iotd->iotd_Req.io_Length = length;
301 volume->iotd->iotd_Req.io_Data = buffer;
302 offset = (UQUAD)(volume->startblock+block)*(volume->SizeBlock<<2);
303 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
304 volume->iotd->iotd_Req.io_Actual = offset>>32;
305 retval = DoIO((struct IORequest *)&volume->iotd->iotd_Req);
306 if (volume->flags & VF_IS_TRACKDISK)
308 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
309 volume->iotd->iotd_Req.io_Length = 0;
310 DoIO((struct IORequest *)&volume->iotd->iotd_Req);
312 return retval;
315 BOOL isvalidFileSystem(struct Volume *volume, STRPTR device, ULONG unit) {
316 BOOL retval = FALSE;
317 struct PartitionBase *PartitionBase;
318 struct PartitionHandle *ph;
320 D(bug("[install-i386] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
322 if (readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd))
324 printf("Read Error\n");
325 return FALSE;
327 if (
328 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
329 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
332 /* first block has no DOS\x so we don't have RDB for sure */
333 volume->flags &= ~VF_IS_RDB;
334 if (readwriteBlock(volume, 1, volume->blockbuffer, 512, volume->readcmd))
336 printf("Read Error\n");
337 return FALSE;
339 if (
340 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
341 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
343 return FALSE;
345 volume->partnum = -1;
346 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
347 if (PartitionBase)
349 ph = OpenRootPartition(device, unit);
350 if (ph)
352 if (OpenPartitionTable(ph) == 0)
354 struct TagItem tags[3];
355 IPTR type;
357 tags[1].ti_Tag = TAG_DONE;
358 tags[0].ti_Tag = PTT_TYPE;
359 tags[0].ti_Data = (STACKIPTR)&type;
360 GetPartitionTableAttrs(ph, tags);
361 if (type == PHPTT_MBR)
363 struct PartitionHandle *pn;
364 struct DosEnvec de;
365 struct PartitionHandle *extph = NULL;
366 struct PartitionType ptype = {0};
368 tags[0].ti_Tag = PT_DOSENVEC;
369 tags[0].ti_Data = (STACKIPTR)&de;
370 tags[1].ti_Tag = PT_TYPE;
371 tags[1].ti_Data = (STACKIPTR)&ptype;
372 tags[2].ti_Tag = TAG_DONE;
373 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
374 while (pn->ln.ln_Succ)
376 ULONG scp;
378 GetPartitionAttrs(pn, tags);
379 if (ptype.id[0] == MBRT_EXTENDED || ptype.id[0] == MBRT_EXTENDED2)
380 extph = pn;
381 else
383 scp = de.de_Surfaces*de.de_BlocksPerTrack;
384 if (
385 (volume->startblock>=(de.de_LowCyl*scp)) &&
386 (volume->startblock<=(((de.de_HighCyl+1)*scp)-1))
388 break;
390 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
392 if (pn->ln.ln_Succ)
394 tags[0].ti_Tag = PT_POSITION;
395 tags[0].ti_Data = (STACKIPTR)&type;
396 tags[1].ti_Tag = TAG_DONE;
397 GetPartitionAttrs(pn, tags);
398 volume->partnum = (UBYTE)type;
399 retval = TRUE;
400 D(bug("[install-i386] Primary partition found: partnum=%ld\n", volume->partnum));
402 else if (extph != NULL)
404 if (OpenPartitionTable(extph) == 0)
406 tags[0].ti_Tag = PTT_TYPE;
407 tags[0].ti_Data = (STACKIPTR)&type;
408 tags[1].ti_Tag = TAG_DONE;
409 GetPartitionTableAttrs(extph, tags);
410 if (type == PHPTT_EBR)
412 tags[0].ti_Tag = PT_DOSENVEC;
413 tags[0].ti_Data = (STACKIPTR)&de;
414 tags[1].ti_Tag = TAG_DONE;
415 pn = (struct PartitionHandle *)extph->table->list.lh_Head;
416 while (pn->ln.ln_Succ)
418 ULONG offset, scp;
420 offset = extph->de.de_LowCyl
421 * extph->de.de_Surfaces
422 * extph->de.de_BlocksPerTrack;
423 GetPartitionAttrs(pn, tags);
424 scp = de.de_Surfaces*de.de_BlocksPerTrack;
425 if (
426 (volume->startblock>=offset+(de.de_LowCyl*scp)) &&
427 (volume->startblock<=offset+(((de.de_HighCyl+1)*scp)-1))
429 break;
430 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
432 if (pn->ln.ln_Succ)
434 tags[0].ti_Tag = PT_POSITION;
435 tags[0].ti_Data = (STACKIPTR)&type;
436 GetPartitionAttrs(pn, tags);
437 volume->partnum = MBR_MAX_PARTITIONS + (UBYTE)type;
438 retval = TRUE;
439 D(bug("[install-i386] Logical partition found: partnum=%ld\n", volume->partnum));
442 ClosePartitionTable(extph);
446 else
448 if (type == PHPTT_RDB)
450 /* just use whole hard disk */
451 retval = TRUE;
453 else
454 printf("only MBR and RDB partition tables are supported\n");
456 ClosePartitionTable(ph);
458 else
460 /* just use whole hard disk */
461 retval = TRUE;
463 CloseRootPartition(ph);
465 else
466 printf("Error OpenRootPartition(%s,%ld)\n", device, unit);
467 CloseLibrary((struct Library *)PartitionBase);
469 else
470 printf("Couldn't open partition.library\n");
471 return retval;
474 struct Volume *getGrubStageVolume
476 STRPTR device,
477 ULONG unit,
478 ULONG flags,
479 struct DosEnvec *de
482 struct Volume *volume;
484 volume = initVolume(device, unit, flags, de);
486 D(bug("[install-i386] getGrubStageVolume(): volume=%x\n", volume));
488 if (volume)
490 if (isvalidFileSystem(volume, device, unit))
491 return volume;
492 else
494 printf("stage2 is on an unsupported file system\n");
495 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
497 uninitVolume(volume);
499 return 0;
502 BOOL isvalidPartition
504 STRPTR device,
505 ULONG unit,
506 LONG *pnum,
507 struct DosEnvec *de
510 struct PartitionBase *PartitionBase;
511 struct PartitionHandle *ph;
512 ULONG type;
513 BOOL retval=FALSE;
515 D(bug("[install-i386] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
517 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
518 if (PartitionBase)
520 ph = OpenRootPartition(device, unit);
521 if (ph)
523 struct TagItem tags[2];
525 tags[1].ti_Tag = TAG_DONE;
526 /* is there a partition table? */
527 if (OpenPartitionTable(ph) == 0)
529 if (pnum)
531 /* install into partition bootblock */
532 tags[0].ti_Tag = PTT_TYPE;
533 tags[0].ti_Data = (STACKIPTR)&type;
534 GetPartitionTableAttrs(ph, tags);
535 if (type == PHPTT_MBR)
537 struct PartitionHandle *pn;
539 /* search for partition */
540 tags[0].ti_Tag = PT_POSITION;
541 tags[0].ti_Data = (STACKIPTR)&type;
542 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
543 while (pn->ln.ln_Succ)
545 GetPartitionAttrs(pn, tags);
546 if (type == *pnum)
547 break;
548 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
550 if (pn->ln.ln_Succ)
552 struct PartitionType ptype;
554 /* is it an AROS partition? */
555 tags[0].ti_Tag = PT_TYPE;
556 tags[0].ti_Data = (STACKIPTR)&ptype;
557 GetPartitionAttrs(pn, tags);
558 if (ptype.id[0] == 0x30)
560 tags[0].ti_Tag = PT_DOSENVEC;
561 tags[0].ti_Data = (STACKIPTR)de;
562 GetPartitionAttrs(pn, tags);
563 retval = TRUE;
565 else
566 printf("partition is not of type AROS (0x30)\n");
568 else
570 printf
572 "partition %ld not found on device %s unit %ld\n",
573 *pnum, device, unit
577 else
578 printf("you can only install in partitions which are MBR partitioned\n");
580 else
582 /* install into MBR */
583 tags[0].ti_Tag = PTT_TYPE;
584 tags[0].ti_Data = (STACKIPTR)&type;
585 GetPartitionTableAttrs(ph, tags);
586 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
588 tags[0].ti_Tag = PT_DOSENVEC;
589 tags[0].ti_Data = (STACKIPTR)de;
590 GetPartitionAttrs(ph, tags);
591 retval = TRUE;
593 else
594 printf("partition table type must be either MBR or RDB\n");
596 ClosePartitionTable(ph);
598 else
600 #warning "FIXME: GetPartitionAttr() should always work for root partition"
601 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
602 retval = TRUE;
604 CloseRootPartition(ph);
606 else
607 printf("Error OpenRootPartition(%s,%ld)\n", device, unit);
608 CloseLibrary((struct Library *)PartitionBase);
610 else
611 printf("Couldn't open partition.library\n");
612 return retval;
615 struct Volume *getBBVolume(STRPTR device, ULONG unit, LONG *partnum) {
616 struct Volume *volume;
617 struct DosEnvec de;
619 D(bug("[install-i386] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
621 if (isvalidPartition(device, unit, partnum, &de))
623 volume = initVolume(device, unit, 0, &de);
624 volume->partnum = partnum ? *partnum : -1;
625 readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd);
626 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
628 memset(volume->blockbuffer,0x00, 446); /* Clear the boot sector region! */
629 return volume;
631 else
632 printf("no space for bootblock (RDB is on block 0)\n");
634 return NULL;
637 ULONG collectBlockList
639 struct Volume *volume,
640 ULONG block,
641 struct BlockNode *blocklist
644 ULONG retval, first_block;
645 WORD blk_count,count;
646 UWORD i;
648 D(bug("[install-i386] collectBlockList(%x, %d, %x)\n", volume, block, blocklist));
650 #warning "TODO: logical/physical blocks"
652 initialze stage2-blocklist
653 (it is NULL-terminated)
655 // for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
656 // blocklist[blk_count].sector = 0;
658 memset((char *)&blocklist[-20],0x00, 20*sizeof(struct BlockNode)); /* Clear the stage2 sector pointers region! */
659 D(bug("[install-i386] collectBlockList: Cleared sector list (20 entries) [start: %x, end %x]\n", &blocklist[-20], &blocklist[-1]));
662 the first block of stage2 will be stored in stage1
663 so skip the first filekey in the first loop
665 #warning "Block read twice"
666 retval=readwriteBlock
668 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
669 volume->readcmd
671 if (retval)
673 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld\n", retval));
674 printf("ReadError %ld\n", retval);
675 return 0;
678 i = volume->SizeBlock - 52;
679 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
680 blk_count=0;
682 D(bug("[install-i386] collectBlockList: First block @ %x, i:%d\n", first_block, i));
687 retval=readwriteBlock
689 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
690 volume->readcmd
692 if (retval)
694 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld)\n", retval));
695 printf("ReadError %ld\n", retval);
696 return 0;
698 D(bug("[install-i386] collectBlockList: read block %lx, i = %d\n", block, i));
699 while ((i>=6) && (volume->blockbuffer[i]))
701 D(bug("[install-i386] collectBlockList: i = %d\n", i));
703 if current sector follows right after last sector
704 then we don't need a new element
706 if (
707 (blocklist[blk_count].sector) &&
708 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
709 AROS_BE2LONG(volume->blockbuffer[i]))
712 blocklist[blk_count].count += 1;
713 D(bug("[install-i386] collectBlockList: sector %d follows previous - increasing count of block %d to %d\n", i, blk_count, blocklist[blk_count].count));
715 else
717 blk_count--; /* decrement first */
718 D(bug("[install-i386] collectBlockList: store new block (%d)\n", blk_count));
719 if (blocklist[blk_count-1].sector != 0)
721 D(bug("[install-i386] collectBlockList: ERROR: out of block space at sector %d, block %d\n", i, blk_count));
722 printf("There is no more space to save blocklist in stage2\n");
723 return 0;
725 D(bug("[install-i386] collectBlockList: storing sector pointer for %d in block %d\n", i, blk_count));
726 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
727 blocklist[blk_count].count = 1;
729 i--;
731 i = volume->SizeBlock - 51;
732 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
733 D(bug("[install-i386] collectBlockList: next block %d, i = %d\n", block, i));
734 } while (block);
736 blocks in blocklist are relative to the first
737 sector of the HD (not partition)
739 D(bug("[install-i386] collectBlockList: successfully updated pointers for %d blocks\n", blk_count));
741 i = 0;
742 for (count=-1;count>=blk_count;count--)
744 blocklist[count].sector += volume->startblock;
745 blocklist[count].seg_adr = 0x820 + (i*32);
746 i += blocklist[count].count;
747 D(bug("[install-i386] collectBlockList: correcting block %d for partition start\n", count));
748 D(bug("[install-i386] collectBlockList: sector : %x seg_adr : %x\n", blocklist[count].sector, blocklist[count].seg_adr));
750 return first_block;
753 void copyRootPath(char *dst, char *rpdos, BOOL isRDB) {
755 D(bug("[install-i386] copyRootPath()\n"));
757 if (isRDB)
759 /* we have an RDB so use devicename */
760 *dst++ = '/';
761 while ((*rpdos) && (*rpdos!=':'))
762 *dst++ = *rpdos++;
764 else
766 while ((*rpdos) && (*rpdos!=':'))
767 rpdos++;
769 rpdos++; /* skip colon */
770 *dst++ = '/';
771 /* append path */
772 while (*rpdos)
773 *dst++ = *rpdos++;
774 if (dst[-1] == '/')
775 dst[-1] = 0;
776 else
777 *dst = 0;
780 UBYTE *memstr(UBYTE *mem, UBYTE *str, LONG len) {
781 UBYTE *next;
782 UBYTE *search;
783 LONG left;
785 while (len)
787 len--;
788 if (*mem++ == *str)
790 next = mem;
791 search = str+1;
792 left = len;
793 while ((*search) && (left) && (*next++ == *search++))
794 left--;
795 if (*search == 0)
796 return mem-1;
799 return 0;
802 BOOL writeStage2
804 BPTR fh,
805 UBYTE *buffer,
806 STRPTR grubpath,
807 struct Volume *volume
810 BOOL retval = FALSE;
811 char *menuname;
813 D(bug("[install-i386] writeStage2(%x)\n", volume));
815 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
817 /* write back first block */
818 if (Write(fh, buffer, 512)==512)
820 /* read second stage2 block */
821 if (Read(fh, buffer, 512) == 512)
823 /* set partition number where stage2 is on */
824 buffer[8] = 0xFF;
825 buffer[9] = 0xFF;
826 buffer[10] = volume->partnum;
827 buffer[11] = 0;
828 /* get ptr to version string */
829 menuname = buffer+18;
830 while (*menuname++); /* skip version string */
831 copyRootPath(menuname, grubpath, volume->flags & VF_IS_RDB);
832 strcat(menuname, "/menu.lst");
833 /* write second stage2 block back */
834 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
836 if (Write(fh, buffer, 512) == 512)
838 retval = TRUE;
840 else
841 printf("%s: Write Error\n", menuname);
843 else
844 printf("%s: Seek Error\n", menuname);
846 else
847 printf("Read Error\n");
849 else
850 printf("Write Error\n");
852 else
853 PrintFault(IoErr(), NULL);
854 return retval;
857 ULONG changeStage2
859 STRPTR grubpath, /* path of grub dir */
860 struct Volume *volume, /* volume stage2 is on */
861 ULONG *buffer /* a buffer of at least 512 bytes */
864 ULONG block = 0;
865 struct FileInfoBlock fib;
866 BPTR fh;
867 char stage2path[256];
869 D(bug("[install-i386] changeStage2(%x)\n", volume));
871 AddPart(stage2path, grubpath, 256);
872 AddPart(stage2path, "stage2", 256);
873 fh = Open(stage2path, MODE_OLDFILE);
874 if (fh)
876 if (Examine(fh, &fib))
878 if (Read(fh, buffer, 512) == 512)
881 get and store all blocks of stage2 in first block of stage2
882 first block of stage2 will be returned
884 block = collectBlockList
885 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
887 if (block)
889 if (!writeStage2(fh, (UBYTE *)buffer, grubpath, volume))
890 block = 0;
893 else
894 printf("%s: Read Error\n", stage2path);
896 else
897 PrintFault(IoErr(), stage2path);
898 Close(fh);
900 else
901 PrintFault(IoErr(), stage2path);
902 return block;
905 BOOL writeStage1
907 STRPTR stage1path,
908 struct Volume *volume,
909 struct Volume *s2vol,
910 ULONG block, /* first block of stage2 file */
911 ULONG unit
914 BOOL retval = FALSE;
915 LONG error = 0;
916 BPTR fh;
918 D(bug("[install-i386] writeStage1(%x)\n", volume));
920 fh = Open(stage1path, MODE_OLDFILE);
921 if (fh)
923 if (Read(fh, volume->blockbuffer, 512) == 512)
925 /* install into MBR ? */
926 if ((volume->startblock == 0) && (!(volume->flags & VF_IS_TRACKDISK)))
928 D(bug("[install-i386] writeStage1: Install to HARDDISK\n"));
929 // read old MBR
930 error = readwriteBlock
931 (volume, 0, s2vol->blockbuffer, 512, volume->readcmd);
933 D(bug("[install-i386] writeStage1: MBR Buffer @ %x\n", volume->blockbuffer));
934 D(bug("[install-i386] writeStage1: Copying MBR BPB to %x\n", (char *)volume->blockbuffer + 0x04));
935 // copy BPB (BIOS Parameter Block)
936 CopyMem
938 (APTR)((char *)s2vol->blockbuffer + 0x04),
939 (APTR)((char *)volume->blockbuffer + 0x04),
940 (MBR_BPBEND - 4)
942 // copy partition table - [Overwrites Floppy boot code]
943 D(bug("[install-i386] writeStage1: Copying MBR Partitions to %x\n", (char *)volume->blockbuffer + MBR_PARTSTART));
944 CopyMem
946 (APTR)((char *)s2vol->blockbuffer + MBR_PARTSTART),
947 (APTR)((char *)volume->blockbuffer + MBR_PARTSTART),
948 (MBR_PARTEND - MBR_PARTSTART)
950 // store the drive num stage2 is stored on
951 ((char *)volume->blockbuffer)[GRUB_BOOT_DRIVE] = unit + BIOS_HDISK_FLAG;
952 // Store the stage 2 pointer ..
953 ULONG * stage2_sector_start = (ULONG *)((char *)volume->blockbuffer + GRUB_STAGE2_SECTOR);
954 D(bug("[install-i386] writeStage1: writing stage2 pointer @ %x\n", stage2_sector_start));
955 stage2_sector_start[0] = block;
956 D(bug("[install-i386] writeStage1: stage2 pointer = %x\n", stage2_sector_start[0]));
957 stage2_sector_start[0] += s2vol->startblock;
958 D(bug("[install-i386] writeStage1: + offset [%d] = %x\n", s2vol->startblock, stage2_sector_start[0]));
960 if (myargs[4]!=0)
962 D(bug("[install-i386] writeStage1: Forcing LBA\n"));
963 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 1;
965 else
967 D(bug("[install-i386] writeStage1: NOT Forcing LBA\n"));
968 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 0;
971 else
973 D(bug("[install-i386] writeStage1: Install to FLOPPY\n"));
976 if (error == 0)
978 error = readwriteBlock
979 (volume, 0, volume->blockbuffer, 512, volume->writecmd);
980 if (error)
981 printf("WriteError %ld\n", error);
982 else
983 retval = TRUE;
985 else
986 printf("WriteError %ld\n", error);
988 else
989 printf("%s: Read Error\n", stage1path);
990 Close(fh);
992 else
993 PrintFault(IoErr(), stage1path);
994 return retval;
997 /* Flushes the cache on the volume containing the specified path. */
998 VOID flushFS(CONST TEXT *path)
1000 char devname[256];
1001 UWORD i;
1003 for (i = 0; path[i] != ':'; i++)
1004 devname[i] = path[i];
1005 devname[i++] = ':';
1006 devname[i] = '\0';
1007 if (Inhibit(devname, DOSTRUE))
1008 Inhibit(devname, DOSFALSE);
1011 BOOL installStageFiles
1013 struct Volume *s2vol, /* stage2 volume */
1014 STRPTR stagepath, /* path to stage* files */
1015 ULONG unit, /* unit stage2 is on */
1016 struct Volume *s1vol /* device on which stage1 will be stored */
1019 BOOL retval = FALSE;
1020 char stagename[256];
1021 ULONG block;
1023 D(bug("[install-i386] installStageFiles(%x)\n", s1vol));
1025 /* Flush GRUB volume's cache */
1026 flushFS(stagepath);
1028 block = changeStage2(stagepath, s2vol, s1vol->blockbuffer);
1029 if (block)
1031 AddPart(stagename, stagepath, 256);
1032 AddPart(stagename, "stage1", 256);
1033 if (writeStage1(stagename, s1vol, s2vol, block, unit))
1034 retval = TRUE;
1036 return retval;
1039 int main(int argc, char **argv) {
1041 struct RDArgs *rdargs;
1042 struct Volume *grubvol;
1043 struct Volume *bbvol;
1044 struct FileSysStartupMsg *fssm;
1046 D(bug("[install-i386] main()\n"));
1048 rdargs = ReadArgs(template, myargs, NULL);
1049 if (rdargs)
1051 D(bug("[install-i386] FORCELBA = %d\n",myargs[4]));
1053 fssm = getDiskFSSM((STRPTR)myargs[3]);
1054 if (fssm != NULL)
1056 if (
1057 (strcmp(AROS_BSTR_ADDR(fssm->fssm_Device),(char*)myargs[0])==0)
1060 grubvol = getGrubStageVolume
1062 AROS_BSTR_ADDR(fssm->fssm_Device),
1063 fssm->fssm_Unit,
1064 fssm->fssm_Flags,
1065 (struct DosEnvec *)BADDR(fssm->fssm_Environ)
1067 if (grubvol)
1069 bbvol=getBBVolume
1071 (STRPTR)myargs[0],
1072 *((LONG *)myargs[1]),
1073 (LONG *)myargs[2]
1075 if (bbvol)
1077 ULONG retval=0;
1079 getBBVolume() read block 0
1080 if the partition directly contains a filesystem
1081 (currently only DOS\x is supported) we have
1082 to move block 0 to block 1 to make space for stage1
1084 if (
1085 (grubvol->startblock == bbvol->startblock) &&
1086 ((AROS_BE2LONG(bbvol->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
1089 grubvol->flags &= ~VF_IS_RDB;
1090 retval = readwriteBlock
1091 (bbvol, 0, bbvol->blockbuffer, 512, bbvol->readcmd);
1093 if (retval == 0)
1095 installStageFiles
1097 grubvol,
1098 (STRPTR)myargs[3], /* grub path (stage1/2) */
1099 fssm->fssm_Unit,
1100 bbvol
1103 else
1104 printf("Read Error: %ld\n", retval);
1105 uninitVolume(bbvol);
1107 uninitVolume(grubvol);
1110 else
1112 printf
1114 "%s is not on device %s unit %ld\n",
1115 (STRPTR)myargs[3], (STRPTR)myargs[0], *((LONG *)myargs[1])
1119 else
1120 if (fssm)
1121 printf("kernel path must begin with a device name\n");
1122 FreeArgs(rdargs);
1124 else
1125 PrintFault(IoErr(), argv[0]);
1126 return 0;