Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / i386-pc / boot / floppy / install.c
blob725afb40f0776a7ec684753a1a4b1d04137edde4
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <errno.h>
7 #include <strings.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <fcntl.h>
12 #include <sys/stat.h>
14 #warning "Only for little endian machines!!!"
15 # define AROS_BE2LONG(l) \
16 ( \
17 ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \
18 ((((unsigned long)(l)) >> 8) & 0x0000FF00UL) | \
19 ((((unsigned long)(l)) << 8) & 0x00FF0000UL) | \
20 ((((unsigned long)(l)) << 24) & 0xFF000000UL) \
23 #define CMD_READ 1
24 #define CMD_WRITE 2
26 #define ERR_BAD_FILETYPE 1
27 #define ERR_FILE_NOT_FOUND 2
28 #define ERR_FSYS_CORRUPT 3
30 #define T_SHORT 2
32 #define ST_ROOT 1
33 #define ST_USERDIR 2
35 struct Volume {
36 int fd;
37 unsigned short readcommand;
38 unsigned short writecommand;
39 unsigned int startblock;
40 unsigned int countblock;
41 unsigned short SizeBlock;
42 unsigned char flags;
43 unsigned int *blockbuffer;
46 #define VF_IS_TRACKDISK (1<<0)
47 #define VF_MOVE_BB (1<<1)
49 struct BlockNode {
50 unsigned int sector;
51 unsigned short count;
52 unsigned short seg_adr;
55 unsigned int stage2_firstblock[128];
57 int readwriteBlock
59 struct Volume *volume,
60 unsigned int block,
61 void *buffer,
62 size_t length,
63 unsigned short command
66 off_t offset;
67 int retval;
69 offset = (volume->startblock+block)*(volume->SizeBlock*4);
70 if (lseek(volume->fd, offset,SEEK_SET)!=-1)
72 if (command == CMD_READ)
74 if (read(volume->fd, buffer, length)!=-1)
75 return 0;
77 else if (command == CMD_WRITE)
79 if (write(volume->fd, buffer, length)!=-1)
80 return 0;
82 else
83 errno = 0;
85 return errno;
88 unsigned int collectBlockList
90 struct Volume *volume,
91 unsigned int block,
92 struct BlockNode *blocklist
95 unsigned int retval, first_block;
96 short blk_count,count;
97 unsigned short i;
99 #warning "TODO: logical/physical blocks"
101 initialze stage2-blocklist
102 (it is NULL-terminated)
104 for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
105 blocklist[blk_count].sector = 0;
107 the first block of stage2 will be stored in stage1
108 so skip the first filekey in the first loop
110 #warning "Block read twice"
111 retval=readwriteBlock
113 volume, block, volume->blockbuffer, volume->SizeBlock*4,
114 volume->readcommand
116 i = volume->SizeBlock - 52;
117 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
118 blk_count=0;
119 do {
120 retval=readwriteBlock
122 volume, block, volume->blockbuffer, volume->SizeBlock*4,
123 volume->readcommand
125 if (retval)
127 printf("ReadError %ld\n", retval);
128 return 0;
130 while ((i>=6) && (volume->blockbuffer[i]))
133 if current sector follows right after last sector
134 then we don't need a new element
136 if (
137 (blocklist[blk_count].sector) &&
138 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
139 AROS_BE2LONG(volume->blockbuffer[i]))
142 blocklist[blk_count].count += 1;
144 else
146 blk_count--; /* decrement first */
147 if (blocklist[blk_count-1].sector != 0)
149 printf("There is no more space to save blocklist in stage2\n");
150 return 0;
152 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
153 blocklist[blk_count].count = 1;
155 i--;
157 i = volume->SizeBlock - 51;
158 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
159 } while (block);
161 blocks in blocklist are relative to the first
162 sector of the HD (not partition)
164 i = 0;
165 for (count=-1;count>=blk_count;count--)
167 blocklist[count].sector += volume->startblock;
168 blocklist[count].seg_adr = 0x820 + (i*32);
169 i += blocklist[count].count;
171 return first_block;
174 /**************************************************************************/
176 unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer) {
177 unsigned int sum=0,count=0;
179 for (count=0;count<SizeBlock;count++)
180 sum += AROS_BE2LONG(buffer[count]);
181 return sum;
184 unsigned char capitalch(unsigned char ch, unsigned char flags) {
186 if ((flags==0) || (flags==1))
187 return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch);
188 else // DOS\(>=2)
189 return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) ||
190 ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch);
193 // str2 is a BCPL string
194 int noCaseStrCmp(char *str1, char *str2, unsigned char flags) {
195 unsigned char length;
197 length=str2++[0];
198 do {
199 if ((*str1==0) && (length==0))
200 return 0;
201 length--;
202 // if ((*str1==0) && (*str2==0)) return 1;
203 } while (capitalch(*str1++,flags)==capitalch(*str2++,flags));
204 str1--;
205 return (*str1) ? 1 : -1;
208 unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags) {
209 unsigned int result;
211 result=strlen(name);
212 while (*name!=0)
213 result=(result * 13 +capitalch(*name++,flags)) & 0x7FF;
214 return result%tablesize;
217 int getHeaderBlock(struct Volume *volume, char *name, unsigned int *dirh) {
218 int key;
220 key = getHashKey(name, (volume->SizeBlock-51)-6+1, 1);
221 if (!dirh[6+key])
222 return ERR_FILE_NOT_FOUND;
223 readwriteBlock
225 volume,
226 AROS_BE2LONG(dirh[6+key]),
227 dirh,
228 volume->SizeBlock*4,
229 volume->readcommand
231 if (calcChkSum(volume->SizeBlock, dirh))
232 return ERR_FSYS_CORRUPT;
233 if (AROS_BE2LONG(dirh[0]) != T_SHORT)
234 return ERR_BAD_FILETYPE;
235 while (noCaseStrCmp(name,(char *)((unsigned int)dirh+((volume->SizeBlock-20)*4)),1) != 0)
237 if (!dirh[volume->SizeBlock-4])
238 return ERR_FILE_NOT_FOUND;
239 readwriteBlock
241 volume,
242 AROS_BE2LONG(dirh[volume->SizeBlock-4]),
243 dirh,
244 volume->SizeBlock*4,
245 volume->readcommand
247 if (calcChkSum(volume->SizeBlock, (unsigned int *)dirh))
248 return ERR_FSYS_CORRUPT;
249 if (AROS_BE2LONG(dirh[0]) != T_SHORT)
250 return ERR_BAD_FILETYPE;
252 return 0;
255 int findFile(struct Volume *volume, char *name, unsigned int *buffer) {
256 char dname[32];
257 char *nbuf;
258 int errnum;
260 readwriteBlock
262 volume,
263 volume->countblock/2,
264 buffer,
265 volume->SizeBlock*4,
266 volume->readcommand
268 name++;
269 while (*name)
271 if (
272 (AROS_BE2LONG(buffer[volume->SizeBlock-1]) != ST_ROOT) &&
273 (AROS_BE2LONG(buffer[volume->SizeBlock-1]) != ST_USERDIR)
275 return ERR_BAD_FILETYPE;
276 nbuf = dname;
277 while ((*name != '/') && (*name))
278 *nbuf++ = *name++;
279 if (*name == '/')
280 name++;
281 *nbuf = 0;
282 errnum = getHeaderBlock(volume, dname, buffer);
283 if (errnum)
284 return errnum;
286 return 0;
290 void installStageFiles(struct Volume *volume) {
291 unsigned int block,retval;
293 retval=findFile(volume, "/boot/grub/stage2", stage2_firstblock);
294 if ( retval == 0 )
296 block = AROS_BE2LONG(stage2_firstblock[1]);
297 /* read first data block */
298 readwriteBlock
300 volume,
301 AROS_BE2LONG(stage2_firstblock[volume->SizeBlock-51]),
302 (void *)stage2_firstblock,
303 volume->SizeBlock*4,
304 volume->readcommand
306 /* save first BB (with flags) */
307 if (volume->flags & VF_MOVE_BB)
309 readwriteBlock
311 volume, 1, volume->blockbuffer, 512,
312 volume->writecommand
315 if (
317 block=collectBlockList
319 volume, block,
320 (struct BlockNode *)&stage2_firstblock[128]
325 if (findFile(volume, "/boot/grub/stage1", volume->blockbuffer) == 0)
327 /* read first data block of stage1 */
328 retval = readwriteBlock
330 volume,
331 AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]),
332 volume->blockbuffer,
333 512,
334 volume->readcommand
336 if (retval == 0)
338 /* write stage1 as BB */
339 volume->blockbuffer[17]=block;
340 retval = readwriteBlock
342 volume, 0,
343 volume->blockbuffer, 512, volume->writecommand
345 if (retval)
346 printf("WriteError %ld\n", retval);
347 else
349 /* write first data block of stage2 */
350 readwriteBlock
352 volume,
353 block,
354 stage2_firstblock,
355 512,
356 volume->writecommand
360 else
361 printf("ReadError %d\n", retval);
363 else
364 printf("stage1 file not found\n");
367 else
368 printf("stage2: %d\n",retval);
371 struct Volume *initVolume(char *filename) {
372 struct Volume *volume=0;
373 struct stat stat;
374 char *error;
375 unsigned int retval;
377 if (lstat(filename, &stat)==0)
379 volume = (struct Volume *)calloc(1, sizeof(struct Volume));
380 if (volume)
382 volume->SizeBlock = 128;
383 volume->blockbuffer = (unsigned int *)calloc(1, volume->SizeBlock*4);
384 if (volume->blockbuffer)
386 volume->fd = open(filename, O_RDWR);
387 if (volume->fd)
389 #warning "No support for partitions"
390 volume->startblock = 0;
391 volume->countblock = stat.st_size/(volume->SizeBlock*4);
392 volume->readcommand = CMD_READ;
393 volume->writecommand = CMD_WRITE;
394 retval = readwriteBlock
396 volume, 0,
397 volume->blockbuffer, 512, volume->readcommand
399 if (retval == 0)
401 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300)
403 retval = readwriteBlock
405 volume, 1,
406 volume->blockbuffer, 512, volume->readcommand
409 else
410 volume->flags |= VF_MOVE_BB;
411 if (
412 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300) &&
413 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF)>0)
416 return volume;
418 else
419 error = "No Amiga FFS disk";
421 else
422 error = "ReadError";
424 else
425 error = "Couldn't open file";
426 free(volume->blockbuffer);
428 else
429 error = "Not enough memory";
430 free(volume);
431 volume = 0;
433 else
434 error = "Not enough memory";
436 else
437 error = "lstat() error";
438 printf("%s\n",error);
439 return 0;
442 void uninitVolume(struct Volume *volume) {
444 close(volume->fd);
445 free(volume->blockbuffer);
446 free(volume);
449 void checkBootCode(struct Volume *volume) {
450 printf("CHECK not implemented yet\n");
453 void removeBootCode(struct Volume *volume) {
454 unsigned int retval;
456 retval = readwriteBlock
458 volume, 1,
459 volume->blockbuffer, 512, volume->readcommand
461 if (retval)
462 printf("ReadError %ld\n", retval);
463 else
465 if ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
467 retval = readwriteBlock
469 volume, 0,
470 volume->blockbuffer, 512, volume->writecommand
472 if (retval)
473 printf("WriteError %ld\n", retval);
478 int main(int argc, char **argv) {
479 struct Volume *volume;
481 if (
482 (argc == 1) ||
483 ((argc == 2) && (strcmp(argv[1],"--help")==0)) ||
484 (argc > 3)
486 printf("Usage: %s filename --noboot --check\n",argv[0]);
487 else
489 volume = initVolume(argv[1]);
490 if (volume)
492 if (argc == 3)
494 if (strcmp(argv[2],"--noboot")==0)
495 removeBootCode(volume);
496 else if (strcmp(argv[2],"--check")==0)
497 checkBootCode(volume);
499 else
500 installStageFiles(volume);
501 uninitVolume(volume);
504 return 0;