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 #1 ('no' prefix specifies default value):\n\
68 file=<file> Load and execute <file>\n\
69 seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
70 - defaults to 0:0x7C00:0x7C00\n\
71 - ommited o/i values default to 0\n\
72 sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
73 - defaults to 0:0x7C00:0x7C00\n\
74 - ommited o/i values default to 0x7C00\n\
75 maps Map loaded sector into real memory\n\
76 nosetbpb Fix BPB fields in loaded sector\n\
77 nofilebpb Apply 'setbpb' to loaded file\n\
78 nosave Write adjusted sector back to disk\n\
79 hand Prepare handover area\n\
80 nohptr Force ds:si and ds:bp to point to handover area\n\
81 bss=<filename> Emulate syslinux's BSS\n\
82 bs=<filename> Emulate syslinux's BS\n\
83 noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
84 nohide Hide primary partitions, unhide selected partition\n\
85 nohideall Hide *all* partitions, unhide selected partition\n\
86 nombrchs Walk *all* partitions and fix E/MBRs' chs values\n\
87 nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
88 nowarn Wait for a keypress to continue chainloading\n\
89 - useful to see emited warnings\n\
91 \nOptions #3 ('no' prefix specifies default value):\n\
92 isolinux=<loader> Load another version of ISOLINUX\n\
93 ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
94 cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
95 freedos=<loader> Load FreeDOS KERNEL.SYS\n\
96 msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
97 msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
98 pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
99 drmk=<loader> Load DRMK DELLBIO.BIN\n\
100 grub=<loader> Load GRUB Legacy stage2\n\
101 grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
102 grldr=<loader> Load GRUB4DOS grldr\n\
103 \nPlease see doc/chain.txt for the detailed documentation.\n\
106 for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
115 int parse_args(int argc, char *argv[])
121 for (i = 1; i < argc; i++) {
122 if (!strncmp(argv[i], "file=", 5)) {
123 opt.file = argv[i] + 5;
124 } else if (!strcmp(argv[i], "nofile")) {
126 } else if (!strncmp(argv[i], "seg=", 4)) {
127 if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
129 } else if (!strncmp(argv[i], "bss=", 4)) {
130 opt.file = argv[i] + 4;
134 /* opt.save = true; */
135 } else if (!strncmp(argv[i], "bs=", 3)) {
136 opt.file = argv[i] + 3;
139 } else if (!strncmp(argv[i], "isolinux=", 9)) {
140 opt.file = argv[i] + 9;
144 } else if (!strncmp(argv[i], "ntldr=", 6)) {
145 opt.fseg = 0x2000; /* NTLDR wants this address */
148 opt.file = argv[i] + 6;
150 /* opt.save = true; */
152 } else if (!strncmp(argv[i], "cmldr=", 6)) {
153 opt.fseg = 0x2000; /* CMLDR wants this address */
156 opt.file = argv[i] + 6;
159 /* opt.save = true; */
161 } else if (!strncmp(argv[i], "freedos=", 8)) {
162 opt.fseg = 0x60; /* FREEDOS wants this address */
166 opt.file = argv[i] + 8;
168 /* opt.save = true; */
170 } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
171 !strncmp(argv[i], "pcdos=", v)) ||
172 (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
173 opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
175 opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
177 opt.file = argv[i] + v;
179 /* opt.save = true; */
181 } else if (!strncmp(argv[i], "drmk=", 5)) {
182 opt.fseg = 0x70; /* DRMK wants this address */
188 opt.file = argv[i] + 5;
189 /* opt.drmk = true; */
191 /* opt.save = true; */
193 } else if (!strncmp(argv[i], "grub=", 5)) {
194 opt.fseg = 0x800; /* stage2 wants this address */
197 opt.file = argv[i] + 5;
201 } else if (!strncmp(argv[i], "grubcfg=", 8)) {
202 opt.grubcfg = argv[i] + 8;
203 } else if (!strncmp(argv[i], "grldr=", 6)) {
204 opt.file = argv[i] + 6;
208 } else if (!strcmp(argv[i], "keeppxe")) {
210 } else if (!strcmp(argv[i], "nokeeppxe")) {
212 } else if (!strcmp(argv[i], "maps")) {
214 } else if (!strcmp(argv[i], "nomaps")) {
216 } else if (!strcmp(argv[i], "hand")) {
218 } else if (!strcmp(argv[i], "nohand")) {
220 } else if (!strcmp(argv[i], "hptr")) {
222 } else if (!strcmp(argv[i], "nohptr")) {
224 } else if (!strcmp(argv[i], "swap")) {
226 } else if (!strcmp(argv[i], "noswap")) {
228 } else if (!strcmp(argv[i], "nohide") ||
229 !strcmp(argv[i], "nohideall")) {
231 } else if (!strcmp(argv[i], "hide")) {
233 } else if (!strcmp(argv[i], "hideall")) {
235 } else if (!strcmp(argv[i], "setbpb")) {
237 } else if (!strcmp(argv[i], "nosetbpb")) {
239 } else if (!strcmp(argv[i], "filebpb")) {
241 } else if (!strcmp(argv[i], "nofilebpb")) {
243 } else if (!strncmp(argv[i], "sect=", 5) ||
244 !strcmp(argv[i], "sect")) {
246 if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0x7c00))
248 if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
249 error("Arguments of 'sect=' are invalid - resulting address too big.\n");
254 } else if (!strcmp(argv[i], "nosect")) {
256 } else if (!strcmp(argv[i], "save")) {
258 } else if (!strcmp(argv[i], "nosave")) {
260 } else if (!strcmp(argv[i], "mbrchs")) {
262 } else if (!strcmp(argv[i], "nombrchs")) {
264 } else if (!strcmp(argv[i], "warn")) {
266 } else if (!strcmp(argv[i], "nowarn")) {
268 } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
269 && argv[i][1] == 'd')
270 || !strncmp(argv[i], "mbr:", 4)
271 || !strncmp(argv[i], "mbr=", 4)
272 || !strncmp(argv[i], "guid:", 5)
273 || !strncmp(argv[i], "guid=", 5)
274 || !strncmp(argv[i], "label:", 6)
275 || !strncmp(argv[i], "label=", 6)
276 || !strcmp(argv[i], "boot")
277 || !strncmp(argv[i], "boot,", 5)
278 || !strcmp(argv[i], "fs")) {
279 opt.drivename = argv[i];
280 if (strncmp(argv[i], "label", 5)) {
281 p = strchr(opt.drivename, ',');
284 opt.partition = p + 1;
285 } else if (argv[i + 1] && argv[i + 1][0] >= '0'
286 && argv[i + 1][0] <= '9') {
287 opt.partition = argv[++i];
296 if (opt.grubcfg && !opt.grub) {
297 error("grubcfg=<filename> must be used together with grub=<loader>.\n");
301 if ((!opt.maps || !opt.sect) && !opt.file) {
302 error("You have to load something.\n");
306 if (opt.filebpb && !opt.file) {
307 error("Option 'filebpb' requires a file.\n");
311 if (opt.save && !opt.sect) {
312 error("Option 'save' requires a sector.\n");
316 if (opt.setbpb && !opt.sect) {
317 error("Option 'setbpb' requires a sector.\n");
326 /* vim: set ts=8 sts=4 sw=4 noet: */