chain module: setbpb changes, bss & bs options, bugfixes
[profile/ivi/syslinux.git] / com32 / chain / options.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "common.h"
5 #include "chain.h"
6 #include "utility.h"
7 #include "options.h"
8
9 int soi_s2n(char *ptr, unsigned int *seg,
10                        unsigned int *off,
11                        unsigned int *ip,
12                        unsigned int def)
13 {
14     unsigned int segval = 0, offval, ipval, val;
15     char *p;
16
17     offval = def;
18     ipval = def;
19
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);
25
26     val = (segval << 4) + offval;
27
28     if (val < ADDRMIN || val > ADDRMAX) {
29         error("Invalid seg:off:* address specified..\n");
30         goto bail;
31     }
32
33     val = (segval << 4) + ipval;
34
35     if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
36         error("Invalid seg:*:ip address specified.\n");
37         goto bail;
38     }
39
40     if (seg)
41         *seg = segval;
42     if (off)
43         *off = offval;
44     if (ip)
45         *ip  = ipval;
46
47     return 0;
48 bail:
49     return -1;
50 }
51
52 void usage(void)
53 {
54     unsigned int i;
55     static const char key[] = "Press any key...\n";
56     static const char *const usage[] = {
57 "\
58 Usage:\n\
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\
66 ", "\
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\
90 ", "\
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\
104 "
105     };
106     for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
107         if (i) {
108             error(key);
109             wait_key();
110         }
111         error(usage[i]);
112     }
113 }
114
115 int parse_args(int argc, char *argv[])
116 {
117     int i;
118     unsigned int v;
119     char *p;
120
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")) {
125             opt.file = NULL;
126         } else if (!strncmp(argv[i], "seg=", 4)) {
127             if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
128                 goto bail;
129         } else if (!strncmp(argv[i], "bss=", 4)) {
130             opt.file = argv[i] + 4;
131             opt.bss = true;
132             opt.maps = false;
133             opt.setbpb = true;
134             /* opt.save = true; */
135         } else if (!strncmp(argv[i], "bs=", 3)) {
136             opt.file = argv[i] + 3;
137             opt.sect = false;
138             opt.filebpb = true;
139         } else if (!strncmp(argv[i], "isolinux=", 9)) {
140             opt.file = argv[i] + 9;
141             opt.isolinux = true;
142             opt.hand = false;
143             opt.sect = false;
144         } else if (!strncmp(argv[i], "ntldr=", 6)) {
145             opt.fseg = 0x2000;  /* NTLDR wants this address */
146             opt.foff = 0;
147             opt.fip = 0;
148             opt.file = argv[i] + 6;
149             opt.setbpb = true;
150             /* opt.save = true; */
151             opt.hand = false;
152         } else if (!strncmp(argv[i], "cmldr=", 6)) {
153             opt.fseg = 0x2000;  /* CMLDR wants this address */
154             opt.foff = 0;
155             opt.fip = 0;
156             opt.file = argv[i] + 6;
157             opt.cmldr = true;
158             opt.setbpb = true;
159             /* opt.save = true; */
160             opt.hand = false;
161         } else if (!strncmp(argv[i], "freedos=", 8)) {
162             opt.fseg = 0x60;    /* FREEDOS wants this address */
163             opt.foff = 0;
164             opt.fip = 0;
165             opt.sseg = 0x1FE0;
166             opt.file = argv[i] + 8;
167             opt.setbpb = true;
168             /* opt.save = true; */
169             opt.hand = false;
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 */
174             opt.foff = 0;
175             opt.fip = v == 7 ? 0x200 : 0;  /* MS-DOS 7.0+ wants this ip */
176             opt.sseg = 0x8000;
177             opt.file = argv[i] + v;
178             opt.setbpb = true;
179             /* opt.save = true; */
180             opt.hand = false;
181         } else if (!strncmp(argv[i], "drmk=", 5)) {
182             opt.fseg = 0x70;    /* DRMK wants this address */
183             opt.foff = 0;
184             opt.fip = 0;
185             opt.sseg = 0x2000;
186             opt.soff = 0;
187             opt.sip = 0;
188             opt.file = argv[i] + 5;
189             /* opt.drmk = true; */
190             opt.setbpb = true;
191             /* opt.save = true; */
192             opt.hand = false;
193         } else if (!strncmp(argv[i], "grub=", 5)) {
194             opt.fseg = 0x800;   /* stage2 wants this address */
195             opt.foff = 0;
196             opt.fip = 0x200;
197             opt.file = argv[i] + 5;
198             opt.grub = true;
199             opt.hand = false;
200             opt.sect = false;
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;
205             opt.grldr = true;
206             opt.hand = false;
207             opt.sect = false;
208         } else if (!strcmp(argv[i], "keeppxe")) {
209             opt.keeppxe = 3;
210         } else if (!strcmp(argv[i], "nokeeppxe")) {
211             opt.keeppxe = 0;
212         } else if (!strcmp(argv[i], "maps")) {
213             opt.maps = true;
214         } else if (!strcmp(argv[i], "nomaps")) {
215             opt.maps = false;
216         } else if (!strcmp(argv[i], "hand")) {
217             opt.hand = true;
218         } else if (!strcmp(argv[i], "nohand")) {
219             opt.hand = false;
220         } else if (!strcmp(argv[i], "hptr")) {
221             opt.hptr = true;
222         } else if (!strcmp(argv[i], "nohptr")) {
223             opt.hptr = false;
224         } else if (!strcmp(argv[i], "swap")) {
225             opt.swap = true;
226         } else if (!strcmp(argv[i], "noswap")) {
227             opt.swap = false;
228         } else if (!strcmp(argv[i], "nohide") ||
229                     !strcmp(argv[i], "nohideall")) {
230             opt.hide = 0;
231         } else if (!strcmp(argv[i], "hide")) {
232             opt.hide = 1;
233         } else if (!strcmp(argv[i], "hideall")) {
234             opt.hide = 2;
235         } else if (!strcmp(argv[i], "setbpb")) {
236             opt.setbpb = true;
237         } else if (!strcmp(argv[i], "nosetbpb")) {
238             opt.setbpb = false;
239         } else if (!strcmp(argv[i], "filebpb")) {
240             opt.filebpb = true;
241         } else if (!strcmp(argv[i], "nofilebpb")) {
242             opt.filebpb = false;
243         } else if (!strncmp(argv[i], "sect=", 5) ||
244                    !strcmp(argv[i], "sect")) {
245             if (argv[i][4]) {
246                 if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0x7c00))
247                     goto bail;
248                 if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
249                     error("Arguments of 'sect=' are invalid - resulting address too big.\n");
250                     goto bail;
251                 }
252             }
253             opt.sect = true;
254         } else if (!strcmp(argv[i], "nosect")) {
255             opt.sect = false;
256         } else if (!strcmp(argv[i], "save")) {
257             opt.save = true;
258         } else if (!strcmp(argv[i], "nosave")) {
259             opt.save = false;
260         } else if (!strcmp(argv[i], "mbrchs")) {
261             opt.mbrchs = true;
262         } else if (!strcmp(argv[i], "nombrchs")) {
263             opt.mbrchs = false;
264         } else if (!strcmp(argv[i], "warn")) {
265             opt.warn = true;
266         } else if (!strcmp(argv[i], "nowarn")) {
267             opt.warn = false;
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, ',');
282                 if (p) {
283                     *p = '\0';
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];
288                 }
289             }
290         } else {
291             usage();
292             goto bail;
293         }
294     }
295
296     if (opt.grubcfg && !opt.grub) {
297         error("grubcfg=<filename> must be used together with grub=<loader>.\n");
298         goto bail;
299     }
300
301     if ((!opt.maps || !opt.sect) && !opt.file) {
302         error("You have to load something.\n");
303         goto bail;
304     }
305
306     if (opt.filebpb && !opt.file) {
307         error("Option 'filebpb' requires a file.\n");
308         goto bail;
309     }
310
311     if (opt.save && !opt.sect) {
312         error("Option 'save' requires a sector.\n");
313         goto bail;
314     }
315
316     if (opt.setbpb && !opt.sect) {
317         error("Option 'setbpb' requires a sector.\n");
318         goto bail;
319     }
320
321     return 0;
322 bail:
323     return -1;
324 }
325
326 /* vim: set ts=8 sts=4 sw=4 noet: */