9 int soi_s2n(char *ptr, unsigned int *seg,
14 unsigned int segval = 0, offval, ipval, val;
20 segval = strtoul(ptr, &p, 0);
21 if (p[0] == ':' && p[1] && p[1] != ':')
22 offval = strtoul(p+1, &p, 0);
23 if (p[0] == ':' && p[1] && p[1] != ':')
24 ipval = strtoul(p+1, NULL, 0);
26 val = (segval << 4) + offval;
28 if (val < ADDRMIN || val > ADDRMAX) {
29 error("Invalid seg:off:* address specified..\n");
33 val = (segval << 4) + ipval;
35 if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
36 error("Invalid seg:*:ip address specified.\n");
55 static const char key[] = "Press any key...\n";
56 static const char *const usage[] = {
59 chain.c32 [options]\n\
60 chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
61 chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
62 chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
63 chain.c32 label{:|=}<label> [<part#>] [options]\n\
64 chain.c32 boot{,| }[<part#>] [options]\n\
65 chain.c32 fs [options]\n\
67 \nOptions ('no' prefix specifies default value):\n\
68 sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
69 - defaults to 0:0x7C00:0x7C00\n\
70 - ommited o/i values default to 0x7C00\n\
71 maps Map loaded sector into real memory\n\
72 nosetbpb Fix BPB fields in loaded sector\n\
73 nofilebpb Apply 'setbpb' to loaded file\n\
74 nosave Write adjusted sector back to disk\n\
75 hand Prepare handover area\n\
76 nohptr Force ds:si and ds:bp to point to handover area\n\
77 noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
78 nohide Disable all hide variations (also the default)\n\
79 hide Hide primary partitions, unhide selected partition\n\
80 hideall Hide *all* partitions, unhide selected partition\n\
81 unhide Unhide primary partitions\n\
82 unhideall Unhide *all* partitions\n\
83 nombrchs Walk *all* partitions and fix E/MBRs' chs values\n\
84 nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
85 nowarn Wait for a keypress to continue chainloading\n\
86 - useful to see emited warnings\n\
87 chain Actually perform the chainloading\n\
89 \nOptions continued ...\n\
90 file=<file> Load and execute <file>\n\
91 seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
92 - defaults to 0:0x7C00:0x7C00\n\
93 - ommited o/i values default to 0\n\
94 isolinux=<loader> Load another version of ISOLINUX\n\
95 ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
96 cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
97 freedos=<loader> Load FreeDOS KERNEL.SYS\n\
98 msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
99 msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
100 pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
101 drmk=<loader> Load DRMK DELLBIO.BIN\n\
102 grub=<loader> Load GRUB Legacy stage2\n\
103 grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
104 grldr=<loader> Load GRUB4DOS grldr\n\
105 bss=<filename> Emulate syslinux's BSS\n\
106 bs=<filename> Emulate syslinux's BS\n\
107 \nPlease see doc/chain.txt for the detailed documentation.\n\
110 for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
119 int parse_args(int argc, char *argv[])
125 for (i = 1; i < argc; i++) {
126 if (!strncmp(argv[i], "file=", 5)) {
127 opt.file = argv[i] + 5;
128 } else if (!strcmp(argv[i], "nofile")) {
130 } else if (!strncmp(argv[i], "seg=", 4)) {
131 if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
133 } else if (!strncmp(argv[i], "bss=", 4)) {
134 opt.file = argv[i] + 4;
138 /* opt.save = true; */
139 } else if (!strncmp(argv[i], "bs=", 3)) {
140 opt.file = argv[i] + 3;
143 } else if (!strncmp(argv[i], "isolinux=", 9)) {
144 opt.file = argv[i] + 9;
148 } else if (!strncmp(argv[i], "ntldr=", 6)) {
149 opt.fseg = 0x2000; /* NTLDR wants this address */
152 opt.file = argv[i] + 6;
154 /* opt.save = true; */
156 } else if (!strncmp(argv[i], "cmldr=", 6)) {
157 opt.fseg = 0x2000; /* CMLDR wants this address */
160 opt.file = argv[i] + 6;
163 /* opt.save = true; */
165 } else if (!strncmp(argv[i], "freedos=", 8)) {
166 opt.fseg = 0x60; /* FREEDOS wants this address */
170 opt.file = argv[i] + 8;
172 /* opt.save = true; */
174 } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
175 !strncmp(argv[i], "pcdos=", v)) ||
176 (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
177 opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
179 opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
181 opt.file = argv[i] + v;
183 /* opt.save = true; */
185 } else if (!strncmp(argv[i], "drmk=", 5)) {
186 opt.fseg = 0x70; /* DRMK wants this address */
192 opt.file = argv[i] + 5;
193 /* opt.drmk = true; */
195 /* opt.save = true; */
197 } else if (!strncmp(argv[i], "grub=", 5)) {
198 opt.fseg = 0x800; /* stage2 wants this address */
201 opt.file = argv[i] + 5;
205 } else if (!strncmp(argv[i], "grubcfg=", 8)) {
206 opt.grubcfg = argv[i] + 8;
207 } else if (!strncmp(argv[i], "grldr=", 6)) {
208 opt.file = argv[i] + 6;
212 } else if (!strcmp(argv[i], "keeppxe")) {
214 } else if (!strcmp(argv[i], "nokeeppxe")) {
216 } else if (!strcmp(argv[i], "maps")) {
218 } else if (!strcmp(argv[i], "nomaps")) {
220 } else if (!strcmp(argv[i], "hand")) {
222 } else if (!strcmp(argv[i], "nohand")) {
224 } else if (!strcmp(argv[i], "hptr")) {
226 } else if (!strcmp(argv[i], "nohptr")) {
228 } else if (!strcmp(argv[i], "swap")) {
230 } else if (!strcmp(argv[i], "noswap")) {
232 } else if (!strcmp(argv[i], "nohide")) {
234 } else if (!strcmp(argv[i], "hide")) {
235 opt.hide = 1; /* 001b */
236 } else if (!strcmp(argv[i], "hideall")) {
237 opt.hide = 2; /* 010b */
238 } else if (!strcmp(argv[i], "unhide")) {
239 opt.hide = 5; /* 101b */
240 } else if (!strcmp(argv[i], "unhideall")) {
241 opt.hide = 6; /* 110b */
242 } else if (!strcmp(argv[i], "setbpb")) {
244 } else if (!strcmp(argv[i], "nosetbpb")) {
246 } else if (!strcmp(argv[i], "filebpb")) {
248 } else if (!strcmp(argv[i], "nofilebpb")) {
250 } else if (!strncmp(argv[i], "sect=", 5) ||
251 !strcmp(argv[i], "sect")) {
253 if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0x7c00))
255 if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
256 error("Arguments of 'sect=' are invalid - resulting address too big.\n");
261 } else if (!strcmp(argv[i], "nosect")) {
263 } else if (!strcmp(argv[i], "save")) {
265 } else if (!strcmp(argv[i], "nosave")) {
267 } else if (!strcmp(argv[i], "mbrchs")) {
269 } else if (!strcmp(argv[i], "nombrchs")) {
271 } else if (!strcmp(argv[i], "warn")) {
273 } else if (!strcmp(argv[i], "nowarn")) {
275 } else if (!strcmp(argv[i], "chain")) {
277 } else if (!strcmp(argv[i], "nochain")) {
282 } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
283 && argv[i][1] == 'd')
284 || !strncmp(argv[i], "mbr:", 4)
285 || !strncmp(argv[i], "mbr=", 4)
286 || !strncmp(argv[i], "guid:", 5)
287 || !strncmp(argv[i], "guid=", 5)
288 || !strncmp(argv[i], "label:", 6)
289 || !strncmp(argv[i], "label=", 6)
290 || !strcmp(argv[i], "boot")
291 || !strncmp(argv[i], "boot,", 5)
292 || !strcmp(argv[i], "fs")) {
293 opt.drivename = argv[i];
294 if (strncmp(argv[i], "label", 5))
295 p = strchr(opt.drivename, ',');
300 opt.partition = p + 1;
301 } else if (argv[i + 1] && argv[i + 1][0] >= '0'
302 && argv[i + 1][0] <= '9') {
303 opt.partition = argv[++i];
311 if (opt.grubcfg && !opt.grub) {
312 error("grubcfg=<filename> must be used together with grub=<loader>.\n");
317 if ((!opt.maps || !opt.sect) && !opt.file) {
318 error("You have to load something.\n");
323 if (opt.filebpb && !opt.file) {
324 error("Option 'filebpb' requires a file.\n");
328 if (opt.save && !opt.sect) {
329 error("Option 'save' requires a sector.\n");
333 if (opt.setbpb && !opt.sect) {
334 error("Option 'setbpb' requires a sector.\n");
343 /* vim: set ts=8 sts=4 sw=4 noet: */