use m4_normalize on the output strings to remove trailing spaces/tabs and consolidate...
[AROS.git] / workbench / c / Install.c
blob97480e4aa1f663ed7e80cb43a09b3525bf0f2e4f
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Install CLI command
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>
75 #ifndef ERROR_UNKNOWN
76 #define ERROR_UNKNOWN 100
77 #define AROS_BSTR_ADDR(s) (((STRPTR)BADDR(s))+1)
78 #endif
80 const TEXT version[] = "$VER: Install 42.1 (19.2.2015)\n";
82 struct Volume {
83 STRPTR drivename;
84 struct MsgPort *mp;
85 struct IOExtTD *iotd;
86 struct FileSysStartupMsg *fssm;
87 ULONG readcommand;
88 ULONG writecommand;
89 ULONG startblock;
90 ULONG countblock;
91 UWORD SizeBlock;
92 UBYTE flags;
93 ULONG *blockbuffer;
96 #define VF_IS_TRACKDISK (1<<0)
97 #define VF_MOVE_BB (1<<1)
99 struct BlockNode {
100 ULONG sector;
101 UWORD count;
102 UWORD seg_adr;
105 ULONG stage2_firstblock[128];
107 int readwriteBlock
109 struct Volume *volume,
110 ULONG block, APTR buffer, ULONG length,
111 ULONG command
114 UQUAD offset;
115 ULONG retval;
117 volume->iotd->iotd_Req.io_Command = command;
118 volume->iotd->iotd_Req.io_Length = length;
119 volume->iotd->iotd_Req.io_Data = buffer;
120 offset = (UQUAD)(volume->startblock+block)*(volume->SizeBlock*4);
121 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
122 volume->iotd->iotd_Req.io_Actual = offset>>32;
123 retval = DoIO((struct IORequest *)&volume->iotd->iotd_Req);
124 if (volume->flags & VF_IS_TRACKDISK)
126 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
127 volume->iotd->iotd_Req.io_Length = 0;
128 DoIO((struct IORequest *)&volume->iotd->iotd_Req);
130 return retval;
133 ULONG collectBlockList(struct Volume *volume, ULONG block, struct BlockNode *blocklist) {
134 ULONG retval, first_block;
135 WORD blk_count,count;
136 UWORD i;
138 /* TODO: logical/physical blocks */
140 initialze stage2-blocklist
141 (it is NULL-terminated)
143 for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
144 blocklist[blk_count].sector = 0;
146 the first block of stage2 will be stored in stage1
147 so skip the first filekey in the first loop
149 /* FIXME: Block read twice */
150 retval=readwriteBlock
152 volume, block, volume->blockbuffer, volume->SizeBlock*4,
153 volume->readcommand
155 i = volume->SizeBlock - 52;
156 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
157 blk_count=0;
158 do {
159 retval=readwriteBlock
161 volume, block, volume->blockbuffer, volume->SizeBlock*4,
162 volume->readcommand
164 if (retval)
166 Printf("ReadError %lu\n", (long)retval);
167 return 0;
169 while ((i>=6) && (volume->blockbuffer[i]))
172 if current sector follows right after last sector
173 then we don't need a new element
175 if (
176 (blocklist[blk_count].sector) &&
177 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
178 AROS_BE2LONG(volume->blockbuffer[i]))
181 blocklist[blk_count].count += 1;
183 else
185 blk_count--; /* decrement first */
186 if (blocklist[blk_count-1].sector != 0)
188 Printf("There is no more space to save blocklist in stage2\n");
189 return 0;
191 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
192 blocklist[blk_count].count = 1;
194 i--;
196 i = volume->SizeBlock - 51;
197 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
198 } while (block);
200 blocks in blocklist are relative to the first
201 sector of the HD (not partition)
203 i = 0;
204 for (count=-1;count>=blk_count;count--)
206 blocklist[count].sector += volume->startblock;
207 blocklist[count].seg_adr = 0x820 + (i*32);
208 i += blocklist[count].count;
210 return first_block;
213 /*************************************
214 Name : installStageFiles
215 Descr.: install stage1 and initialize stage2
216 Input : volume - the volume to install on
217 use_mbr - flag to use MBR
218 stage2_drive - the unit stage2 is located
219 **************************************/
220 void installStageFiles(struct Volume *volume, LONG use_mbr, UBYTE stage2_drive) {
221 char stagename[256];
222 struct FileInfoBlock fib;
223 BPTR fh, fh2;
224 ULONG block,retval;
225 ULONG error=0;
226 STRPTR errstr=NULL;
229 strcpy(stagename, (char *)volume->drivename);
230 strcat(stagename, "Boot/grub/stage2");
231 fh = Open(stagename,MODE_OLDFILE);
232 if (fh)
234 if (ExamineFH(fh, &fib))
236 if (Read(fh, stage2_firstblock, 512) == 512)
238 if ((volume->flags & VF_MOVE_BB) && !use_mbr)
240 readwriteBlock
242 volume, 1, volume->blockbuffer, 512,
243 volume->writecommand
246 if (
248 block=collectBlockList
250 volume, fib.fib_DiskKey,
251 (struct BlockNode *)&stage2_firstblock[128]
256 if (Seek(fh, 0, OFFSET_BEGINNING)!=-1)
258 if (Write(fh, stage2_firstblock, 512)==512)
260 strcpy(stagename, (char *)volume->drivename);
261 strcat(stagename, "Boot/grub/stage1");
262 fh2 = Open(stagename, MODE_OLDFILE);
263 if (fh2)
265 if (Read(fh2, volume->blockbuffer, 512) == 512)
267 volume->blockbuffer[17]=block;
268 retval = 0;
269 if (use_mbr)
271 volume->blockbuffer[17] += volume->startblock;
272 volume->startblock = 0;
273 retval = readwriteBlock
275 volume, 0,
276 stage2_firstblock, 512, volume->readcommand
278 /* copy BPB (BIOS Parameter Block)*/
279 CopyMem
281 (APTR)((char *)stage2_firstblock+0x3),
282 (APTR)((char *)volume->blockbuffer+0x3),
283 0x3B
285 /* copy partition table */
286 CopyMem
288 (APTR)((char *)stage2_firstblock+0x1BE),
289 (APTR)((char *)volume->blockbuffer+0x1BE),
290 0x40
292 /* store the drive num stage2 is stored on */
293 ((char *)volume->blockbuffer)[0x40] = stage2_drive+0x80;
295 if (retval==0)
297 retval = readwriteBlock
299 volume, 0,
300 volume->blockbuffer, 512, volume->writecommand
302 if (retval)
303 Printf("WriteError %lu\n", (long)retval);
305 else
306 Printf("WriteErrro %lu\n", (long)retval);
308 else
309 error = IoErr();
310 Close(fh2);
312 else
314 error = IoErr();
315 errstr = stagename;
318 else
319 error = IoErr();
321 else
322 error = IoErr();
325 else
327 error = IoErr();
328 errstr = stagename;
331 else
333 error = IoErr();
334 errstr = stagename;
336 Close(fh);
338 else
340 error = IoErr();
341 errstr = stagename;
343 if (error)
344 PrintFault(error, errstr);
347 void nsdCheck(struct Volume *volume) {
348 struct NSDeviceQueryResult nsdq;
349 UWORD *cmdcheck;
350 if (
352 (volume->startblock+volume->countblock)* /* last block */
353 (volume->SizeBlock*4/512) /* 1 portion (block) equals 512 (bytes) */
354 )>8388608)
356 nsdq.SizeAvailable=0;
357 nsdq.DevQueryFormat=0;
358 volume->iotd->iotd_Req.io_Command=NSCMD_DEVICEQUERY;
359 volume->iotd->iotd_Req.io_Data=&nsdq;
360 volume->iotd->iotd_Req.io_Length=sizeof(struct NSDeviceQueryResult);
361 if (DoIO((struct IORequest *)&volume->iotd->iotd_Req)==IOERR_NOCMD)
363 Printf("Device doesn't understand NSD-Query\n");
365 else
367 if (
368 (volume->iotd->iotd_Req.io_Actual>sizeof(struct NSDeviceQueryResult)) ||
369 (volume->iotd->iotd_Req.io_Actual==0) ||
370 (volume->iotd->iotd_Req.io_Actual!=nsdq.SizeAvailable)
373 Printf("WARNING wrong io_Actual using NSD\n");
375 else
377 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
378 Printf("WARNING no trackdisk type\n");
379 for (cmdcheck=nsdq.SupportedCommands;*cmdcheck;cmdcheck++)
381 if (*cmdcheck == NSCMD_TD_READ64)
382 volume->readcommand = NSCMD_TD_READ64;
383 if (*cmdcheck == NSCMD_TD_WRITE64)
384 volume->writecommand = NSCMD_TD_WRITE64;
386 if (
387 (volume->readcommand!=NSCMD_TD_READ64) ||
388 (volume->writecommand!=NSCMD_TD_WRITE64)
390 Printf("WARNING no READ64/WRITE64\n");
396 struct Volume *initVolume(STRPTR drivename, IPTR use_mbr) {
397 struct Volume *volume=0;
398 struct FileSysStartupMsg *fssm;
399 struct DosList *dl;
400 struct DosEnvec *de;
401 struct DeviceNode *dn;
402 char dname[32];
403 UBYTE i;
404 ULONG error=0,retval;
405 STRPTR errstr=NULL;
407 for (i=0;(drivename[i]) && (drivename[i]!=':');i++)
408 dname[i]=drivename[i];
409 dname[i]=0;
410 dl = LockDosList(LDF_READ | LDF_DEVICES);
411 if (dl)
413 dn = (struct DeviceNode *)FindDosEntry(dl, dname, LDF_DEVICES);
414 UnLockDosList(LDF_READ | LDF_DEVICES);
415 if (dn)
417 if (IsFileSystem(drivename))
419 fssm = (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);
420 if (use_mbr)
422 if (strcmp(AROS_BSTR_ADDR(fssm->fssm_Device),"ide.device")!=0)
424 error = ERROR_OBJECT_WRONG_TYPE;
425 errstr = AROS_BSTR_ADDR(fssm->fssm_Device);
427 else
429 if (fssm->fssm_Unit!=0)
431 error = ERROR_OBJECT_WRONG_TYPE;
432 errstr = "MBR can only be stored on the first HD";
436 if (error == 0)
438 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
439 if (volume)
441 volume->fssm = fssm;
442 volume->drivename = drivename;
443 volume->mp = CreateMsgPort();
444 if (volume->mp)
446 volume->iotd = (struct IOExtTD *)CreateIORequest(volume->mp, sizeof(struct IOExtTD));
447 if (volume->iotd)
449 de = BADDR(volume->fssm->fssm_Environ);
450 volume->SizeBlock = de->de_SizeBlock;
451 volume->blockbuffer = AllocVec(volume->SizeBlock*4, MEMF_PUBLIC | MEMF_CLEAR);
452 if (volume->blockbuffer)
454 if (
455 OpenDevice
457 AROS_BSTR_ADDR(volume->fssm->fssm_Device),
458 volume->fssm->fssm_Unit,
459 (struct IORequest *)&volume->iotd->iotd_Req,
460 volume->fssm->fssm_Flags
461 )==0
464 if (strcmp(AROS_BSTR_ADDR(volume->fssm->fssm_Device), "trackdisk.device") == 0)
465 volume->flags |= VF_IS_TRACKDISK;
466 volume->startblock =
467 de->de_LowCyl*
468 de->de_Surfaces*
469 de->de_BlocksPerTrack;
470 volume->countblock =
473 de->de_HighCyl-de->de_LowCyl+1
474 )*de->de_Surfaces*de->de_BlocksPerTrack
475 )-1+de->de_Reserved;
476 volume->readcommand = CMD_READ;
477 volume->writecommand = CMD_WRITE;
478 nsdCheck(volume);
479 retval = readwriteBlock
481 volume, 0,
482 volume->blockbuffer, 512, volume->readcommand
484 if (retval == 0)
486 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300)
488 retval = readwriteBlock
490 volume, 1,
491 volume->blockbuffer, 512, volume->readcommand
494 else
495 volume->flags |= VF_MOVE_BB;
496 if (
497 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300) &&
498 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF)>0)
501 return volume;
503 else
504 error = ERROR_NOT_A_DOS_DISK;
506 else
508 error = ERROR_UNKNOWN;
509 errstr = "Read Error";
512 else
514 error = ERROR_UNKNOWN;
515 errstr = "OpenDevice() Error";
517 FreeVec(volume->blockbuffer);
519 else
520 error = ERROR_NO_FREE_STORE;
522 else
523 error = ERROR_NO_FREE_STORE;
524 DeleteMsgPort(volume->mp);
526 else
527 error = ERROR_NO_FREE_STORE;
528 FreeVec(volume);
529 volume = 0;
531 else
532 error = ERROR_NO_FREE_STORE;
535 else
536 error = IoErr();
538 else
540 error = ERROR_OBJECT_NOT_FOUND;
541 errstr = dname;
544 else
546 error = ERROR_UNKNOWN;
547 errstr = "LockDosList Error";
549 PrintFault(error, errstr);
550 return 0;
553 void uninitVolume(struct Volume *volume) {
555 FreeVec(volume->blockbuffer);
556 CloseDevice((struct IORequest *)&volume->iotd->iotd_Req);
557 DeleteIORequest((struct IORequest *)volume->iotd);
558 DeleteMsgPort(volume->mp);
559 FreeVec(volume);
562 void checkBootCode(struct Volume *volume) {
563 Printf("CHECK not implemented yet\n");
566 void removeBootCode(struct Volume *volume) {
567 ULONG retval;
569 retval = readwriteBlock
571 volume, 1,
572 volume->blockbuffer, 512, volume->readcommand
574 if (retval)
575 Printf("ReadError %lu\n", (long)retval);
576 else
578 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
580 retval = readwriteBlock
582 volume, 0,
583 volume->blockbuffer, 512, volume->writecommand
585 if (retval)
586 Printf("WriteError %lu\n", (long)retval);
591 int main(void) {
592 IPTR myargs[5]={0,0,0,0,0};
593 struct RDArgs *rdargs;
594 struct Volume *volume;
596 rdargs = ReadArgs("DRIVE/A,NOBOOT/S,CHECK/S,FFS/S,MBR/S",myargs,NULL);
597 if (rdargs)
599 volume = initVolume((STRPTR)myargs[0], myargs[4]);
600 if (volume)
602 if (myargs[1])
603 removeBootCode(volume);
604 else if (myargs[2])
605 checkBootCode(volume);
606 else
607 installStageFiles(volume, myargs[4], volume->fssm->fssm_Unit);
608 uninitVolume(volume);
610 FreeArgs(rdargs);
612 else
613 PrintFault(IoErr(), NULL);
614 return 0;