9 int soi_s2n(char *ptr
, unsigned int *seg
,
13 unsigned int segval
= 0, offval
= 0, ipval
= 0, val
;
16 segval
= strtoul(ptr
, &p
, 0);
18 offval
= strtoul(p
+1, &p
, 0);
20 ipval
= strtoul(p
+1, NULL
, 0);
22 val
= (segval
<< 4) + offval
;
24 if (val
< ADDRMIN
|| val
> ADDRMAX
) {
25 error("Invalid seg:off:* address specified..\n");
29 val
= (segval
<< 4) + ipval
;
31 if (ipval
> 0xFFFE || val
< ADDRMIN
|| val
> ADDRMAX
) {
32 error("Invalid seg:*:ip address specified.\n");
50 static const char *const usage
[] = { "\
52 chain.c32 [options]\n\
53 chain.c32 {fd|hd}<disk> [<partition>] [options]\n\
54 chain.c32 mbr{:|=}<id> [<partition>] [options]\n\
55 chain.c32 guid{:|=}<guid> [<partition>] [options]\n\
56 chain.c32 label{:|=}<label> [<partition>] [options]\n\
57 chain.c32 boot{,| }[<partition>] [options]\n\
58 chain.c32 fs [options]\n\
59 \nOptions ('no' prefix specify defaulti value):\n\
60 file=<loader> Load and execute file\n\
61 seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
62 nofilebpb Treat file in memory as BPB compatible\n\
63 sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
64 - defaults to 0:0x7C00:0x7C00\n\
65 maps Map loaded sector into real memory\n\
66 nosethid[den] Set BPB's hidden sectors field\n\
67 nosetgeo Set BPB's sectors per track and heads fields\n\
68 nosetdrv[@<off>] Set BPB's drive unit field at <o>\n\
69 - <off> defaults to autodetection\n\
70 - only 0x24 and 0x40 are accepted\n\
71 nosetbpb Enable set{hid,geo,drv}\n\
72 nosave Write adjusted sector back to disk\n\
73 hand Prepare handover area\n\
74 nohptr Force ds:si and ds:bp to point to handover area\n\
75 noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
76 nohide Hide primary partitions, unhide selected partition\n\
77 nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
78 nowarn Wait for a keypress to continue chainloading\n\
79 - useful to see emited warnings\n\
81 \nComposite options:\n\
82 isolinux=<loader> Load another version of ISOLINUX\n\
83 ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
84 cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
85 freedos=<loader> Load FreeDOS KERNEL.SYS\n\
86 msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
87 msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
88 pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
89 drmk=<loader> Load DRMK DELLBIO.BIN\n\
90 grub=<loader> Load GRUB Legacy stage2\n\
91 grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
92 grldr=<loader> Load GRUB4DOS grldr\n\
93 \nPlease see doc/chain.txt for the detailed documentation.\n"
96 error("Press any key...\n");
101 int parse_args(int argc
, char *argv
[])
107 for (i
= 1; i
< argc
; i
++) {
108 if (!strncmp(argv
[i
], "file=", 5)) {
109 opt
.file
= argv
[i
] + 5;
110 } else if (!strcmp(argv
[i
], "nofile")) {
112 } else if (!strncmp(argv
[i
], "seg=", 4)) {
113 if (soi_s2n(argv
[i
] + 4, &opt
.fseg
, &opt
.foff
, &opt
.fip
))
115 } else if (!strncmp(argv
[i
], "isolinux=", 9)) {
116 opt
.file
= argv
[i
] + 9;
120 } else if (!strncmp(argv
[i
], "ntldr=", 6)) {
121 opt
.fseg
= 0x2000; /* NTLDR wants this address */
124 opt
.file
= argv
[i
] + 6;
129 /* opt.save = true; */
131 } else if (!strncmp(argv
[i
], "cmldr=", 6)) {
132 opt
.fseg
= 0x2000; /* CMLDR wants this address */
135 opt
.file
= argv
[i
] + 6;
141 /* opt.save = true; */
143 } else if (!strncmp(argv
[i
], "freedos=", 8)) {
144 opt
.fseg
= 0x60; /* FREEDOS wants this address */
150 opt
.file
= argv
[i
] + 8;
155 /* opt.save = true; */
157 } else if ( (v
= 6, !strncmp(argv
[i
], "msdos=", v
) ||
158 !strncmp(argv
[i
], "pcdos=", v
)) ||
159 (v
= 7, !strncmp(argv
[i
], "msdos7=", v
)) ) {
160 opt
.fseg
= 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
162 opt
.fip
= v
== 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
166 opt
.file
= argv
[i
] + v
;
171 /* opt.save = true; */
173 } else if (!strncmp(argv
[i
], "drmk=", 5)) {
174 opt
.fseg
= 0x70; /* DRMK wants this address */
180 opt
.file
= argv
[i
] + 5;
181 /* opt.drmk = true; */
186 /* opt.save = true; */
188 } else if (!strncmp(argv
[i
], "grub=", 5)) {
189 opt
.fseg
= 0x800; /* stage2 wants this address */
192 opt
.file
= argv
[i
] + 5;
196 } else if (!strncmp(argv
[i
], "grubcfg=", 8)) {
197 opt
.grubcfg
= argv
[i
] + 8;
198 } else if (!strncmp(argv
[i
], "grldr=", 6)) {
199 opt
.file
= argv
[i
] + 6;
203 } else if (!strcmp(argv
[i
], "keeppxe")) {
205 } else if (!strcmp(argv
[i
], "nokeeppxe")) {
207 } else if (!strcmp(argv
[i
], "maps")) {
209 } else if (!strcmp(argv
[i
], "nomaps")) {
211 } else if (!strcmp(argv
[i
], "hand")) {
213 } else if (!strcmp(argv
[i
], "nohand")) {
215 } else if (!strcmp(argv
[i
], "hptr")) {
217 } else if (!strcmp(argv
[i
], "nohptr")) {
219 } else if (!strcmp(argv
[i
], "swap")) {
221 } else if (!strcmp(argv
[i
], "noswap")) {
223 } else if (!strcmp(argv
[i
], "hide")) {
225 } else if (!strcmp(argv
[i
], "nohide")) {
227 } else if (!strcmp(argv
[i
], "sethid") ||
228 !strcmp(argv
[i
], "sethidden")) {
230 } else if (!strcmp(argv
[i
], "nosethid") ||
231 !strcmp(argv
[i
], "nosethidden")) {
233 } else if (!strcmp(argv
[i
], "setgeo")) {
235 } else if (!strcmp(argv
[i
], "nosetgeo")) {
237 } else if (!strncmp(argv
[i
], "setdrv",6)) {
239 v
= ~0u; /* autodetect */
240 else if (argv
[i
][6] == '@' ||
243 v
= strtoul(argv
[i
] + 7, NULL
, 0);
244 if (!(v
== 0x24 || v
== 0x40)) {
245 error("Invalid 'setdrv' offset.\n");
249 error("Invalid 'setdrv' specification.\n");
254 } else if (!strcmp(argv
[i
], "nosetdrv")) {
256 } else if (!strcmp(argv
[i
], "setbpb")) {
261 } else if (!strcmp(argv
[i
], "nosetbpb")) {
265 } else if (!strncmp(argv
[i
], "sect=", 5) ||
266 !strcmp(argv
[i
], "sect")) {
268 if (soi_s2n(argv
[i
] + 5, &opt
.sseg
, &opt
.soff
, &opt
.sip
))
270 if ((opt
.sseg
<< 4) + opt
.soff
+ SECTOR
- 1 > ADDRMAX
) {
271 error("Arguments of 'sect=' are invalid - resulting address too big.\n");
276 } else if (!strcmp(argv
[i
], "nosect")) {
278 } else if (!strcmp(argv
[i
], "save")) {
280 } else if (!strcmp(argv
[i
], "nosave")) {
282 } else if (!strcmp(argv
[i
], "filebpb")) {
284 } else if (!strcmp(argv
[i
], "nofilebpb")) {
286 } else if (!strcmp(argv
[i
], "warn")) {
288 } else if (!strcmp(argv
[i
], "nowarn")) {
290 } else if (((argv
[i
][0] == 'h' || argv
[i
][0] == 'f')
291 && argv
[i
][1] == 'd')
292 || !strncmp(argv
[i
], "mbr:", 4)
293 || !strncmp(argv
[i
], "mbr=", 4)
294 || !strncmp(argv
[i
], "guid:", 5)
295 || !strncmp(argv
[i
], "guid=", 5)
296 || !strncmp(argv
[i
], "label:", 6)
297 || !strncmp(argv
[i
], "label=", 6)
298 || !strcmp(argv
[i
], "boot")
299 || !strncmp(argv
[i
], "boot,", 5)
300 || !strcmp(argv
[i
], "fs")) {
301 opt
.drivename
= argv
[i
];
302 p
= strchr(opt
.drivename
, ',');
305 opt
.partition
= p
+ 1;
306 } else if (argv
[i
+ 1] && argv
[i
+ 1][0] >= '0'
307 && argv
[i
+ 1][0] <= '9') {
308 opt
.partition
= argv
[++i
];
316 if (opt
.grubcfg
&& !opt
.grub
) {
317 error("grubcfg=<filename> must be used together with grub=<loader>.\n");
321 if ((!opt
.maps
|| !opt
.sect
) && !opt
.file
) {
322 error("You have to load something.\n");
326 if (opt
.filebpb
&& !opt
.file
) {
327 error("Option 'filebpb' requires file.\n");
336 /* vim: set ts=8 sts=4 sw=4 noet: */