summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/ntldr-img/grubinst.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/grub-extras/ntldr-img/grubinst.c')
-rw-r--r--debian/grub-extras/ntldr-img/grubinst.c1043
1 files changed, 1043 insertions, 0 deletions
diff --git a/debian/grub-extras/ntldr-img/grubinst.c b/debian/grub-extras/ntldr-img/grubinst.c
new file mode 100644
index 0000000..2f7561a
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/grubinst.c
@@ -0,0 +1,1043 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef WIN32
+
+#define O_BINARY 0
+
+#endif
+
+#include "grub_mbr.h"
+#include "utils.h"
+#include "version.h"
+
+// Application flags, used by this program
+
+#define AFG_VERBOSE 1
+#define AFG_PAUSE 2
+#define AFG_READ_ONLY 4
+#define AFG_NO_BACKUP_MBR 8
+#define AFG_FORCE_BACKUP_MBR 16
+#define AFG_RESTORE_PREVMBR 32
+#define AFG_LIST_PART 64
+#define AFG_IS_FLOPPY 128
+#define AFG_LBA_MODE 256
+#define AFG_CHS_MODE 512
+#define AFG_OUTPUT 1024
+#define AFG_EDIT 2048
+
+// Grldr flags, this flag is used by grldr.mbr
+
+#define GFG_DISABLE_FLOPPY 1
+#define GFG_DISABLE_OSBR 2
+#define GFG_DUCE 4
+#define GFG_PREVMBR_LAST 128
+
+#define APP_NAME "grubinst: "
+
+#define print_pause if (afg & AFG_PAUSE) {fputs("Press <ENTER> to continue ...\n",stderr); fflush(stderr); fgetc(stdin);}
+
+#define print_apperr(a) { fprintf(stderr,APP_NAME "%s\n",a); print_pause; }
+#define print_syserr(a) { perror(APP_NAME a); print_pause; }
+
+static void help(void)
+{
+ fputs("Usage:\n"
+ "\tgrubinst [OPTIONS] DEVICE_OR_FILE\n\n"
+ "OPTIONS:\n\n"
+ "\t--help,-h\t\tShow usage information\n\n"
+ "\t--pause\t\t\tPause before exiting\n\n"
+ "\t--version\t\tShow version information\n\n"
+ "\t--verbose,-v\t\tVerbose output\n\n"
+ "\t--list-part,-l\t\tList all logical partitions in DEVICE_OR_FILE\n\n"
+ "\t--save=FN,-s=FN\t\tSave the orginal MBR/BS to FN\n\n"
+ "\t--restore=FN,-r=FN\tRestore MBR/BS from previously saved FN\n\n"
+ "\t--restore-prevmbr,-r\tRestore previous MBR saved in the second sector\n"
+ "\t\t\t\tof DEVICE_OR_FILE\n\n"
+ "\t--read-only,-t\t\tdo everything except the actual write to the\n"
+ "\t\t\t\tspecified DEVICE_OR_FILE. (test mode)\n\n"
+ "\t--no-backup-mbr\t\tdo not copy the old MBR to the second sector of\n"
+ "\t\t\t\tDEVICE_OR_FILE.\n\n"
+ "\t--force-backup-mbr\tforce the copy of old MBR to the second sector\n"
+ "\t\t\t\tof DEVICE_OR_FILE.(default)\n\n"
+ "\t--mbr-enable-floppy\tenable the search for GRLDR on floppy.(default)\n\n"
+ "\t--mbr-disable-floppy\tdisable the search for GRLDR on floppy.\n\n"
+ "\t--mbr-enable-osbr\tenable the boot of PREVIOUS MBR with invalid\n"
+ "\t\t\t\tpartition table (usually an OS boot sector).\n"
+ "\t\t\t\t(default)\n\n"
+ "\t--mbr-disable-osbr\tdisable the boot of PREVIOUS MBR with invalid\n"
+ "\t\t\t\tpartition table (usually an OS boot sector).\n\n"
+ "\t--duce\t\t\tdisable the feature of unconditional entrance\n"
+ "\t\t\t\tto the command-line.\n\n"
+ "\t--boot-prevmbr-first\ttry to boot PREVIOUS MBR before the search for\n"
+ "\t\t\t\tGRLDR.\n\n"
+ "\t--boot-prevmbr-last\ttry to boot PREVIOUS MBR after the search for\n"
+ "\t\t\t\tGRLDR.(default)\n\n"
+ "\t--preferred-drive=D\tpreferred boot drive number, 0 <= D < 255.\n\n"
+ "\t--preferred-partition=P\tpreferred partition number, 0 <= P < 255.\n\n"
+ "\t--time-out=T,-t=T\twait T seconds before booting PREVIOUS MBR. if\n"
+ "\t\t\t\tT is 0xff, wait forever. The default is 5.\n\n"
+ "\t\t\t\tbefore booting PREVIOUS MBR. K is a word\n"
+ "\t\t\t\tvalue, just as the value in AX register\n"
+ "\t\t\t\treturned from int16/AH=1. The high byte is the\n"
+ "\t\t\t\tscan code and the low byte is ASCII code. The\n"
+ "\t\t\t\tdefault is 0x3920 for space bar.\n\n"
+ "\t--key-name=S\t\tSpecify the name of the hot key.\n\n"
+ "\t--floppy,-f\t\tif DEVICE_OR_FILE is floppy, use this option.\n\n"
+ "\t--floppy=N\t\tif DEVICE_OR_FILE is a partition on a hard\n"
+ "\t\t\t\tdrive, use this option. N is used to specify\n"
+ "\t\t\t\tthe partition number: 0,1,2 and 3 for the\n"
+ "\t\t\t\tprimary partitions, and 4,5,6,... for the\n"
+ "\t\t\t\tlogical partitions.\n\n"
+ "\t--sectors-per-track=S\tspecifies sectors per track for --floppy.\n"
+ "\t\t\t\t1 <= S <= 63, default is 63.\n\n"
+ "\t--heads=H\t\tspecifies number of heads for --floppy.\n"
+ "\t\t\t\t1 <= H <= 256, default is 255.\n\n"
+ "\t--start-sector=B\tspecifies hidden sectors for --floppy=N.\n\n"
+ "\t--total-sectors=C\tspecifies total sectors for --floppy.\n"
+ "\t\t\t\tdefault is 0.\n\n"
+ "\t--lba\t\t\tuse lba mode for --floppy. If the floppy BIOS\n"
+ "\t\t\t\thas LBA support, you can specify --lba here.\n"
+ "\t\t\t\tIt is assumed that all floppy BIOSes have CHS\n"
+ "\t\t\t\tsupport. So you would rather specify --chs.\n"
+ "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
+ "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
+ "\t\t\t\tboot sector) will not be touched.\n\n"
+ "\t--chs\t\t\tuse chs mode for --floppy. You should specify\n"
+ "\t\t\t\t--chs if the floppy BIOS does not support LBA.\n"
+ "\t\t\t\tWe assume all floppy BIOSes have CHS support.\n"
+ "\t\t\t\tSo it is likely you want to specify --chs.\n"
+ "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
+ "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
+ "\t\t\t\tboot sector) will not be touched.\n\n"
+ "\t--install-partition=I\tInstall the boot record onto the boot area of\n"
+ "\t-p=I\t\t\tpartition number I of the specified hard drive\n"
+ "\t\t\t\tor harddrive image DEVICE_OR_FILE.\n\n"
+ "\t--boot-file=F,-b=F\tChange the name of boot file.\n\n"
+ "\t--load-seg=S\t\tChange load segment for boot file.\n\n"
+ "\t--grub2,-2\t\tLoad grub2 kernel g2ldr instead of grldr.\n\n"
+ "\t--output,-o\t\tSave embeded grldr.mbr to DEVICE_OR_FILE.\n\n"
+ "\t--edit,-e\t\tEdit external grldr/grldr.mbr.\n",
+ stderr);
+}
+
+int afg,gfg,def_drive,def_part,time_out,hot_key,part_num;
+int def_spt,def_hds,def_ssc,def_tsc;
+char *save_fn,*restore_fn,boot_file_83[12];
+const char *key_name;
+const char *boot_file;
+unsigned short load_seg;
+
+static char fn_buf[24];
+
+static char* get_disk_name(int n)
+{
+#if defined(WIN32)
+ sprintf(fn_buf,"\\\\.\\PhysicalDrive%d",n);
+#elif defined(LINUX)
+ sprintf(fn_buf,"/dev/hd%c",'a'+n);
+#elif defined(FREEBSD)
+ sprintf(fn_buf,"/dev/ad%d",n);
+#else
+ print_apperr("Disk device is not supported in your system");
+ return NULL;
+#endif
+ return fn_buf;
+}
+
+static char* get_flop_name(int n)
+{
+#if defined(WIN32)
+ if (n>1)
+ {
+ print_apperr("Only two floppy drives are supported");
+ return NULL;
+ }
+ sprintf(fn_buf,"\\\\.\\%c:",'A'+n);
+#elif defined(LINUX) || defined(FREEBSD)
+ sprintf(fn_buf,"/dev/fd%d",n);
+#else
+ print_apperr("Floppy device is not supported in your system");
+ return NULL;
+#endif
+ return fn_buf;
+}
+
+static char* parse_fname(char* fn)
+{
+ if ((afg & AFG_OUTPUT) && (fn[0]=='('))
+ {
+ print_apperr("Can\'t use device name while using --output option");
+ return NULL;
+ }
+ if ((! strncmp(fn,"(hd",3)) || (! strncmp(fn,"(fd",3)))
+ {
+ int n;
+ char *p;
+
+ n=strtol(&fn[3],&p,0);
+ if ((n<0) || (n>=MAX_DISKS))
+ {
+ print_apperr("Invalid device number");
+ return NULL;
+ }
+ if (*p==',')
+ {
+ part_num=strtol(p+1,&p,0);
+ if ((part_num<0) || (part_num>=MAX_PARTS))
+ {
+ print_apperr("Invalid partition number");
+ return NULL;
+ }
+ }
+ if ((*p!=')') || (*(p+1)!=0))
+ {
+ print_apperr("Invalid device name");
+ return NULL;
+ }
+ if (fn[1]=='h')
+ fn=get_disk_name(n);
+ else
+ {
+ fn=get_flop_name(n);
+ afg|=AFG_IS_FLOPPY;
+ }
+ }
+ return fn;
+}
+
+static char* str_upcase(char* str)
+{
+ int i;
+
+ for (i=0;str[i];i++)
+ if ((str[i]>='a') && (str[i]<='z'))
+ str[i]-='a'-'A';
+
+ return str;
+}
+
+static char* str_lowcase(char* str)
+{
+ int i;
+
+ for (i=0;str[i];i++)
+ if ((str[i]>='A') && (str[i]<='Z'))
+ str[i]+='a'-'A';
+
+ return str;
+}
+
+static int SetBootFile(char* fn)
+{
+ char* pc;
+
+ if (*fn==0)
+ return 1;
+ if (strlen(fn)>7)
+ return 1;
+ pc=strchr(fn,'.');
+ if (pc)
+ if ((pc==fn) || (pc-fn>8) || (strlen(pc+1)>3))
+ return 1;
+ str_upcase(fn);
+ memset(boot_file_83,' ',sizeof(boot_file_83)-1);
+ if (pc)
+ {
+ memcpy(boot_file_83,fn,pc-fn);
+ memcpy(&boot_file_83[8],pc+1,strlen(pc+1));
+ }
+ else
+ memcpy(boot_file_83,fn,strlen(fn));
+ str_lowcase(fn);
+ boot_file=fn;
+ return 0;
+}
+
+static void list(int hd)
+{
+ xde_t xe;
+
+ xe.cur=xe.nxt=0xFF;
+ fprintf(stderr," # id base leng\n");
+ while (! xd_enum(hd,&xe))
+ fprintf(stderr,"%2d %02" PRIX64 " %8" PRIX64 " %8" PRIX64 "\n",
+ xe.cur,
+ (uint64_t) xe.dfs,
+ (uint64_t) xe.bse,
+ (uint64_t) xe.len);
+}
+
+static int is_grldr_mbr(unsigned char* buf)
+{
+ int i,n;
+
+ i=0x1B7;
+ n=sizeof("Missing MBR-helper.")-1;
+
+ while ((i>n) && (buf[i]==0))
+ i--;
+ return (! memcmp(&buf[i-n+1],"Missing MBR-helper.", sizeof("Missing MBR-helper.")));
+}
+
+static int install(char* fn)
+{
+ int hd = -1,nn,fs,slen;
+ unsigned char prev_mbr[sizeof(grub_mbr)];
+ unsigned long ssec;
+
+ if (fn==NULL)
+ return 1;
+
+ if (afg & AFG_EDIT)
+ {
+ unsigned short r1,r2;
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Edit mode\n");
+ hd=open(fn,O_RDWR | O_BINARY,0644);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ r1=get16(&grub_mbr[0x1FFA],0);
+ nn=read(hd,grub_mbr,sizeof(grub_mbr));
+ if (nn==-1)
+ {
+ print_syserr("read");
+ close(hd);
+ return errno;
+ }
+ if (nn<(int)sizeof(grub_mbr))
+ {
+ print_apperr("The input file is too short");
+ close(hd);
+ return 1;
+ }
+ if (get32(&grub_mbr[0x1FFC],0)!=0xAA555247)
+ {
+ print_apperr("Invalid input file");
+ close(hd);
+ return 1;
+ }
+ r2=get16(&grub_mbr[0x1FFA],0);
+ if (r1!=r2)
+ {
+ char buf[80];
+
+ sprintf(buf,"Version number mismatched (old=%d new=%d)",r2,r1);
+ print_apperr(buf);
+ close(hd);
+ return 1;
+ }
+ go_sect(hd,0);
+ afg |= AFG_OUTPUT;
+ }
+
+ if (boot_file)
+ {
+ unsigned short ofs;
+
+ // Patching the FAT32 boot sector
+ ofs=get16(&grub_mbr,0x400+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x400+ofs],boot_file_83);
+ if (load_seg)
+ set16(&grub_mbr,0x400+0x1EA,load_seg);
+
+ // Patching the FAT12/FAT16 boot sector
+ ofs=get16(&grub_mbr,0x600+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x600+ofs],boot_file_83);
+ if (load_seg)
+ set16(&grub_mbr,0x600+0x1EA,load_seg);
+
+ // Patching the EXT2 boot sector
+ ofs=get16(grub_mbr,0x800+0x1EE) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x800+ofs],boot_file);
+
+ // Patching the NTFS sector
+ ofs=get16(grub_mbr,0xA00+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0xA00+ofs],boot_file);
+ if (load_seg)
+ set16(grub_mbr,0xA00+0x1EA,load_seg);
+
+ if (afg & AFG_VERBOSE)
+ {
+ fprintf(stderr,"Boot file changed to %s\n",boot_file);
+ if (load_seg)
+ fprintf(stderr,"Load segment changed to %04X\n",load_seg);
+ }
+ }
+
+ if (afg & AFG_OUTPUT)
+ {
+ int mode;
+
+ mode=(! (afg & AFG_READ_ONLY))?(O_TRUNC | O_CREAT):0;
+ if (! (afg & AFG_EDIT))
+ {
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Extract mode\n");
+ hd=open(fn,O_RDWR | O_BINARY | mode,0644);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ }
+ if (! (afg & AFG_READ_ONLY))
+ if (write(hd,grub_mbr,sizeof(grub_mbr))!=sizeof(grub_mbr))
+ {
+ print_apperr("Write to output file fails");
+ close(hd);
+ return 1;
+ }
+ goto quit;
+ }
+
+ memset(&grub_mbr[512],0,512);
+ grub_mbr[2] = gfg;
+ grub_mbr[3]=time_out;
+ set16(&grub_mbr,4,hot_key);
+ grub_mbr[6] = def_drive;
+ grub_mbr[7] = def_part;
+ if ((key_name==NULL) && (hot_key==0x3920))
+ key_name="SPACE";
+ if (key_name)
+ strcpy((char *) &grub_mbr[0x1fec],key_name);
+
+ hd=open(fn,O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ if (afg & AFG_LIST_PART)
+ {
+ list(hd);
+ close(hd);
+ return 0;
+ }
+ if (part_num!=-1)
+ {
+ if (def_ssc!=-1)
+ ssec=def_ssc;
+ else
+ {
+ xde_t xe;
+
+ xe.cur=0xFF;
+ xe.nxt=part_num;
+ if (xd_enum(hd,&xe))
+ {
+ print_apperr("Partition not found");
+ close(hd);
+ return 1;
+ }
+ ssec=xe.bse;
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Part Fs: %02X (%s)\nPart Leng: %" PRIu64 "\n",xe.dfs,dfs2str(xe.dfs),
+ (uint64_t) xe.len);
+ }
+ }
+ else
+ ssec=0;
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Start sector: %" PRIu64 "\n", (uint64_t) ssec);
+ if ((ssec) && (go_sect(hd,ssec)))
+ {
+ print_apperr("Can\'t seek to the start sector");
+ close(hd);
+ return 1;
+ }
+ nn=read(hd,prev_mbr,sizeof(prev_mbr));
+ if (nn==-1)
+ {
+ print_syserr("read");
+ close(hd);
+ return errno;
+ }
+ if (nn<(int)sizeof(prev_mbr))
+ {
+ print_apperr("The input file is too short");
+ close(hd);
+ return 1;
+ }
+ fs=get_fstype(prev_mbr);
+ if (afg & AFG_VERBOSE)
+ {
+ fprintf(stderr,"Image type: %s\n",fst2str(fs));
+ if (fs==FST_MBR)
+ fprintf(stderr,"Num of heads: %d\nSectors per track: %d\n",mbr_nhd,mbr_spt);
+ }
+ if (fs==FST_OTHER)
+ {
+ print_apperr("Unknown image type");
+ close(hd);
+ return 1;
+ }
+ if (((part_num!=-1) || (afg & AFG_IS_FLOPPY)) && (fs==FST_MBR))
+ {
+ print_apperr("Should be a file system image");
+ close(hd);
+ return 1;
+ }
+ if ((part_num==-1) && ((afg & AFG_IS_FLOPPY)==0) && (fs!=FST_MBR))
+ {
+ print_apperr("Should be a disk image");
+ close(hd);
+ return 1;
+ }
+ if (fs==FST_MBR)
+ {
+ int n,nfs,sln;
+ unsigned long ofs;
+ unsigned char bs[1024];
+
+ ofs=0xFFFFFFFF;
+ for (n=0x1BE;n<0x1FE;n+=16)
+ if (prev_mbr[n+4])
+ {
+ if (ofs>get32(&prev_mbr[n],8))
+ ofs=get32(&prev_mbr[n],8);
+ }
+ if (ofs<(sizeof(prev_mbr)>>9))
+ {
+ print_apperr("Not enough room to install mbr");
+ close(hd);
+ return 1;
+ }
+ slen=sizeof(prev_mbr);
+ if (go_sect(hd,ofs))
+ {
+ print_apperr("Can\'t seek to the first partition");
+ close(hd);
+ return 1;
+ }
+ if (read(hd,bs,sizeof(bs))!=sizeof(bs))
+ {
+ print_apperr("Fail to read boot sector");
+ close(hd);
+ return 1;
+ }
+ nfs=get_fstype(bs);
+ if (nfs==FST_FAT32)
+ sln=0x5A - 0xB;
+ else if (nfs==FST_FAT16)
+ sln=0x3E - 0xB;
+ else
+ sln=0;
+ if (sln)
+ {
+ memcpy(&grub_mbr[0xB],&bs[0xB],sln);
+ set32(&grub_mbr[0],0x1C,0);
+ set16(&grub_mbr[0],0xE,get16(&grub_mbr[0],0xE) + ofs);
+ }
+ }
+ else if (fs==FST_NTFS)
+ slen=2048;
+ else
+ slen=512;
+
+ if (go_sect(hd,ssec))
+ {
+ print_apperr("Can\'t seek to the start sector");
+ close(hd);
+ return 1;
+ }
+
+ if (save_fn)
+ {
+ int h2;
+
+ h2=open(save_fn,O_CREAT | O_TRUNC | O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
+ if (h2==-1)
+ {
+ print_syserr("open save file");
+ close(hd);
+ return errno;
+ }
+ nn=write(h2,prev_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("write save file");
+ close(hd);
+ close(h2);
+ return errno;
+ }
+ if (nn<slen)
+ {
+ print_apperr("Can\'t write the whole MBR to the save file");
+ close(hd);
+ close(h2);
+ return 1;
+ }
+ close(h2);
+ }
+ if (afg & AFG_RESTORE_PREVMBR)
+ {
+ if (fs!=FST_MBR)
+ {
+ print_apperr("Not a disk image");
+ close(hd);
+ return 1;
+ }
+ if (memcmp(&prev_mbr[1024+3],"GRLDR",5))
+ {
+ print_apperr("GRLDR is not installed");
+ close(hd);
+ return 1;
+ }
+ if (get16(prev_mbr,512+510)!=0xAA55)
+ {
+ print_apperr("No previous saved MBR");
+ close(hd);
+ return 1;
+ }
+ memset(&grub_mbr,0,sizeof(grub_mbr));
+ memcpy(&grub_mbr,&prev_mbr[512],512);
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Restore previous MBR mode\n");
+ }
+ else
+ {
+ // Load MBR/BS from restore file or configure grub_mbr
+ if (restore_fn)
+ {
+ int h2;
+
+ h2=open(restore_fn,O_RDONLY | O_BINARY,S_IREAD);
+ if (h2==-1)
+ {
+ print_syserr("open restore file");
+ close(hd);
+ return errno;
+ }
+ nn=read(h2,grub_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("read restore file");
+ close(hd);
+ close(h2);
+ return errno;
+ }
+ if ((nn<512) || ((nn & 0x1FF)!=0) ||
+ ((fs!=FST_EXT2) && (get16(grub_mbr,510)!=0xAA55)))
+ {
+ print_apperr("Invalid restore file");
+ close(hd);
+ close(h2);
+ return 1;
+ }
+ close(h2);
+ if (nn<slen)
+ memset(&grub_mbr[nn],0,slen-nn);
+
+ //if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
+ if (fs!=FST_EXT2)
+ {
+ int new_fs;
+
+ new_fs=get_fstype(grub_mbr);
+ if (new_fs!=fs)
+ {
+ print_apperr("Invalid restore file");
+ close(hd);
+ return 1;
+ }
+ }
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Restore mode\n");
+ }
+ else
+ {
+ if (fs==FST_MBR)
+ {
+ if (! (afg & AFG_NO_BACKUP_MBR))
+ {
+ int i;
+
+ if (afg & AFG_FORCE_BACKUP_MBR)
+ i=512;
+ else
+ for (i=1;i<512;i++)
+ if (prev_mbr[512+i]!=prev_mbr[512])
+ break;
+
+ if ((i==512) && (! is_grldr_mbr(prev_mbr)))
+ memcpy(&grub_mbr[512],prev_mbr,512);
+ else
+ memcpy(&grub_mbr[512],&prev_mbr[512],512);
+ }
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+ }
+ else if (fs==FST_FAT16)
+ {
+ memcpy(grub_mbr,&grub_mbr[0x600],slen);
+ grub_mbr[0x41]=part_num;
+ }
+ else if (fs==FST_FAT32)
+ {
+ memcpy(grub_mbr,&grub_mbr[0x400],slen);
+ grub_mbr[0x5D]=part_num;
+ }
+ else if (fs==FST_NTFS)
+ {
+ memcpy(grub_mbr,&grub_mbr[0xA00],slen);
+ grub_mbr[0x57]=part_num;
+ }
+ else if (fs==FST_EXT2)
+ {
+ memcpy(&grub_mbr,&grub_mbr[0x800],slen);
+ grub_mbr[0x25]=part_num;
+ if (afg & AFG_LBA_MODE)
+ grub_mbr[2]=0x42;
+ else if (afg & AFG_CHS_MODE)
+ grub_mbr[2]=0x2;
+ if (def_spt!=-1)
+ set16(&grub_mbr,0x18,def_spt);
+ else if ((afg & AFG_IS_FLOPPY)==0)
+ set16(&grub_mbr,0x18,63);
+ if (def_hds!=-1)
+ set16(&grub_mbr,0x1A,def_hds);
+ else if ((afg & AFG_IS_FLOPPY)==0)
+ set16(&grub_mbr,0x1A,255);
+ if (def_tsc!=-1)
+ set32(&grub_mbr,0x20,def_tsc);
+ set32(&grub_mbr,0x1C,ssec);
+ // s_inode_size
+ if (prev_mbr[1024+0x4C]) // s_rev_level
+ set16(&grub_mbr,0x26,get16(&prev_mbr[1024],0x58));
+ else
+ set16(&grub_mbr,0x26,0x80);
+ // s_inodes_per_group
+ set32(&grub_mbr,0x28,get32(&prev_mbr[1024],0x28));
+ // s_first_data_block+1
+ set32(&grub_mbr,0x2C,get32(&prev_mbr[1024],0x14)+1);
+ }
+ else
+ {
+ // Shouldn't be here
+ print_apperr("Invalid file system");
+ close(hd);
+ return 1;
+ }
+ if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
+ {
+ if (afg & AFG_LBA_MODE)
+ grub_mbr[2]=0xe;
+ else if (afg & AFG_CHS_MODE)
+ grub_mbr[2]=0x90;
+ else
+ grub_mbr[2]=prev_mbr[2];
+ }
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Install mode\n");
+ }
+ // Patch the new MBR/BS with information from prev_mbr
+ if (fs==FST_MBR)
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+ else if (fs==FST_FAT16)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x3E - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ else if (fs==FST_FAT32)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x5A - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ else if (fs==FST_NTFS)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x54 - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ }
+ if (! (afg & AFG_READ_ONLY))
+ {
+ nn=write(hd,grub_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("write");
+ close(hd);
+ return errno;
+ }
+ if (nn<slen)
+ {
+ print_apperr("Can\'t write the whole mbr");
+ close(hd);
+ return 1;
+ }
+ }
+ else if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Read only mode\n");
+quit:
+ close(hd);
+ if (afg & AFG_PAUSE)
+ {
+ fputs("The MBR/BS has been successfully installed\n",stderr);
+ print_pause;
+ }
+ return 0;
+}
+
+int main(int argc,char** argv)
+{
+ int idx;
+
+ afg=gfg=0;
+ part_num=def_drive=def_part=def_spt=def_hds=def_ssc=def_tsc=-1;
+ afg=0;
+ gfg=GFG_PREVMBR_LAST;
+ time_out=5;
+ hot_key=0x3920;
+ save_fn=NULL;
+ restore_fn=NULL;
+ for (idx=1;idx<argc;idx++)
+ {
+ if (argv[idx][0]!='-')
+ break;
+ if ((! strcmp(argv[idx],"--help"))
+ || (! strcmp(argv[idx],"-h")))
+ {
+ help();
+ print_pause;
+ return 1;
+ }
+ else if (! strcmp(argv[idx],"--version"))
+ {
+ fprintf(stderr,"grubinst version : " VERSION "\n");
+ print_pause;
+ return 1;
+ }
+ else if ((! strcmp(argv[idx],"--verbose")) ||
+ (! strcmp(argv[idx],"-v")))
+ afg |=AFG_VERBOSE;
+ else if (! strcmp(argv[idx],"--pause"))
+ afg|=AFG_PAUSE;
+ else if ((! strcmp(argv[idx],"--read-only"))
+ || (! strcmp(argv[idx],"-t")))
+ afg|=AFG_READ_ONLY;
+ else if (! strcmp(argv[idx],"--no-backup-mbr"))
+ afg|=AFG_NO_BACKUP_MBR;
+ else if (! strcmp(argv[idx],"--force-backup-mbr"))
+ afg|=AFG_FORCE_BACKUP_MBR;
+ else if (! strcmp(argv[idx],"--mbr-enable-floppy"))
+ gfg&=~GFG_DISABLE_FLOPPY;
+ else if (! strcmp(argv[idx],"--mbr-disable-floppy"))
+ gfg|=GFG_DISABLE_FLOPPY;
+ else if (! strcmp(argv[idx],"--mbr-enable-osbr"))
+ gfg&=~GFG_DISABLE_OSBR;
+ else if (! strcmp(argv[idx],"--mbr-disable-osbr"))
+ gfg|=GFG_DISABLE_OSBR;
+ else if (! strcmp(argv[idx],"--duce"))
+ gfg|=GFG_DUCE;
+ else if (! strcmp(argv[idx],"--boot-prevmbr-first"))
+ gfg&=~GFG_PREVMBR_LAST;
+ else if (! strcmp(argv[idx],"--boot-prevmbr-last"))
+ gfg|=GFG_PREVMBR_LAST;
+ else if (! strncmp(argv[idx],"--preferred-drive=",18))
+ {
+ def_drive=strtol(&argv[idx][18],NULL,0);
+ if ((def_drive<0) || (def_drive>=255))
+ {
+ print_apperr("Invalid preferred drive number");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--preferred-partition=",22))
+ {
+ def_part=strtol(&argv[idx][22],NULL,0);
+ if ((def_part<0) || (def_part>=255))
+ {
+ print_apperr("Invalid preferred partition number");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--time-out=",11)) ||
+ (! strncmp(argv[idx],"-t=",3)))
+ {
+ time_out=strtol((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][11],NULL,0);
+ if ((time_out<0) || (time_out>255))
+ {
+ print_apperr("Invalid timeout value");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--key-name=",11)))
+ {
+ key_name=&argv[idx][11];
+ if (strlen(key_name)>13)
+ {
+ print_apperr("Key name too long");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--restore-prevmbr")) ||
+ (! strcmp(argv[idx],"-r")))
+ afg|=AFG_RESTORE_PREVMBR;
+ else if ((! strncmp(argv[idx],"--save=",7)) ||
+ (! strncmp(argv[idx],"-s=",3)))
+ {
+ save_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][7];
+ if (*save_fn==0)
+ {
+ print_apperr("Empty filename");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--restore=",10)) ||
+ (! strncmp(argv[idx],"-r=",3)))
+ {
+ restore_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][10];
+ if (*restore_fn==0)
+ {
+ print_apperr("Empty filename");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--list-part")) ||
+ (! strcmp(argv[idx],"-l")))
+ afg|=AFG_LIST_PART;
+ else if ((! strcmp(argv[idx],"--floppy")) ||
+ (! strcmp(argv[idx],"-f")))
+ afg|=AFG_IS_FLOPPY;
+ else if ((! strncmp(argv[idx],"--floppy=",9)) ||
+ (! strncmp(argv[idx],"--install-partition=",20)) ||
+ (! strncmp(argv[idx],"-p=",3)))
+ {
+ char *p;
+
+ if (argv[idx][2]=='f')
+ p=&argv[idx][9];
+ else if (argv[idx][2]=='i')
+ p=&argv[idx][20];
+ else
+ p=&argv[idx][3];
+ part_num=strtoul(p,NULL,0);
+ if ((part_num<0) || (part_num>=MAX_PARTS))
+ {
+ print_apperr("Invalid partition number");
+ return 1;
+ }
+ }
+ else if (! strcmp(argv[idx],"--lba"))
+ afg|=AFG_LBA_MODE;
+ else if (! strcmp(argv[idx],"--chs"))
+ afg|=AFG_CHS_MODE;
+ else if (! strncmp(argv[idx],"--sectors-per-track=",20))
+ {
+ def_spt=strtol(&argv[idx][10],NULL,0);
+ if ((def_spt<1) || (def_spt>63))
+ {
+ print_apperr("Invalid sector per track");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--heads=",8))
+ {
+ def_hds=strtol(&argv[idx][8],NULL,0);
+ if ((def_hds<1) || (def_hds>255))
+ {
+ print_apperr("Invalid number of heads");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--start-sector=",15))
+ {
+ def_spt=strtol(&argv[idx][15],NULL,0);
+ if (def_ssc<0)
+ {
+ print_apperr("Invalid start sector");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--total-sectors=",16))
+ {
+ def_tsc=strtol(&argv[idx][16],NULL,0);
+ if (def_tsc<0)
+ {
+ print_apperr("Invalid total sectors");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--boot-file=",12)) ||
+ (! strncmp(argv[idx],"-b=",3)))
+ {
+ if (SetBootFile((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][12]))
+ {
+ print_apperr("Invalid boot file name");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--load-seg=",11))
+ {
+ load_seg=strtoul(&argv[idx][11],NULL,16);
+ if (load_seg<0x1000)
+ {
+ print_apperr("Load address too small");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--grub2")) ||
+ (! strcmp(argv[idx],"-2")))
+ {
+ if (! boot_file)
+ {
+ boot_file="g2ldr";
+ strcpy(boot_file_83,"G2LDR ");
+ }
+ }
+ else if ((! strcmp(argv[idx],"--output")) ||
+ (! strcmp(argv[idx],"-o")))
+ afg|=AFG_OUTPUT;
+ else if ((! strcmp(argv[idx],"--edit")) ||
+ (! strcmp(argv[idx],"-e")))
+ afg|=AFG_EDIT;
+ else
+ {
+ print_apperr("Invalid option, please use --help to see all valid options");
+ return 1;
+ }
+ }
+ if (idx>=argc)
+ {
+ print_apperr("No filename specified");
+ return 1;
+ }
+ if (idx<argc-1)
+ {
+ print_apperr("Extra parameters");
+ return 1;
+ }
+ return install(parse_fname(argv[idx]));
+}