grub-extras/lua: add fs label to grub.enum_device
[grub-extras.git] / ntldr-img / grubinst.c
blob4565cb402f52a5684b210d7312e725e8b47a48f8
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>
26 #include <unistd.h>
28 #ifndef WIN32
30 #define O_BINARY 0
32 #endif
34 #include "grub_mbr.h"
35 #include "utils.h"
36 #include "version.h"
38 // Application flags, used by this program
40 #define AFG_VERBOSE 1
41 #define AFG_PAUSE 2
42 #define AFG_READ_ONLY 4
43 #define AFG_NO_BACKUP_MBR 8
44 #define AFG_FORCE_BACKUP_MBR 16
45 #define AFG_RESTORE_PREVMBR 32
46 #define AFG_LIST_PART 64
47 #define AFG_IS_FLOPPY 128
48 #define AFG_LBA_MODE 256
49 #define AFG_CHS_MODE 512
50 #define AFG_OUTPUT 1024
51 #define AFG_EDIT 2048
53 // Grldr flags, this flag is used by grldr.mbr
55 #define GFG_DISABLE_FLOPPY 1
56 #define GFG_DISABLE_OSBR 2
57 #define GFG_DUCE 4
58 #define GFG_PREVMBR_LAST 128
60 #define APP_NAME "grubinst: "
62 #define print_pause if (afg & AFG_PAUSE) {fputs("Press <ENTER> to continue ...\n",stderr); fflush(stderr); fgetc(stdin);}
64 #define print_apperr(a) { fprintf(stderr,APP_NAME "%s\n",a); print_pause; }
65 #define print_syserr(a) { perror(APP_NAME a); print_pause; }
67 static void help(void)
69 fputs("Usage:\n"
70 "\tgrubinst [OPTIONS] DEVICE_OR_FILE\n\n"
71 "OPTIONS:\n\n"
72 "\t--help,-h\t\tShow usage information\n\n"
73 "\t--pause\t\t\tPause before exiting\n\n"
74 "\t--version\t\tShow version information\n\n"
75 "\t--verbose,-v\t\tVerbose output\n\n"
76 "\t--list-part,-l\t\tList all logical partitions in DEVICE_OR_FILE\n\n"
77 "\t--save=FN,-s=FN\t\tSave the orginal MBR/BS to FN\n\n"
78 "\t--restore=FN,-r=FN\tRestore MBR/BS from previously saved FN\n\n"
79 "\t--restore-prevmbr,-r\tRestore previous MBR saved in the second sector\n"
80 "\t\t\t\tof DEVICE_OR_FILE\n\n"
81 "\t--read-only,-t\t\tdo everything except the actual write to the\n"
82 "\t\t\t\tspecified DEVICE_OR_FILE. (test mode)\n\n"
83 "\t--no-backup-mbr\t\tdo not copy the old MBR to the second sector of\n"
84 "\t\t\t\tDEVICE_OR_FILE.\n\n"
85 "\t--force-backup-mbr\tforce the copy of old MBR to the second sector\n"
86 "\t\t\t\tof DEVICE_OR_FILE.(default)\n\n"
87 "\t--mbr-enable-floppy\tenable the search for GRLDR on floppy.(default)\n\n"
88 "\t--mbr-disable-floppy\tdisable the search for GRLDR on floppy.\n\n"
89 "\t--mbr-enable-osbr\tenable the boot of PREVIOUS MBR with invalid\n"
90 "\t\t\t\tpartition table (usually an OS boot sector).\n"
91 "\t\t\t\t(default)\n\n"
92 "\t--mbr-disable-osbr\tdisable the boot of PREVIOUS MBR with invalid\n"
93 "\t\t\t\tpartition table (usually an OS boot sector).\n\n"
94 "\t--duce\t\t\tdisable the feature of unconditional entrance\n"
95 "\t\t\t\tto the command-line.\n\n"
96 "\t--boot-prevmbr-first\ttry to boot PREVIOUS MBR before the search for\n"
97 "\t\t\t\tGRLDR.\n\n"
98 "\t--boot-prevmbr-last\ttry to boot PREVIOUS MBR after the search for\n"
99 "\t\t\t\tGRLDR.(default)\n\n"
100 "\t--preferred-drive=D\tpreferred boot drive number, 0 <= D < 255.\n\n"
101 "\t--preferred-partition=P\tpreferred partition number, 0 <= P < 255.\n\n"
102 "\t--time-out=T,-t=T\twait T seconds before booting PREVIOUS MBR. if\n"
103 "\t\t\t\tT is 0xff, wait forever. The default is 5.\n\n"
104 "\t\t\t\tbefore booting PREVIOUS MBR. K is a word\n"
105 "\t\t\t\tvalue, just as the value in AX register\n"
106 "\t\t\t\treturned from int16/AH=1. The high byte is the\n"
107 "\t\t\t\tscan code and the low byte is ASCII code. The\n"
108 "\t\t\t\tdefault is 0x3920 for space bar.\n\n"
109 "\t--key-name=S\t\tSpecify the name of the hot key.\n\n"
110 "\t--floppy,-f\t\tif DEVICE_OR_FILE is floppy, use this option.\n\n"
111 "\t--floppy=N\t\tif DEVICE_OR_FILE is a partition on a hard\n"
112 "\t\t\t\tdrive, use this option. N is used to specify\n"
113 "\t\t\t\tthe partition number: 0,1,2 and 3 for the\n"
114 "\t\t\t\tprimary partitions, and 4,5,6,... for the\n"
115 "\t\t\t\tlogical partitions.\n\n"
116 "\t--sectors-per-track=S\tspecifies sectors per track for --floppy.\n"
117 "\t\t\t\t1 <= S <= 63, default is 63.\n\n"
118 "\t--heads=H\t\tspecifies number of heads for --floppy.\n"
119 "\t\t\t\t1 <= H <= 256, default is 255.\n\n"
120 "\t--start-sector=B\tspecifies hidden sectors for --floppy=N.\n\n"
121 "\t--total-sectors=C\tspecifies total sectors for --floppy.\n"
122 "\t\t\t\tdefault is 0.\n\n"
123 "\t--lba\t\t\tuse lba mode for --floppy. If the floppy BIOS\n"
124 "\t\t\t\thas LBA support, you can specify --lba here.\n"
125 "\t\t\t\tIt is assumed that all floppy BIOSes have CHS\n"
126 "\t\t\t\tsupport. So you would rather specify --chs.\n"
127 "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
128 "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
129 "\t\t\t\tboot sector) will not be touched.\n\n"
130 "\t--chs\t\t\tuse chs mode for --floppy. You should specify\n"
131 "\t\t\t\t--chs if the floppy BIOS does not support LBA.\n"
132 "\t\t\t\tWe assume all floppy BIOSes have CHS support.\n"
133 "\t\t\t\tSo it is likely you want to specify --chs.\n"
134 "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
135 "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
136 "\t\t\t\tboot sector) will not be touched.\n\n"
137 "\t--install-partition=I\tInstall the boot record onto the boot area of\n"
138 "\t-p=I\t\t\tpartition number I of the specified hard drive\n"
139 "\t\t\t\tor harddrive image DEVICE_OR_FILE.\n\n"
140 "\t--boot-file=F,-b=F\tChange the name of boot file.\n\n"
141 "\t--load-seg=S\t\tChange load segment for boot file.\n\n"
142 "\t--grub2,-2\t\tLoad grub2 kernel g2ldr instead of grldr.\n\n"
143 "\t--output,-o\t\tSave embeded grldr.mbr to DEVICE_OR_FILE.\n\n"
144 "\t--edit,-e\t\tEdit external grldr/grldr.mbr.\n",
145 stderr);
148 int afg,gfg,def_drive,def_part,time_out,hot_key,part_num;
149 int def_spt,def_hds,def_ssc,def_tsc;
150 char *save_fn,*restore_fn,boot_file_83[12];
151 const char *key_name;
152 const char *boot_file;
153 unsigned short load_seg;
155 static char fn_buf[24];
157 static char* get_disk_name(int n)
159 #if defined(WIN32)
160 sprintf(fn_buf,"\\\\.\\PhysicalDrive%d",n);
161 #elif defined(LINUX)
162 sprintf(fn_buf,"/dev/hd%c",'a'+n);
163 #elif defined(FREEBSD)
164 sprintf(fn_buf,"/dev/ad%d",n);
165 #else
166 print_apperr("Disk device is not supported in your system");
167 return NULL;
168 #endif
169 return fn_buf;
172 static char* get_flop_name(int n)
174 #if defined(WIN32)
175 if (n>1)
177 print_apperr("Only two floppy drives are supported");
178 return NULL;
180 sprintf(fn_buf,"\\\\.\\%c:",'A'+n);
181 #elif defined(LINUX) || defined(FREEBSD)
182 sprintf(fn_buf,"/dev/fd%d",n);
183 #else
184 print_apperr("Floppy device is not supported in your system");
185 return NULL;
186 #endif
187 return fn_buf;
190 static char* parse_fname(char* fn)
192 if ((afg & AFG_OUTPUT) && (fn[0]=='('))
194 print_apperr("Can\'t use device name while using --output option");
195 return NULL;
197 if ((! strncmp(fn,"(hd",3)) || (! strncmp(fn,"(fd",3)))
199 int n;
200 char *p;
202 n=strtol(&fn[3],&p,0);
203 if ((n<0) || (n>=MAX_DISKS))
205 print_apperr("Invalid device number");
206 return NULL;
208 if (*p==',')
210 part_num=strtol(p+1,&p,0);
211 if ((part_num<0) || (part_num>=MAX_PARTS))
213 print_apperr("Invalid partition number");
214 return NULL;
217 if ((*p!=')') || (*(p+1)!=0))
219 print_apperr("Invalid device name");
220 return NULL;
222 if (fn[1]=='h')
223 fn=get_disk_name(n);
224 else
226 fn=get_flop_name(n);
227 afg|=AFG_IS_FLOPPY;
230 return fn;
233 static char* str_upcase(char* str)
235 int i;
237 for (i=0;str[i];i++)
238 if ((str[i]>='a') && (str[i]<='z'))
239 str[i]-='a'-'A';
241 return str;
244 static char* str_lowcase(char* str)
246 int i;
248 for (i=0;str[i];i++)
249 if ((str[i]>='A') && (str[i]<='Z'))
250 str[i]+='a'-'A';
252 return str;
255 static int SetBootFile(char* fn)
257 char* pc;
259 if (*fn==0)
260 return 1;
261 if (strlen(fn)>7)
262 return 1;
263 pc=strchr(fn,'.');
264 if (pc)
265 if ((pc==fn) || (pc-fn>8) || (strlen(pc+1)>3))
266 return 1;
267 str_upcase(fn);
268 memset(boot_file_83,' ',sizeof(boot_file_83)-1);
269 if (pc)
271 memcpy(boot_file_83,fn,pc-fn);
272 memcpy(&boot_file_83[8],pc+1,strlen(pc+1));
274 else
275 memcpy(boot_file_83,fn,strlen(fn));
276 str_lowcase(fn);
277 boot_file=fn;
278 return 0;
281 static void list(int hd)
283 xde_t xe;
285 xe.cur=xe.nxt=0xFF;
286 fprintf(stderr," # id base leng\n");
287 while (! xd_enum(hd,&xe))
288 fprintf(stderr,"%2d %02llX %8llX %8llX\n",xe.cur,
289 (unsigned long long) xe.dfs,
290 (unsigned long long) xe.bse,
291 (unsigned long long) xe.len);
294 static int is_grldr_mbr(unsigned char* buf)
296 int i,n;
298 i=0x1B7;
299 n=sizeof("Missing MBR-helper.")-1;
301 while ((i>n) && (buf[i]==0))
302 i--;
303 return (! memcmp(&buf[i-n+1],"Missing MBR-helper.", sizeof("Missing MBR-helper.")));
306 static int install(char* fn)
308 int hd = -1,nn,fs,slen;
309 unsigned char prev_mbr[sizeof(grub_mbr)];
310 unsigned long ssec;
312 if (fn==NULL)
313 return 1;
315 if (afg & AFG_EDIT)
317 unsigned short r1,r2;
319 if (afg & AFG_VERBOSE)
320 fprintf(stderr,"Edit mode\n");
321 hd=open(fn,O_RDWR | O_BINARY,0644);
322 if (hd==-1)
324 print_syserr("open");
325 return errno;
327 r1=get16(&grub_mbr[0x1FFA],0);
328 nn=read(hd,grub_mbr,sizeof(grub_mbr));
329 if (nn==-1)
331 print_syserr("read");
332 close(hd);
333 return errno;
335 if (nn<(int)sizeof(grub_mbr))
337 print_apperr("The input file is too short");
338 close(hd);
339 return 1;
341 if (get32(&grub_mbr[0x1FFC],0)!=0xAA555247)
343 print_apperr("Invalid input file");
344 close(hd);
345 return 1;
347 r2=get16(&grub_mbr[0x1FFA],0);
348 if (r1!=r2)
350 char buf[80];
352 sprintf(buf,"Version number mismatched (old=%d new=%d)",r2,r1);
353 print_apperr(buf);
354 close(hd);
355 return 1;
357 go_sect(hd,0);
358 afg |= AFG_OUTPUT;
361 if (boot_file)
363 unsigned short ofs;
365 // Patching the FAT32 boot sector
366 ofs=get16(&grub_mbr,0x400+0x1EC) & 0x7FF;
367 strcpy((char *) &grub_mbr[0x400+ofs],boot_file_83);
368 if (load_seg)
369 set16(&grub_mbr,0x400+0x1EA,load_seg);
371 // Patching the FAT12/FAT16 boot sector
372 ofs=get16(&grub_mbr,0x600+0x1EC) & 0x7FF;
373 strcpy((char *) &grub_mbr[0x600+ofs],boot_file_83);
374 if (load_seg)
375 set16(&grub_mbr,0x600+0x1EA,load_seg);
377 // Patching the EXT2 boot sector
378 ofs=get16(grub_mbr,0x800+0x1EE) & 0x7FF;
379 strcpy((char *) &grub_mbr[0x800+ofs],boot_file);
381 // Patching the NTFS sector
382 ofs=get16(grub_mbr,0xA00+0x1EC) & 0x7FF;
383 strcpy((char *) &grub_mbr[0xA00+ofs],boot_file);
384 if (load_seg)
385 set16(grub_mbr,0xA00+0x1EA,load_seg);
387 if (afg & AFG_VERBOSE)
389 fprintf(stderr,"Boot file changed to %s\n",boot_file);
390 if (load_seg)
391 fprintf(stderr,"Load segment changed to %04X\n",load_seg);
395 if (afg & AFG_OUTPUT)
397 int mode;
399 mode=(! (afg & AFG_READ_ONLY))?(O_TRUNC | O_CREAT):0;
400 if (! (afg & AFG_EDIT))
402 if (afg & AFG_VERBOSE)
403 fprintf(stderr,"Extract mode\n");
404 hd=open(fn,O_RDWR | O_BINARY | mode,0644);
405 if (hd==-1)
407 print_syserr("open");
408 return errno;
411 if (! (afg & AFG_READ_ONLY))
412 if (write(hd,grub_mbr,sizeof(grub_mbr))!=sizeof(grub_mbr))
414 print_apperr("Write to output file fails");
415 close(hd);
416 return 1;
418 goto quit;
421 memset(&grub_mbr[512],0,512);
422 grub_mbr[2] = gfg;
423 grub_mbr[3]=time_out;
424 set16(&grub_mbr,4,hot_key);
425 grub_mbr[6] = def_drive;
426 grub_mbr[7] = def_part;
427 if ((key_name==NULL) && (hot_key==0x3920))
428 key_name="SPACE";
429 if (key_name)
430 strcpy((char *) &grub_mbr[0x1fec],key_name);
432 hd=open(fn,O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
433 if (hd==-1)
435 print_syserr("open");
436 return errno;
438 if (afg & AFG_LIST_PART)
440 list(hd);
441 close(hd);
442 return 0;
444 if (part_num!=-1)
446 if (def_ssc!=-1)
447 ssec=def_ssc;
448 else
450 xde_t xe;
452 xe.cur=0xFF;
453 xe.nxt=part_num;
454 if (xd_enum(hd,&xe))
456 print_apperr("Partition not found");
457 close(hd);
458 return 1;
460 ssec=xe.bse;
461 if (afg & AFG_VERBOSE)
462 fprintf(stderr,"Part Fs: %02X (%s)\nPart Leng: %llu\n",xe.dfs,dfs2str(xe.dfs),
463 (unsigned long long) xe.len);
466 else
467 ssec=0;
468 if (afg & AFG_VERBOSE)
469 fprintf(stderr,"Start sector: %llu\n", (unsigned long long) ssec);
470 if ((ssec) && (go_sect(hd,ssec)))
472 print_apperr("Can\'t seek to the start sector");
473 close(hd);
474 return 1;
476 nn=read(hd,prev_mbr,sizeof(prev_mbr));
477 if (nn==-1)
479 print_syserr("read");
480 close(hd);
481 return errno;
483 if (nn<(int)sizeof(prev_mbr))
485 print_apperr("The input file is too short");
486 close(hd);
487 return 1;
489 fs=get_fstype(prev_mbr);
490 if (afg & AFG_VERBOSE)
492 fprintf(stderr,"Image type: %s\n",fst2str(fs));
493 if (fs==FST_MBR)
494 fprintf(stderr,"Num of heads: %d\nSectors per track: %d\n",mbr_nhd,mbr_spt);
496 if (fs==FST_OTHER)
498 print_apperr("Unknown image type");
499 close(hd);
500 return 1;
502 if (((part_num!=-1) || (afg & AFG_IS_FLOPPY)) && (fs==FST_MBR))
504 print_apperr("Should be a file system image");
505 close(hd);
506 return 1;
508 if ((part_num==-1) && ((afg & AFG_IS_FLOPPY)==0) && (fs!=FST_MBR))
510 print_apperr("Should be a disk image");
511 close(hd);
512 return 1;
514 if (fs==FST_MBR)
516 int n,nfs,sln;
517 unsigned long ofs;
518 unsigned char bs[1024];
520 ofs=0xFFFFFFFF;
521 for (n=0x1BE;n<0x1FE;n+=16)
522 if (prev_mbr[n+4])
524 if (ofs>get32(&prev_mbr[n],8))
525 ofs=get32(&prev_mbr[n],8);
527 if (ofs<(sizeof(prev_mbr)>>9))
529 print_apperr("Not enough room to install mbr");
530 close(hd);
531 return 1;
533 slen=sizeof(prev_mbr);
534 if (go_sect(hd,ofs))
536 print_apperr("Can\'t seek to the first partition");
537 close(hd);
538 return 1;
540 if (read(hd,bs,sizeof(bs))!=sizeof(bs))
542 print_apperr("Fail to read boot sector");
543 close(hd);
544 return 1;
546 nfs=get_fstype(bs);
547 if (nfs==FST_FAT32)
548 sln=0x5A - 0xB;
549 else if (nfs==FST_FAT16)
550 sln=0x3E - 0xB;
551 else
552 sln=0;
553 if (sln)
555 memcpy(&grub_mbr[0xB],&bs[0xB],sln);
556 set32(&grub_mbr[0],0x1C,0);
557 set16(&grub_mbr[0],0xE,get16(&grub_mbr[0],0xE) + ofs);
560 else if (fs==FST_NTFS)
561 slen=2048;
562 else
563 slen=512;
565 if (go_sect(hd,ssec))
567 print_apperr("Can\'t seek to the start sector");
568 close(hd);
569 return 1;
572 if (save_fn)
574 int h2;
576 h2=open(save_fn,O_CREAT | O_TRUNC | O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
577 if (h2==-1)
579 print_syserr("open save file");
580 close(hd);
581 return errno;
583 nn=write(h2,prev_mbr,slen);
584 if (nn==-1)
586 print_syserr("write save file");
587 close(hd);
588 close(h2);
589 return errno;
591 if (nn<slen)
593 print_apperr("Can\'t write the whole MBR to the save file");
594 close(hd);
595 close(h2);
596 return 1;
598 close(h2);
600 if (afg & AFG_RESTORE_PREVMBR)
602 if (fs!=FST_MBR)
604 print_apperr("Not a disk image");
605 close(hd);
606 return 1;
608 if (memcmp(&prev_mbr[1024+3],"GRLDR",5))
610 print_apperr("GRLDR is not installed");
611 close(hd);
612 return 1;
614 if (get16(prev_mbr,512+510)!=0xAA55)
616 print_apperr("No previous saved MBR");
617 close(hd);
618 return 1;
620 memset(&grub_mbr,0,sizeof(grub_mbr));
621 memcpy(&grub_mbr,&prev_mbr[512],512);
622 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
624 if (afg & AFG_VERBOSE)
625 fprintf(stderr,"Restore previous MBR mode\n");
627 else
629 // Load MBR/BS from restore file or configure grub_mbr
630 if (restore_fn)
632 int h2;
634 h2=open(restore_fn,O_RDONLY | O_BINARY,S_IREAD);
635 if (h2==-1)
637 print_syserr("open restore file");
638 close(hd);
639 return errno;
641 nn=read(h2,grub_mbr,slen);
642 if (nn==-1)
644 print_syserr("read restore file");
645 close(hd);
646 close(h2);
647 return errno;
649 if ((nn<512) || ((nn & 0x1FF)!=0) ||
650 ((fs!=FST_EXT2) && (get16(grub_mbr,510)!=0xAA55)))
652 print_apperr("Invalid restore file");
653 close(hd);
654 close(h2);
655 return 1;
657 close(h2);
658 if (nn<slen)
659 memset(&grub_mbr[nn],0,slen-nn);
661 //if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
662 if (fs!=FST_EXT2)
664 int new_fs;
666 new_fs=get_fstype(grub_mbr);
667 if (new_fs!=fs)
669 print_apperr("Invalid restore file");
670 close(hd);
671 return 1;
675 if (afg & AFG_VERBOSE)
676 fprintf(stderr,"Restore mode\n");
678 else
680 if (fs==FST_MBR)
682 if (! (afg & AFG_NO_BACKUP_MBR))
684 int i;
686 if (afg & AFG_FORCE_BACKUP_MBR)
687 i=512;
688 else
689 for (i=1;i<512;i++)
690 if (prev_mbr[512+i]!=prev_mbr[512])
691 break;
693 if ((i==512) && (! is_grldr_mbr(prev_mbr)))
694 memcpy(&grub_mbr[512],prev_mbr,512);
695 else
696 memcpy(&grub_mbr[512],&prev_mbr[512],512);
698 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
700 else if (fs==FST_FAT16)
702 memcpy(grub_mbr,&grub_mbr[0x600],slen);
703 grub_mbr[0x41]=part_num;
705 else if (fs==FST_FAT32)
707 memcpy(grub_mbr,&grub_mbr[0x400],slen);
708 grub_mbr[0x5D]=part_num;
710 else if (fs==FST_NTFS)
712 memcpy(grub_mbr,&grub_mbr[0xA00],slen);
713 grub_mbr[0x57]=part_num;
715 else if (fs==FST_EXT2)
717 memcpy(&grub_mbr,&grub_mbr[0x800],slen);
718 grub_mbr[0x25]=part_num;
719 if (afg & AFG_LBA_MODE)
720 grub_mbr[2]=0x42;
721 else if (afg & AFG_CHS_MODE)
722 grub_mbr[2]=0x2;
723 if (def_spt!=-1)
724 set16(&grub_mbr,0x18,def_spt);
725 else if ((afg & AFG_IS_FLOPPY)==0)
726 set16(&grub_mbr,0x18,63);
727 if (def_hds!=-1)
728 set16(&grub_mbr,0x1A,def_hds);
729 else if ((afg & AFG_IS_FLOPPY)==0)
730 set16(&grub_mbr,0x1A,255);
731 if (def_tsc!=-1)
732 set32(&grub_mbr,0x20,def_tsc);
733 set32(&grub_mbr,0x1C,ssec);
734 // s_inode_size
735 if (prev_mbr[1024+0x4C]) // s_rev_level
736 set16(&grub_mbr,0x26,get16(&prev_mbr[1024],0x58));
737 else
738 set16(&grub_mbr,0x26,0x80);
739 // s_inodes_per_group
740 set32(&grub_mbr,0x28,get32(&prev_mbr[1024],0x28));
741 // s_first_data_block+1
742 set32(&grub_mbr,0x2C,get32(&prev_mbr[1024],0x14)+1);
744 else
746 // Shouldn't be here
747 print_apperr("Invalid file system");
748 close(hd);
749 return 1;
751 if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
753 if (afg & AFG_LBA_MODE)
754 grub_mbr[2]=0xe;
755 else if (afg & AFG_CHS_MODE)
756 grub_mbr[2]=0x90;
757 else
758 grub_mbr[2]=prev_mbr[2];
761 if (afg & AFG_VERBOSE)
762 fprintf(stderr,"Install mode\n");
764 // Patch the new MBR/BS with information from prev_mbr
765 if (fs==FST_MBR)
766 memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
767 else if (fs==FST_FAT16)
769 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x3E - 0xB);
770 set32(grub_mbr,0x1C,ssec);
772 else if (fs==FST_FAT32)
774 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x5A - 0xB);
775 set32(grub_mbr,0x1C,ssec);
777 else if (fs==FST_NTFS)
779 memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x54 - 0xB);
780 set32(grub_mbr,0x1C,ssec);
783 if (! (afg & AFG_READ_ONLY))
785 nn=write(hd,grub_mbr,slen);
786 if (nn==-1)
788 print_syserr("write");
789 close(hd);
790 return errno;
792 if (nn<slen)
794 print_apperr("Can\'t write the whole mbr");
795 close(hd);
796 return 1;
799 else if (afg & AFG_VERBOSE)
800 fprintf(stderr,"Read only mode\n");
801 quit:
802 close(hd);
803 if (afg & AFG_PAUSE)
805 fputs("The MBR/BS has been successfully installed\n",stderr);
806 print_pause;
808 return 0;
811 int main(int argc,char** argv)
813 int idx;
815 afg=gfg=0;
816 part_num=def_drive=def_part=def_spt=def_hds=def_ssc=def_tsc=-1;
817 afg=0;
818 gfg=GFG_PREVMBR_LAST;
819 time_out=5;
820 hot_key=0x3920;
821 save_fn=NULL;
822 restore_fn=NULL;
823 for (idx=1;idx<argc;idx++)
825 if (argv[idx][0]!='-')
826 break;
827 if ((! strcmp(argv[idx],"--help"))
828 || (! strcmp(argv[idx],"-h")))
830 help();
831 print_pause;
832 return 1;
834 else if (! strcmp(argv[idx],"--version"))
836 fprintf(stderr,"grubinst version : " VERSION "\n");
837 print_pause;
838 return 1;
840 else if ((! strcmp(argv[idx],"--verbose")) ||
841 (! strcmp(argv[idx],"-v")))
842 afg |=AFG_VERBOSE;
843 else if (! strcmp(argv[idx],"--pause"))
844 afg|=AFG_PAUSE;
845 else if ((! strcmp(argv[idx],"--read-only"))
846 || (! strcmp(argv[idx],"-t")))
847 afg|=AFG_READ_ONLY;
848 else if (! strcmp(argv[idx],"--no-backup-mbr"))
849 afg|=AFG_NO_BACKUP_MBR;
850 else if (! strcmp(argv[idx],"--force-backup-mbr"))
851 afg|=AFG_FORCE_BACKUP_MBR;
852 else if (! strcmp(argv[idx],"--mbr-enable-floppy"))
853 gfg&=~GFG_DISABLE_FLOPPY;
854 else if (! strcmp(argv[idx],"--mbr-disable-floppy"))
855 gfg|=GFG_DISABLE_FLOPPY;
856 else if (! strcmp(argv[idx],"--mbr-enable-osbr"))
857 gfg&=~GFG_DISABLE_OSBR;
858 else if (! strcmp(argv[idx],"--mbr-disable-osbr"))
859 gfg|=GFG_DISABLE_OSBR;
860 else if (! strcmp(argv[idx],"--duce"))
861 gfg|=GFG_DUCE;
862 else if (! strcmp(argv[idx],"--boot-prevmbr-first"))
863 gfg&=~GFG_PREVMBR_LAST;
864 else if (! strcmp(argv[idx],"--boot-prevmbr-last"))
865 gfg|=GFG_PREVMBR_LAST;
866 else if (! strncmp(argv[idx],"--preferred-drive=",18))
868 def_drive=strtol(&argv[idx][18],NULL,0);
869 if ((def_drive<0) || (def_drive>=255))
871 print_apperr("Invalid preferred drive number");
872 return 1;
875 else if (! strncmp(argv[idx],"--preferred-partition=",22))
877 def_part=strtol(&argv[idx][22],NULL,0);
878 if ((def_part<0) || (def_part>=255))
880 print_apperr("Invalid preferred partition number");
881 return 1;
884 else if ((! strncmp(argv[idx],"--time-out=",11)) ||
885 (! strncmp(argv[idx],"-t=",3)))
887 time_out=strtol((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][11],NULL,0);
888 if ((time_out<0) || (time_out>255))
890 print_apperr("Invalid timeout value");
891 return 1;
894 else if ((! strncmp(argv[idx],"--key-name=",11)))
896 key_name=&argv[idx][11];
897 if (strlen(key_name)>13)
899 print_apperr("Key name too long");
900 return 1;
903 else if ((! strcmp(argv[idx],"--restore-prevmbr")) ||
904 (! strcmp(argv[idx],"-r")))
905 afg|=AFG_RESTORE_PREVMBR;
906 else if ((! strncmp(argv[idx],"--save=",7)) ||
907 (! strncmp(argv[idx],"-s=",3)))
909 save_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][7];
910 if (*save_fn==0)
912 print_apperr("Empty filename");
913 return 1;
916 else if ((! strncmp(argv[idx],"--restore=",10)) ||
917 (! strncmp(argv[idx],"-r=",3)))
919 restore_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][10];
920 if (*restore_fn==0)
922 print_apperr("Empty filename");
923 return 1;
926 else if ((! strcmp(argv[idx],"--list-part")) ||
927 (! strcmp(argv[idx],"-l")))
928 afg|=AFG_LIST_PART;
929 else if ((! strcmp(argv[idx],"--floppy")) ||
930 (! strcmp(argv[idx],"-f")))
931 afg|=AFG_IS_FLOPPY;
932 else if ((! strncmp(argv[idx],"--floppy=",9)) ||
933 (! strncmp(argv[idx],"--install-partition=",20)) ||
934 (! strncmp(argv[idx],"-p=",3)))
936 char *p;
938 if (argv[idx][2]=='f')
939 p=&argv[idx][9];
940 else if (argv[idx][2]=='i')
941 p=&argv[idx][20];
942 else
943 p=&argv[idx][3];
944 part_num=strtoul(p,NULL,0);
945 if ((part_num<0) || (part_num>=MAX_PARTS))
947 print_apperr("Invalid partition number");
948 return 1;
951 else if (! strcmp(argv[idx],"--lba"))
952 afg|=AFG_LBA_MODE;
953 else if (! strcmp(argv[idx],"--chs"))
954 afg|=AFG_CHS_MODE;
955 else if (! strncmp(argv[idx],"--sectors-per-track=",20))
957 def_spt=strtol(&argv[idx][10],NULL,0);
958 if ((def_spt<1) || (def_spt>63))
960 print_apperr("Invalid sector per track");
961 return 1;
964 else if (! strncmp(argv[idx],"--heads=",8))
966 def_hds=strtol(&argv[idx][8],NULL,0);
967 if ((def_hds<1) || (def_hds>255))
969 print_apperr("Invalid number of heads");
970 return 1;
973 else if (! strncmp(argv[idx],"--start-sector=",15))
975 def_spt=strtol(&argv[idx][15],NULL,0);
976 if (def_ssc<0)
978 print_apperr("Invalid start sector");
979 return 1;
982 else if (! strncmp(argv[idx],"--total-sectors=",16))
984 def_tsc=strtol(&argv[idx][16],NULL,0);
985 if (def_tsc<0)
987 print_apperr("Invalid total sectors");
988 return 1;
991 else if ((! strncmp(argv[idx],"--boot-file=",12)) ||
992 (! strncmp(argv[idx],"-b=",3)))
994 if (SetBootFile((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][12]))
996 print_apperr("Invalid boot file name");
997 return 1;
1000 else if (! strncmp(argv[idx],"--load-seg=",11))
1002 load_seg=strtoul(&argv[idx][11],NULL,16);
1003 if (load_seg<0x1000)
1005 print_apperr("Load address too small");
1006 return 1;
1009 else if ((! strcmp(argv[idx],"--grub2")) ||
1010 (! strcmp(argv[idx],"-2")))
1012 if (! boot_file)
1014 boot_file="g2ldr";
1015 strcpy(boot_file_83,"G2LDR ");
1018 else if ((! strcmp(argv[idx],"--output")) ||
1019 (! strcmp(argv[idx],"-o")))
1020 afg|=AFG_OUTPUT;
1021 else if ((! strcmp(argv[idx],"--edit")) ||
1022 (! strcmp(argv[idx],"-e")))
1023 afg|=AFG_EDIT;
1024 else
1026 print_apperr("Invalid option, please use --help to see all valid options");
1027 return 1;
1030 if (idx>=argc)
1032 print_apperr("No filename specified");
1033 return 1;
1035 if (idx<argc-1)
1037 print_apperr("Extra parameters");
1038 return 1;
1040 return install(parse_fname(argv[idx]));