Install g2hdr.bin and g2ldr.mbr.
[grub-extras.git] / grubinst.c
blob4eb042258befd46d2be5ea587f4baed5791b66cc
1 /*
2 * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
3 * Copyright (C) 2007 Bean (bean123@126.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <errno.h>
27 #ifndef WIN32
29 #define O_BINARY 0
31 #endif
33 #include "grub_mbr.h"
34 #include "utils.h"
35 #include "version.h"
37 // Application flags, used by this program
39 #define AFG_VERBOSE 1
40 #define AFG_PAUSE 2
41 #define AFG_READ_ONLY 4
42 #define AFG_NO_BACKUP_MBR 8
43 #define AFG_FORCE_BACKUP_MBR 16
44 #define AFG_RESTORE_PREVMBR 32
45 #define AFG_LIST_PART 64
46 #define AFG_IS_FLOPPY 128
47 #define AFG_LBA_MODE 256
48 #define AFG_CHS_MODE 512
49 #define AFG_OUTPUT 1024
50 #define AFG_EDIT 2048
52 // Grldr flags, this flag is used by grldr.mbr
54 #define GFG_DISABLE_FLOPPY 1
55 #define GFG_DISABLE_OSBR 2
56 #define GFG_DUCE 4
57 #define GFG_PREVMBR_LAST 128
59 #define APP_NAME "grubinst: "
61 #define print_pause if (afg & AFG_PAUSE) {fputs("Press <ENTER> to continue ...\n",stderr); fflush(stderr); fgetc(stdin);}
63 #define print_apperr(a) { fprintf(stderr,APP_NAME "%s\n",a); print_pause; }
64 #define print_syserr(a) { perror(APP_NAME a); print_pause; }
66 void help(void)
68 fputs("Usage:\n"
69 "\tgrubinst [OPTIONS] DEVICE_OR_FILE\n\n"
70 "OPTIONS:\n\n"
71 "\t--help,-h\t\tShow usage information\n\n"
72 "\t--pause\t\t\tPause before exiting\n\n"
73 "\t--version\t\tShow version information\n\n"
74 "\t--verbose,-v\t\tVerbose output\n\n"
75 "\t--list-part,-l\t\tList all logical partitions in DEVICE_OR_FILE\n\n"
76 "\t--save=FN,-s=FN\t\tSave the orginal MBR/BS to FN\n\n"
77 "\t--restore=FN,-r=FN\tRestore MBR/BS from previously saved FN\n\n"
78 "\t--restore-prevmbr,-r\tRestore previous MBR saved in the second sector\n"
79 "\t\t\t\tof DEVICE_OR_FILE\n\n"
80 "\t--read-only,-t\t\tdo everything except the actual write to the\n"
81 "\t\t\t\tspecified DEVICE_OR_FILE. (test mode)\n\n"
82 "\t--no-backup-mbr\t\tdo not copy the old MBR to the second sector of\n"
83 "\t\t\t\tDEVICE_OR_FILE.\n\n"
84 "\t--force-backup-mbr\tforce the copy of old MBR to the second sector\n"
85 "\t\t\t\tof DEVICE_OR_FILE.(default)\n\n"
86 "\t--mbr-enable-floppy\tenable the search for GRLDR on floppy.(default)\n\n"
87 "\t--mbr-disable-floppy\tdisable the search for GRLDR on floppy.\n\n"
88 "\t--mbr-enable-osbr\tenable the boot of PREVIOUS MBR with invalid\n"
89 "\t\t\t\tpartition table (usually an OS boot sector).\n"
90 "\t\t\t\t(default)\n\n"
91 "\t--mbr-disable-osbr\tdisable the boot of PREVIOUS MBR with invalid\n"
92 "\t\t\t\tpartition table (usually an OS boot sector).\n\n"
93 "\t--duce\t\t\tdisable the feature of unconditional entrance\n"
94 "\t\t\t\tto the command-line.\n\n"
95 "\t--boot-prevmbr-first\ttry to boot PREVIOUS MBR before the search for\n"
96 "\t\t\t\tGRLDR.\n\n"
97 "\t--boot-prevmbr-last\ttry to boot PREVIOUS MBR after the search for\n"
98 "\t\t\t\tGRLDR.(default)\n\n"
99 "\t--preferred-drive=D\tpreferred boot drive number, 0 <= D < 255.\n\n"
100 "\t--preferred-partition=P\tpreferred partition number, 0 <= P < 255.\n\n"
101 "\t--time-out=T,-t=T\twait T seconds before booting PREVIOUS MBR. if\n"
102 "\t\t\t\tT is 0xff, wait forever. The default is 5.\n\n"
103 "\t\t\t\tbefore booting PREVIOUS MBR. K is a word\n"
104 "\t\t\t\tvalue, just as the value in AX register\n"
105 "\t\t\t\treturned from int16/AH=1. The high byte is the\n"
106 "\t\t\t\tscan code and the low byte is ASCII code. The\n"
107 "\t\t\t\tdefault is 0x3920 for space bar.\n\n"
108 "\t--key-name=S\t\tSpecify the name of the hot key.\n\n"
109 "\t--floppy,-f\t\tif DEVICE_OR_FILE is floppy, use this option.\n\n"
110 "\t--floppy=N\t\tif DEVICE_OR_FILE is a partition on a hard\n"
111 "\t\t\t\tdrive, use this option. N is used to specify\n"
112 "\t\t\t\tthe partition number: 0,1,2 and 3 for the\n"
113 "\t\t\t\tprimary partitions, and 4,5,6,... for the\n"
114 "\t\t\t\tlogical partitions.\n\n"
115 "\t--sectors-per-track=S\tspecifies sectors per track for --floppy.\n"
116 "\t\t\t\t1 <= S <= 63, default is 63.\n\n"
117 "\t--heads=H\t\tspecifies number of heads for --floppy.\n"
118 "\t\t\t\t1 <= H <= 256, default is 255.\n\n"
119 "\t--start-sector=B\tspecifies hidden sectors for --floppy=N.\n\n"
120 "\t--total-sectors=C\tspecifies total sectors for --floppy.\n"
121 "\t\t\t\tdefault is 0.\n\n"
122 "\t--lba\t\t\tuse lba mode for --floppy. If the floppy BIOS\n"
123 "\t\t\t\thas LBA support, you can specify --lba here.\n"
124 "\t\t\t\tIt is assumed that all floppy BIOSes have CHS\n"
125 "\t\t\t\tsupport. So you would rather specify --chs.\n"
126 "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
127 "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
128 "\t\t\t\tboot sector) will not be touched.\n\n"
129 "\t--chs\t\t\tuse chs mode for --floppy. You should specify\n"
130 "\t\t\t\t--chs if the floppy BIOS does not support LBA.\n"
131 "\t\t\t\tWe assume all floppy BIOSes have CHS support.\n"
132 "\t\t\t\tSo it is likely you want to specify --chs.\n"
133 "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
134 "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
135 "\t\t\t\tboot sector) will not be touched.\n\n"
136 "\t--install-partition=I\tInstall the boot record onto the boot area of\n"
137 "\t-p=I\t\t\tpartition number I of the specified hard drive\n"
138 "\t\t\t\tor harddrive image DEVICE_OR_FILE.\n\n"
139 "\t--boot-file=F,-b=F\tChange the name of boot file.\n\n"
140 "\t--load-seg=S\t\tChange load segment for boot file.\n\n"
141 "\t--grub2,-2\t\tLoad grub2 kernel g2ldr instead of grldr.\n\n"
142 "\t--output,-o\t\tSave embeded grldr.mbr to DEVICE_OR_FILE.\n\n"
143 "\t--edit,-e\t\tEdit external grldr/grldr.mbr.\n",
144 stderr);
147 int afg,gfg,def_drive,def_part,time_out,hot_key,part_num;
148 int def_spt,def_hds,def_ssc,def_tsc;
149 char *save_fn,*restore_fn,*boot_file,boot_file_83[12],*key_name;
150 unsigned short load_seg;
152 static char fn_buf[24];
154 char* get_disk_name(int n)
156 #if defined(WIN32)
157 sprintf(fn_buf,"\\\\.\\PhysicalDrive%d",n);
158 #elif defined(LINUX)
159 sprintf(fn_buf,"/dev/hd%c",'a'+n);
160 #elif defined(FREEBSD)
161 sprintf(fn_buf,"/dev/ad%d",n);
162 #else
163 print_apperr("Disk device is not supported in your system");
164 return NULL;
165 #endif
166 return fn_buf;
169 char* get_flop_name(int n)
171 #if defined(WIN32)
172 if (n>1)
174 print_apperr("Only two floppy drives are supported");
175 return NULL;
177 sprintf(fn_buf,"\\\\.\\%c:",'A'+n);
178 #elif defined(LINUX) || defined(FREEBSD)
179 sprintf(fn_buf,"/dev/fd%d",n);
180 #else
181 print_apperr("Floppy device is not supported in your system");
182 return NULL;
183 #endif
184 return fn_buf;
187 char* parse_fname(char* fn)
189 if ((afg & AFG_OUTPUT) && (fn[0]=='('))
191 print_apperr("Can\'t use device name while using --output option");
192 return NULL;
194 if ((! strncmp(fn,"(hd",3)) || (! strncmp(fn,"(fd",3)))
196 int n;
197 char *p;
199 n=strtol(&fn[3],&p,0);
200 if ((n<0) || (n>=MAX_DISKS))
202 print_apperr("Invalid device number");
203 return NULL;
205 if (*p==',')
207 part_num=strtol(p+1,&p,0);
208 if ((part_num<0) || (part_num>=MAX_PARTS))
210 print_apperr("Invalid partition number");
211 return NULL;
214 if ((*p!=')') || (*(p+1)!=0))
216 print_apperr("Invalid device name");
217 return NULL;
219 if (fn[1]=='h')
220 fn=get_disk_name(n);
221 else
223 fn=get_flop_name(n);
224 afg|=AFG_IS_FLOPPY;
227 return fn;
230 char* str_upcase(char* str)
232 int i;
234 for (i=0;str[i];i++)
235 if ((str[i]>='a') && (str[i]<='z'))
236 str[i]-='a'-'A';
238 return str;
241 char* str_lowcase(char* str)
243 int i;
245 for (i=0;str[i];i++)
246 if ((str[i]>='A') && (str[i]<='Z'))
247 str[i]+='a'-'A';
249 return str;
252 int SetBootFile(char* fn)
254 char* pc;
256 if (*fn==0)
257 return 1;
258 if (strlen(fn)>7)
259 return 1;
260 pc=strchr(fn,'.');
261 if (pc)
262 if ((pc==fn) || (pc-fn>8) || (strlen(pc+1)>3))
263 return 1;
264 str_upcase(fn);
265 memset(boot_file_83,' ',sizeof(boot_file_83)-1);
266 if (pc)
268 memcpy(boot_file_83,fn,pc-fn);
269 memcpy(&boot_file_83[8],pc+1,strlen(pc+1));
271 else
272 memcpy(boot_file_83,fn,strlen(fn));
273 str_lowcase(fn);
274 boot_file=fn;
275 return 0;
278 int chk_mbr(unsigned char* buf);
280 void list(int hd)
282 xde_t xe;
284 xe.cur=xe.nxt=0xFF;
285 fprintf(stderr," # id base leng\n");
286 while (! xd_enum(hd,&xe))
287 fprintf(stderr,"%2d %02X %8X %8X\n",xe.cur,xe.dfs,xe.bse,xe.len);
290 int is_grldr_mbr(char* buf)
292 int i,n;
294 i=0x1B7;
295 n=sizeof("Missing MBR-helper.")-1;
297 while ((i>n) && (buf[i]==0))
298 i--;
299 return (! strcmp(&buf[i-n+1],"Missing MBR-helper."));
302 int install(char* fn)
304 int hd,nn,fs,slen;
305 char prev_mbr[sizeof(grub_mbr)];
306 unsigned long ssec;
308 if (fn==NULL)
309 return 1;
311 if (afg & AFG_EDIT)
313 unsigned short r1,r2;
315 if (afg & AFG_VERBOSE)
316 fprintf(stderr,"Edit mode\n");
317 hd=open(fn,O_RDWR | O_BINARY,0644);
318 if (hd==-1)
320 print_syserr("open");
321 return errno;
323 r1=valueat(grub_mbr[0x1FFA],0,unsigned short);
324 nn=read(hd,grub_mbr,sizeof(grub_mbr));
325 if (nn==-1)
327 print_syserr("read");
328 close(hd);
329 return errno;
331 if (nn<sizeof(grub_mbr))
333 print_apperr("The input file is too short");
334 close(hd);
335 return 1;
337 if (valueat(grub_mbr[0x1FFC],0,unsigned long)!=0xAA555247)
339 print_apperr("Invalid input file");
340 close(hd);
341 return 1;
343 r2=valueat(grub_mbr[0x1FFA],0,unsigned short);
344 if (r1!=r2)
346 char buf[30];
348 sprintf(buf,"Version number mismatched (old=%d new=%d)",r2,r1);
349 print_apperr(buf);
350 close(hd);
351 return 1;
353 go_sect(hd,0);
354 afg |= AFG_OUTPUT;
357 if (boot_file)
359 unsigned short ofs,len;
361 // Patching the FAT32 boot sector
362 ofs=valueat(grub_mbr,0x400+0x1EC,unsigned short) & 0x7FF;
363 strcpy(&grub_mbr[0x400+ofs],boot_file_83);
364 if (load_seg)
365 valueat(grub_mbr,0x400+0x1EA,unsigned short)=load_seg;
367 // Patching the FAT12/FAT16 boot sector
368 ofs=valueat(grub_mbr,0x600+0x1EC,unsigned short) & 0x7FF;
369 strcpy(&grub_mbr[0x600+ofs],boot_file_83);
370 if (load_seg)
371 valueat(grub_mbr,0x600+0x1EA,unsigned short)=load_seg;
373 // Patching the EXT2 boot sector
374 ofs=valueat(grub_mbr,0x800+0x1EE,unsigned short) & 0x7FF;
375 strcpy(&grub_mbr[0x800+ofs],boot_file);
377 // Patching the NTFS sector
378 ofs=valueat(grub_mbr,0xA00+0x1EC,unsigned short) & 0x7FF;
379 strcpy(&grub_mbr[0xA00+ofs],boot_file);
380 if (load_seg)
381 valueat(grub_mbr,0xA00+0x1EA,unsigned short)=load_seg;
383 if (afg & AFG_VERBOSE)
385 fprintf(stderr,"Boot file changed to %s\n",boot_file);
386 if (load_seg)
387 fprintf(stderr,"Load segment changed to %04X\n",load_seg);
391 if (afg & AFG_OUTPUT)
393 int mode;
395 mode=(! (afg & AFG_READ_ONLY))?(O_TRUNC | O_CREAT):0;
396 if (! (afg & AFG_EDIT))
398 if (afg & AFG_VERBOSE)
399 fprintf(stderr,"Extract mode\n");
400 hd=open(fn,O_RDWR | O_BINARY | mode,0644);
401 if (hd==-1)
403 print_syserr("open");
404 return errno;
407 if (! (afg & AFG_READ_ONLY))
408 if (write(hd,grub_mbr,sizeof(grub_mbr))!=sizeof(grub_mbr))
410 print_apperr("Write to output file fails");
411 close(hd);
412 return 1;
414 goto quit;
417 memset(&grub_mbr[512],0,512);
418 valueat(grub_mbr,2,unsigned char)=gfg;
419 valueat(grub_mbr,3,unsigned char)=time_out;
420 valueat(grub_mbr,4,unsigned short)=hot_key;
421 valueat(grub_mbr,6,unsigned char)=def_drive;
422 valueat(grub_mbr,7,unsigned char)=def_part;
423 if ((key_name==NULL) && (hot_key==0x3920))
424 key_name="SPACE";
425 if (key_name)
426 strcpy(&grub_mbr[0x1fec],key_name);
428 hd=open(fn,O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
429 if (hd==-1)
431 print_syserr("open");
432 return errno;
434 if (afg & AFG_LIST_PART)
436 list(hd);
437 close(hd);
438 return 0;
440 if (part_num!=-1)
442 if (def_ssc!=-1)
443 ssec=def_ssc;
444 else
446 xde_t xe;
448 xe.cur=0xFF;
449 xe.nxt=part_num;
450 if (xd_enum(hd,&xe))
452 print_apperr("Partition not found");
453 close(hd);
454 return 1;
456 ssec=xe.bse;
457 if (afg & AFG_VERBOSE)
458 fprintf(stderr,"Part Fs: %02X (%s)\nPart Leng: %u\n",xe.dfs,dfs2str(xe.dfs),xe.len);
461 else
462 ssec=0;
463 if (afg & AFG_VERBOSE)
464 fprintf(stderr,"Start sector: %u\n",ssec);
465 if ((ssec) && (go_sect(hd,ssec)))
467 print_apperr("Can\'t seek to the start sector");
468 close(hd);
469 return 1;
471 nn=read(hd,prev_mbr,sizeof(prev_mbr));
472 if (nn==-1)
474 print_syserr("read");
475 close(hd);
476 return errno;
478 if (nn<sizeof(prev_mbr))
480 print_apperr("The input file is too short");
481 close(hd);
482 return 1;
484 fs=get_fstype(prev_mbr);
485 if (afg & AFG_VERBOSE)
487 fprintf(stderr,"Image type: %s\n",fst2str(fs));
488 if (fs==FST_MBR)
489 fprintf(stderr,"Num of heads: %d\nSectors per track: %d\n",mbr_nhd,mbr_spt);
491 if (fs==FST_OTHER)
493 print_apperr("Unknown image type");
494 close(hd);
495 return 1;
497 if (((part_num!=-1) || (afg & AFG_IS_FLOPPY)) && (fs==FST_MBR))
499 print_apperr("Should be a file system image");
500 close(hd);
501 return 1;
503 if ((part_num==-1) && ((afg & AFG_IS_FLOPPY)==0) && (fs!=FST_MBR))
505 print_apperr("Should be a disk image");
506 close(hd);
507 return 1;
509 if (fs==FST_MBR)
511 int n,nfs,sln;
512 unsigned long ofs;
513 char bs[1024];
515 ofs=0xFFFFFFFF;
516 for (n=0x1BE;n<0x1FE;n+=16)
517 if (prev_mbr[n+4])
519 if (ofs>valueat(prev_mbr[n],8,unsigned long))
520 ofs=valueat(prev_mbr[n],8,unsigned long);
522 if (ofs<(sizeof(prev_mbr)>>9))
524 print_apperr("Not enough room to install mbr");
525 close(hd);
526 return 1;
528 slen=sizeof(prev_mbr);
529 if (go_sect(hd,ofs))
531 print_apperr("Can\'t seek to the first partition");
532 close(hd);
533 return 1;
535 if (read(hd,bs,sizeof(bs))!=sizeof(bs))
537 print_apperr("Fail to read boot sector");
538 close(hd);
539 return 1;
541 nfs=get_fstype(bs);
542 if (nfs==FST_FAT32)
543 sln=0x5A - 0xB;
544 else if (nfs==FST_FAT16)
545 sln=0x3E - 0xB;
546 else
547 sln=0;
548 if (sln)
550 memcpy(&grub_mbr[0xB],&bs[0xB],sln);
551 valueat(grub_mbr[0],0x1C,unsigned long)=0;
552 valueat(grub_mbr[0],0xE,unsigned short)+=ofs;
555 else if (fs==FST_NTFS)
556 slen=2048;
557 else
558 slen=512;
560 if (go_sect(hd,ssec))
562 print_apperr("Can\'t seek to the start sector");
563 close(hd);
564 return 1;
567 if (save_fn)
569 int h2;
571 h2=open(save_fn,O_CREAT | O_TRUNC | O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
572 if (h2==-1)
574 print_syserr("open save file");
575 close(hd);
576 return errno;
578 nn=write(h2,prev_mbr,slen);
579 if (nn==-1)
581 print_syserr("write save file");
582 close(hd);
583 close(h2);
584 return errno;
586 if (nn<slen)
588 print_apperr("Can\'t write the whole MBR to the save file");
589 close(hd);
590 close(h2);
591 return 1;
593 close(h2);
595 if (afg & AFG_RESTORE_PREVMBR)
597 if (fs!=FST_MBR)
599 print_apperr("Not a disk image");
600 close(hd);
601 return 1;
603 if (strncmp(&prev_mbr[1024+3],"GRLDR",5))
605 print_apperr("GRLDR is not installed");
606 close(hd);
607 return 1;
609 if (valueat(prev_mbr,512+510,unsigned short)!=0xAA55)
611 print_apperr("No previous saved MBR");
612 close(hd);
613 return 1;
615 memset(&grub_mbr,0,sizeof(grub_mbr));
616 memcpy(&grub_mbr,&prev_mbr[512],512);
617 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
619 if (afg & AFG_VERBOSE)
620 fprintf(stderr,"Restore previous MBR mode\n");
622 else
624 // Load MBR/BS from restore file or configure grub_mbr
625 if (restore_fn)
627 int h2;
629 h2=open(restore_fn,O_RDONLY | O_BINARY,S_IREAD);
630 if (h2==-1)
632 print_syserr("open restore file");
633 close(hd);
634 return errno;
636 nn=read(h2,grub_mbr,slen);
637 if (nn==-1)
639 print_syserr("read restore file");
640 close(hd);
641 close(h2);
642 return errno;
644 if ((nn<512) || (nn & 0x1FF!=0) ||
645 (fs!=FST_EXT2) && (valueat(grub_mbr,510,unsigned short)!=0xAA55))
647 print_apperr("Invalid restore file");
648 close(hd);
649 close(h2);
650 return 1;
652 close(h2);
653 if (nn<slen)
654 memset(&grub_mbr[nn],0,slen-nn);
656 //if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
657 if (fs!=FST_EXT2)
659 int new_fs;
661 new_fs=get_fstype(grub_mbr);
662 if (new_fs!=fs)
664 print_apperr("Invalid restore file");
665 close(hd);
666 return 1;
670 if (afg & AFG_VERBOSE)
671 fprintf(stderr,"Restore mode\n");
673 else
675 if (fs==FST_MBR)
677 if (! (afg & AFG_NO_BACKUP_MBR))
679 int i;
681 if (afg & AFG_FORCE_BACKUP_MBR)
682 i=512;
683 else
684 for (i=1;i<512;i++)
685 if (prev_mbr[512+i]!=prev_mbr[512])
686 break;
688 if ((i==512) && (! is_grldr_mbr(prev_mbr)))
689 memcpy(&grub_mbr[512],prev_mbr,512);
690 else
691 memcpy(&grub_mbr[512],&prev_mbr[512],512);
693 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
695 else if (fs==FST_FAT16)
697 memcpy(grub_mbr,&grub_mbr[0x600],slen);
698 grub_mbr[0x41]=part_num;
700 else if (fs==FST_FAT32)
702 memcpy(grub_mbr,&grub_mbr[0x400],slen);
703 grub_mbr[0x5D]=part_num;
705 else if (fs==FST_NTFS)
707 memcpy(grub_mbr,&grub_mbr[0xA00],slen);
708 grub_mbr[0x57]=part_num;
710 else if (fs==FST_EXT2)
712 memcpy(grub_mbr,&grub_mbr[0x800],slen);
713 grub_mbr[0x25]=part_num;
714 if (afg & AFG_LBA_MODE)
715 grub_mbr[2]=0x42;
716 else if (afg & AFG_CHS_MODE)
717 grub_mbr[2]=0x2;
718 if (def_spt!=-1)
719 valueat(grub_mbr,0x18,unsigned short)=def_spt;
720 else if ((afg & AFG_IS_FLOPPY)==0)
721 valueat(grub_mbr,0x18,unsigned short)=63;
722 if (def_hds!=-1)
723 valueat(grub_mbr,0x1A,unsigned short)=def_hds;
724 else if ((afg & AFG_IS_FLOPPY)==0)
725 valueat(grub_mbr,0x1A,unsigned short)=255;
726 if (def_tsc!=-1)
727 valueat(grub_mbr,0x20,unsigned long)=def_tsc;
728 valueat(grub_mbr,0x1C,unsigned long)=ssec;
729 // s_inodes_per_group
730 valueat(grub_mbr,0x28,unsigned long)=valueat(prev_mbr[1024],0x28,unsigned long);
731 // s_first_data_block+1
732 valueat(grub_mbr,0x2C,unsigned long)=valueat(prev_mbr[1024],0x14,unsigned long)+1;
734 else
736 // Shouldn't be here
737 print_apperr("Invalid file system");
738 close(hd);
739 return 1;
741 if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
743 if (afg & AFG_LBA_MODE)
744 grub_mbr[2]=0xe;
745 else if (afg & AFG_CHS_MODE)
746 grub_mbr[2]=0x90;
747 else
748 grub_mbr[2]=prev_mbr[2];
751 if (afg & AFG_VERBOSE)
752 fprintf(stderr,"Install mode\n");
754 // Patch the new MBR/BS with information from prev_mbr
755 if (fs==FST_MBR)
756 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
757 else if (fs==FST_FAT16)
759 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x3E - 0xB);
760 valueat(grub_mbr,0x1C,unsigned long)=ssec;
762 else if (fs==FST_FAT32)
764 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x5A - 0xB);
765 valueat(grub_mbr,0x1C,unsigned long)=ssec;
767 else if (fs==FST_NTFS)
769 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x54 - 0xB);
770 valueat(grub_mbr,0x1C,unsigned long)=ssec;
773 if (! (afg & AFG_READ_ONLY))
775 nn=write(hd,grub_mbr,slen);
776 if (nn==-1)
778 print_syserr("write");
779 close(hd);
780 return errno;
782 if (nn<slen)
784 print_apperr("Can\'t write the whole mbr");
785 close(hd);
786 return 1;
789 else if (afg & AFG_VERBOSE)
790 fprintf(stderr,"Read only mode\n");
791 quit:
792 close(hd);
793 if (afg & AFG_PAUSE)
795 fputs("The MBR/BS has been successfully installed\n",stderr);
796 print_pause;
798 return 0;
801 int main(int argc,char** argv)
803 int idx;
805 afg=gfg=0;
806 part_num=def_drive=def_part=def_spt=def_hds=def_ssc=def_tsc=-1;
807 afg=0;
808 gfg=GFG_PREVMBR_LAST;
809 time_out=5;
810 hot_key=0x3920;
811 save_fn=NULL;
812 restore_fn=NULL;
813 for (idx=1;idx<argc;idx++)
815 if (argv[idx][0]!='-')
816 break;
817 if ((! strcmp(argv[idx],"--help"))
818 || (! strcmp(argv[idx],"-h")))
820 help();
821 print_pause;
822 return 1;
824 else if (! strcmp(argv[idx],"--version"))
826 fprintf(stderr,"grubinst version : " VERSION "\n");
827 print_pause;
828 return 1;
830 else if ((! strcmp(argv[idx],"--verbose")) ||
831 (! strcmp(argv[idx],"-v")))
832 afg |=AFG_VERBOSE;
833 else if (! strcmp(argv[idx],"--pause"))
834 afg|=AFG_PAUSE;
835 else if ((! strcmp(argv[idx],"--read-only"))
836 || (! strcmp(argv[idx],"-t")))
837 afg|=AFG_READ_ONLY;
838 else if (! strcmp(argv[idx],"--no-backup-mbr"))
839 afg|=AFG_NO_BACKUP_MBR;
840 else if (! strcmp(argv[idx],"--force-backup-mbr"))
841 afg|=AFG_FORCE_BACKUP_MBR;
842 else if (! strcmp(argv[idx],"--mbr-enable-floppy"))
843 gfg&=~GFG_DISABLE_FLOPPY;
844 else if (! strcmp(argv[idx],"--mbr-disable-floppy"))
845 gfg|=GFG_DISABLE_FLOPPY;
846 else if (! strcmp(argv[idx],"--mbr-enable-osbr"))
847 gfg&=~GFG_DISABLE_OSBR;
848 else if (! strcmp(argv[idx],"--mbr-disable-osbr"))
849 gfg|=GFG_DISABLE_OSBR;
850 else if (! strcmp(argv[idx],"--duce"))
851 gfg|=GFG_DUCE;
852 else if (! strcmp(argv[idx],"--boot-prevmbr-first"))
853 gfg&=~GFG_PREVMBR_LAST;
854 else if (! strcmp(argv[idx],"--boot-prevmbr-last"))
855 gfg|=GFG_PREVMBR_LAST;
856 else if (! strncmp(argv[idx],"--preferred-drive=",18))
858 def_drive=strtol(&argv[idx][18],NULL,0);
859 if ((def_drive<0) || (def_drive>=255))
861 print_apperr("Invalid preferred drive number");
862 return 1;
865 else if (! strncmp(argv[idx],"--preferred-partition=",22))
867 def_part=strtol(&argv[idx][22],NULL,0);
868 if ((def_part<0) || (def_part>=255))
870 print_apperr("Invalid preferred partition number");
871 return 1;
874 else if ((! strncmp(argv[idx],"--time-out=",11)) ||
875 (! strncmp(argv[idx],"-t=",3)))
877 time_out=strtol((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][11],NULL,0);
878 if ((time_out<0) || (time_out>255))
880 print_apperr("Invalid timeout value");
881 return 1;
884 else if ((! strncmp(argv[idx],"--key-name=",11)))
886 key_name=&argv[idx][11];
887 if (strlen(key_name)>13)
889 print_apperr("Key name too long");
890 return 1;
893 else if ((! strcmp(argv[idx],"--restore-prevmbr")) ||
894 (! strcmp(argv[idx],"-r")))
895 afg|=AFG_RESTORE_PREVMBR;
896 else if ((! strncmp(argv[idx],"--save=",7)) ||
897 (! strncmp(argv[idx],"-s=",3)))
899 save_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][7];
900 if (*save_fn==0)
902 print_apperr("Empty filename");
903 return 1;
906 else if ((! strncmp(argv[idx],"--restore=",10)) ||
907 (! strncmp(argv[idx],"-r=",3)))
909 restore_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][10];
910 if (*restore_fn==0)
912 print_apperr("Empty filename");
913 return 1;
916 else if ((! strcmp(argv[idx],"--list-part")) ||
917 (! strcmp(argv[idx],"-l")))
918 afg|=AFG_LIST_PART;
919 else if ((! strcmp(argv[idx],"--floppy")) ||
920 (! strcmp(argv[idx],"-f")))
921 afg|=AFG_IS_FLOPPY;
922 else if ((! strncmp(argv[idx],"--floppy=",9)) ||
923 (! strncmp(argv[idx],"--install-partition=",20)) ||
924 (! strncmp(argv[idx],"-p=",3)))
926 char *p;
928 if (argv[idx][2]=='f')
929 p=&argv[idx][9];
930 else if (argv[idx][2]=='i')
931 p=&argv[idx][20];
932 else
933 p=&argv[idx][3];
934 part_num=strtoul(p,NULL,0);
935 if ((part_num<0) || (part_num>=MAX_PARTS))
937 print_apperr("Invalid partition number");
938 return 1;
941 else if (! strcmp(argv[idx],"--lba"))
942 afg|=AFG_LBA_MODE;
943 else if (! strcmp(argv[idx],"--chs"))
944 afg|=AFG_CHS_MODE;
945 else if (! strncmp(argv[idx],"--sectors-per-track=",20))
947 def_spt=strtol(&argv[idx][10],NULL,0);
948 if ((def_spt<1) || (def_spt>63))
950 print_apperr("Invalid sector per track");
951 return 1;
954 else if (! strncmp(argv[idx],"--heads=",8))
956 def_hds=strtol(&argv[idx][8],NULL,0);
957 if ((def_hds<1) || (def_hds>255))
959 print_apperr("Invalid number of heads");
960 return 1;
963 else if (! strncmp(argv[idx],"--start-sector=",15))
965 def_spt=strtol(&argv[idx][15],NULL,0);
966 if (def_ssc<0)
968 print_apperr("Invalid start sector");
969 return 1;
972 else if (! strncmp(argv[idx],"--total-sectors=",16))
974 def_tsc=strtol(&argv[idx][16],NULL,0);
975 if (def_tsc<0)
977 print_apperr("Invalid total sectors");
978 return 1;
981 else if ((! strncmp(argv[idx],"--boot-file=",12)) ||
982 (! strncmp(argv[idx],"-b=",3)))
984 if (SetBootFile((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][12]))
986 print_apperr("Invalid boot file name");
987 return 1;
990 else if (! strncmp(argv[idx],"--load-seg=",11))
992 load_seg=strtoul(&argv[idx][11],NULL,16);
993 if (load_seg<0x1000)
995 print_apperr("Load address too small");
996 return 1;
999 else if ((! strcmp(argv[idx],"--grub2")) ||
1000 (! strcmp(argv[idx],"-2")))
1002 if (! boot_file)
1004 boot_file="g2ldr";
1005 strcpy(boot_file_83,"G2LDR ");
1008 else if ((! strcmp(argv[idx],"--output")) ||
1009 (! strcmp(argv[idx],"-o")))
1010 afg|=AFG_OUTPUT;
1011 else if ((! strcmp(argv[idx],"--edit")) ||
1012 (! strcmp(argv[idx],"-e")))
1013 afg|=AFG_EDIT;
1014 else
1016 print_apperr("Invalid option, please use --help to see all valid options");
1017 return 1;
1020 if (idx>=argc)
1022 print_apperr("No filename specified");
1023 return 1;
1025 if (idx<argc-1)
1027 print_apperr("Extra parameters");
1028 return 1;
1030 return install(parse_fname(argv[idx]));