exec.library: Allocate/Deallocate functions must remain generic and not handler MemHe...
[AROS.git] / workbench / c / Install.c
blob32b495acdaf99fd32e7cf9cbad9d6ddf98474392
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: English
7 */
8 /******************************************************************************
11 NAME
13 Install
15 SYNOPSIS
17 DRIVE/A, NOBOOT/S, CHECK/S, FFS/S
19 LOCATION
23 FUNCTION
25 Saves a bootblock to a floppy disk. If the NOBOOT is appointed it
26 will not be able to be boot on computer startup (Amiga only)
28 INPUTS
30 DRIVE -- Show information on file system devices
31 NOBOOT -- Should be set on PC Floppy drives
32 CHECK -- Verify the existing bootblock
33 FFS -- For FFS formatted Floppy disks
35 RESULT
37 NOTES
39 This is a pretty useless command for PC-Drives, since most systems
40 require grub to be present on disk for AROS to boot.
42 EXAMPLE
44 Install df0: NOBOOT FFS
46 BUGS
48 SEE ALSO
50 Install-i386-pc, Sys:System/Format
52 INTERNALS
54 HISTORY
56 ******************************************************************************/
58 #include <string.h>
60 #include <proto/dos.h>
61 #include <proto/exec.h>
62 #include <proto/alib.h>
64 #include <devices/newstyle.h>
65 #include <devices/trackdisk.h>
66 #include <dos/dos.h>
67 #include <dos/dosextens.h>
68 #include <dos/filehandler.h>
69 #include <exec/errors.h>
70 #include <exec/io.h>
71 #include <exec/memory.h>
72 #include <exec/types.h>
73 #include <exec/ports.h>
74 #include <aros/macros.h>
76 struct Volume {
77 STRPTR drivename;
78 struct MsgPort *mp;
79 struct IOExtTD *iotd;
80 struct FileSysStartupMsg *fssm;
81 ULONG readcommand;
82 ULONG writecommand;
83 ULONG startblock;
84 ULONG countblock;
85 UWORD SizeBlock;
86 UBYTE flags;
87 ULONG *blockbuffer;
90 #define VF_IS_TRACKDISK (1<<0)
91 #define VF_MOVE_BB (1<<1)
93 struct BlockNode {
94 ULONG sector;
95 UWORD count;
96 UWORD seg_adr;
99 ULONG stage2_firstblock[128];
101 int readwriteBlock
103 struct Volume *volume,
104 ULONG block, APTR buffer, ULONG length,
105 ULONG command
108 UQUAD offset;
109 ULONG retval;
111 volume->iotd->iotd_Req.io_Command = command;
112 volume->iotd->iotd_Req.io_Length = length;
113 volume->iotd->iotd_Req.io_Data = buffer;
114 offset = (UQUAD)(volume->startblock+block)*(volume->SizeBlock*4);
115 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
116 volume->iotd->iotd_Req.io_Actual = offset>>32;
117 retval = DoIO((struct IORequest *)&volume->iotd->iotd_Req);
118 if (volume->flags & VF_IS_TRACKDISK)
120 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
121 volume->iotd->iotd_Req.io_Length = 0;
122 DoIO((struct IORequest *)&volume->iotd->iotd_Req);
124 return retval;
127 ULONG collectBlockList(struct Volume *volume, ULONG block, struct BlockNode *blocklist) {
128 ULONG retval, first_block;
129 WORD blk_count,count;
130 UWORD i;
132 /* TODO: logical/physical blocks */
134 initialze stage2-blocklist
135 (it is NULL-terminated)
137 for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
138 blocklist[blk_count].sector = 0;
140 the first block of stage2 will be stored in stage1
141 so skip the first filekey in the first loop
143 /* FIXME: Block read twice */
144 retval=readwriteBlock
146 volume, block, volume->blockbuffer, volume->SizeBlock*4,
147 volume->readcommand
149 i = volume->SizeBlock - 52;
150 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
151 blk_count=0;
152 do {
153 retval=readwriteBlock
155 volume, block, volume->blockbuffer, volume->SizeBlock*4,
156 volume->readcommand
158 if (retval)
160 Printf("ReadError %lu\n", (long)retval);
161 return 0;
163 while ((i>=6) && (volume->blockbuffer[i]))
166 if current sector follows right after last sector
167 then we don't need a new element
169 if (
170 (blocklist[blk_count].sector) &&
171 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
172 AROS_BE2LONG(volume->blockbuffer[i]))
175 blocklist[blk_count].count += 1;
177 else
179 blk_count--; /* decrement first */
180 if (blocklist[blk_count-1].sector != 0)
182 Printf("There is no more space to save blocklist in stage2\n");
183 return 0;
185 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
186 blocklist[blk_count].count = 1;
188 i--;
190 i = volume->SizeBlock - 51;
191 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
192 } while (block);
194 blocks in blocklist are relative to the first
195 sector of the HD (not partition)
197 i = 0;
198 for (count=-1;count>=blk_count;count--)
200 blocklist[count].sector += volume->startblock;
201 blocklist[count].seg_adr = 0x820 + (i*32);
202 i += blocklist[count].count;
204 return first_block;
207 /*************************************
208 Name : installStageFiles
209 Descr.: install stage1 and initialize stage2
210 Input : volume - the volume to install on
211 use_mbr - flag to use MBR
212 stage2_drive - the unit stage2 is located
213 **************************************/
214 void installStageFiles(struct Volume *volume, LONG use_mbr, UBYTE stage2_drive) {
215 char stagename[256];
216 struct FileInfoBlock fib;
217 BPTR fh, fh2;
218 ULONG block,retval;
219 ULONG error=0;
220 STRPTR errstr=NULL;
223 strcpy(stagename, (char *)volume->drivename);
224 strcat(stagename, "Boot/grub/stage2");
225 fh = Open(stagename,MODE_OLDFILE);
226 if (fh)
228 if (ExamineFH(fh, &fib))
230 if (Read(fh, stage2_firstblock, 512) == 512)
232 if ((volume->flags & VF_MOVE_BB) && !use_mbr)
234 readwriteBlock
236 volume, 1, volume->blockbuffer, 512,
237 volume->writecommand
240 if (
242 block=collectBlockList
244 volume, fib.fib_DiskKey,
245 (struct BlockNode *)&stage2_firstblock[128]
250 if (Seek(fh, 0, OFFSET_BEGINNING)!=-1)
252 if (Write(fh, stage2_firstblock, 512)==512)
254 strcpy(stagename, (char *)volume->drivename);
255 strcat(stagename, "Boot/grub/stage1");
256 fh2 = Open(stagename, MODE_OLDFILE);
257 if (fh2)
259 if (Read(fh2, volume->blockbuffer, 512) == 512)
261 volume->blockbuffer[17]=block;
262 retval = 0;
263 if (use_mbr)
265 volume->blockbuffer[17] += volume->startblock;
266 volume->startblock = 0;
267 retval = readwriteBlock
269 volume, 0,
270 stage2_firstblock, 512, volume->readcommand
272 /* copy BPB (BIOS Parameter Block)*/
273 CopyMem
275 (APTR)((char *)stage2_firstblock+0x3),
276 (APTR)((char *)volume->blockbuffer+0x3),
277 0x3B
279 /* copy partition table */
280 CopyMem
282 (APTR)((char *)stage2_firstblock+0x1BE),
283 (APTR)((char *)volume->blockbuffer+0x1BE),
284 0x40
286 /* store the drive num stage2 is stored on */
287 ((char *)volume->blockbuffer)[0x40] = stage2_drive+0x80;
289 if (retval==0)
291 retval = readwriteBlock
293 volume, 0,
294 volume->blockbuffer, 512, volume->writecommand
296 if (retval)
297 Printf("WriteError %lu\n", (long)retval);
299 else
300 Printf("WriteErrro %lu\n", (long)retval);
302 else
303 error = IoErr();
304 Close(fh2);
306 else
308 error = IoErr();
309 errstr = stagename;
312 else
313 error = IoErr();
315 else
316 error = IoErr();
319 else
321 error = IoErr();
322 errstr = stagename;
325 else
327 error = IoErr();
328 errstr = stagename;
330 Close(fh);
332 else
334 error = IoErr();
335 errstr = stagename;
337 if (error)
338 PrintFault(error, errstr);
341 void nsdCheck(struct Volume *volume) {
342 struct NSDeviceQueryResult nsdq;
343 UWORD *cmdcheck;
344 if (
346 (volume->startblock+volume->countblock)* /* last block */
347 (volume->SizeBlock*4/512) /* 1 portion (block) equals 512 (bytes) */
348 )>8388608)
350 nsdq.SizeAvailable=0;
351 nsdq.DevQueryFormat=0;
352 volume->iotd->iotd_Req.io_Command=NSCMD_DEVICEQUERY;
353 volume->iotd->iotd_Req.io_Data=&nsdq;
354 volume->iotd->iotd_Req.io_Length=sizeof(struct NSDeviceQueryResult);
355 if (DoIO((struct IORequest *)&volume->iotd->iotd_Req)==IOERR_NOCMD)
357 Printf("Device doesn't understand NSD-Query\n");
359 else
361 if (
362 (volume->iotd->iotd_Req.io_Actual>sizeof(struct NSDeviceQueryResult)) ||
363 (volume->iotd->iotd_Req.io_Actual==0) ||
364 (volume->iotd->iotd_Req.io_Actual!=nsdq.SizeAvailable)
367 Printf("WARNING wrong io_Actual using NSD\n");
369 else
371 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
372 Printf("WARNING no trackdisk type\n");
373 for (cmdcheck=nsdq.SupportedCommands;*cmdcheck;cmdcheck++)
375 if (*cmdcheck == NSCMD_TD_READ64)
376 volume->readcommand = NSCMD_TD_READ64;
377 if (*cmdcheck == NSCMD_TD_WRITE64);
378 volume->writecommand = NSCMD_TD_WRITE64;
380 if (
381 (volume->readcommand!=NSCMD_TD_READ64) ||
382 (volume->writecommand!=NSCMD_TD_WRITE64)
384 Printf("WARNING no READ64/WRITE64\n");
390 struct Volume *initVolume(STRPTR drivename, IPTR use_mbr) {
391 struct Volume *volume=0;
392 struct FileSysStartupMsg *fssm;
393 struct DosList *dl;
394 struct DosEnvec *de;
395 struct DeviceNode *dn;
396 char dname[32];
397 UBYTE i;
398 ULONG error=0,retval;
399 STRPTR errstr=NULL;
401 for (i=0;(drivename[i]) && (drivename[i]!=':');i++)
402 dname[i]=drivename[i];
403 dname[i]=0;
404 dl = LockDosList(LDF_READ | LDF_DEVICES);
405 if (dl)
407 dn = (struct DeviceNode *)FindDosEntry(dl, dname, LDF_DEVICES);
408 UnLockDosList(LDF_READ | LDF_DEVICES);
409 if (dn)
411 if (IsFileSystem(drivename))
413 fssm = (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);
414 if (use_mbr)
416 if (strcmp(AROS_BSTR_ADDR(fssm->fssm_Device),"ide.device")!=0)
418 error = ERROR_OBJECT_WRONG_TYPE;
419 errstr = AROS_BSTR_ADDR(fssm->fssm_Device);
421 else
423 if (fssm->fssm_Unit!=0)
425 error = ERROR_OBJECT_WRONG_TYPE;
426 errstr = "MBR can only be stored on the first HD";
430 if (error == 0)
432 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
433 if (volume)
435 volume->fssm = fssm;
436 volume->drivename = drivename;
437 volume->mp = CreateMsgPort();
438 if (volume->mp)
440 volume->iotd = (struct IOExtTD *)CreateIORequest(volume->mp, sizeof(struct IOExtTD));
441 if (volume->iotd)
443 de = BADDR(volume->fssm->fssm_Environ);
444 volume->SizeBlock = de->de_SizeBlock;
445 volume->blockbuffer = AllocVec(volume->SizeBlock*4, MEMF_PUBLIC | MEMF_CLEAR);
446 if (volume->blockbuffer)
448 if (
449 OpenDevice
451 AROS_BSTR_ADDR(volume->fssm->fssm_Device),
452 volume->fssm->fssm_Unit,
453 (struct IORequest *)&volume->iotd->iotd_Req,
454 volume->fssm->fssm_Flags
455 )==0
458 if (strcmp(AROS_BSTR_ADDR(volume->fssm->fssm_Device), "trackdisk.device") == 0)
459 volume->flags |= VF_IS_TRACKDISK;
460 volume->startblock =
461 de->de_LowCyl*
462 de->de_Surfaces*
463 de->de_BlocksPerTrack;
464 volume->countblock =
467 de->de_HighCyl-de->de_LowCyl+1
468 )*de->de_Surfaces*de->de_BlocksPerTrack
469 )-1+de->de_Reserved;
470 volume->readcommand = CMD_READ;
471 volume->writecommand = CMD_WRITE;
472 nsdCheck(volume);
473 retval = readwriteBlock
475 volume, 0,
476 volume->blockbuffer, 512, volume->readcommand
478 if (retval == 0)
480 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300)
482 retval = readwriteBlock
484 volume, 1,
485 volume->blockbuffer, 512, volume->readcommand
488 else
489 volume->flags |= VF_MOVE_BB;
490 if (
491 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300) &&
492 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF)>0)
495 return volume;
497 else
498 error = ERROR_NOT_A_DOS_DISK;
500 else
502 error = ERROR_UNKNOWN;
503 errstr = "Read Error";
506 else
508 error = ERROR_UNKNOWN;
509 errstr = "OpenDevice() Error";
511 FreeVec(volume->blockbuffer);
513 else
514 error = ERROR_NO_FREE_STORE;
516 else
517 error = ERROR_NO_FREE_STORE;
518 DeleteMsgPort(volume->mp);
520 else
521 error = ERROR_NO_FREE_STORE;
522 FreeVec(volume);
523 volume = 0;
525 else
526 error = ERROR_NO_FREE_STORE;
529 else
530 error = IoErr();
532 else
534 error = ERROR_OBJECT_NOT_FOUND;
535 errstr = dname;
538 else
540 error = ERROR_UNKNOWN;
541 errstr = "LockDosList Error";
543 PrintFault(error, errstr);
544 return 0;
547 void uninitVolume(struct Volume *volume) {
549 FreeVec(volume->blockbuffer);
550 CloseDevice((struct IORequest *)&volume->iotd->iotd_Req);
551 DeleteIORequest((struct IORequest *)volume->iotd);
552 DeleteMsgPort(volume->mp);
553 FreeVec(volume);
556 void checkBootCode(struct Volume *volume) {
557 Printf("CHECK not implemented yet\n");
560 void removeBootCode(struct Volume *volume) {
561 ULONG retval;
563 retval = readwriteBlock
565 volume, 1,
566 volume->blockbuffer, 512, volume->readcommand
568 if (retval)
569 Printf("ReadError %lu\n", (long)retval);
570 else
572 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
574 retval = readwriteBlock
576 volume, 0,
577 volume->blockbuffer, 512, volume->writecommand
579 if (retval)
580 Printf("WriteError %lu\n", (long)retval);
585 int main(void) {
586 IPTR myargs[5]={0,0,0,0,0};
587 struct RDArgs *rdargs;
588 struct Volume *volume;
590 rdargs = ReadArgs("DRIVE/A,NOBOOT/S,CHECK/S,FFS/S,MBR/S",myargs,NULL);
591 if (rdargs)
593 volume = initVolume((STRPTR)myargs[0], myargs[4]);
594 if (volume)
596 if (myargs[1])
597 removeBootCode(volume);
598 else if (myargs[2])
599 checkBootCode(volume);
600 else
601 installStageFiles(volume, myargs[4], volume->fssm->fssm_Unit);
602 uninitVolume(volume);
604 FreeArgs(rdargs);
606 else
607 PrintFault(IoErr(), NULL);
608 return 0;