com32/chain: allow service-only runs
[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 ('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\
88 ", "\
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\
108 "
109     };
110     for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
111         if (i) {
112             error(key);
113             wait_key();
114         }
115         error(usage[i]);
116     }
117 }
118
119 int parse_args(int argc, char *argv[])
120 {
121     int i;
122     unsigned int v;
123     char *p;
124
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")) {
129             opt.file = NULL;
130         } else if (!strncmp(argv[i], "seg=", 4)) {
131             if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
132                 goto bail;
133         } else if (!strncmp(argv[i], "bss=", 4)) {
134             opt.file = argv[i] + 4;
135             opt.bss = true;
136             opt.maps = false;
137             opt.setbpb = true;
138             /* opt.save = true; */
139         } else if (!strncmp(argv[i], "bs=", 3)) {
140             opt.file = argv[i] + 3;
141             opt.sect = false;
142             opt.filebpb = true;
143         } else if (!strncmp(argv[i], "isolinux=", 9)) {
144             opt.file = argv[i] + 9;
145             opt.isolinux = true;
146             opt.hand = false;
147             opt.sect = false;
148         } else if (!strncmp(argv[i], "ntldr=", 6)) {
149             opt.fseg = 0x2000;  /* NTLDR wants this address */
150             opt.foff = 0;
151             opt.fip = 0;
152             opt.file = argv[i] + 6;
153             opt.setbpb = true;
154             /* opt.save = true; */
155             opt.hand = false;
156         } else if (!strncmp(argv[i], "cmldr=", 6)) {
157             opt.fseg = 0x2000;  /* CMLDR wants this address */
158             opt.foff = 0;
159             opt.fip = 0;
160             opt.file = argv[i] + 6;
161             opt.cmldr = true;
162             opt.setbpb = true;
163             /* opt.save = true; */
164             opt.hand = false;
165         } else if (!strncmp(argv[i], "freedos=", 8)) {
166             opt.fseg = 0x60;    /* FREEDOS wants this address */
167             opt.foff = 0;
168             opt.fip = 0;
169             opt.sseg = 0x1FE0;
170             opt.file = argv[i] + 8;
171             opt.setbpb = true;
172             /* opt.save = true; */
173             opt.hand = false;
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 */
178             opt.foff = 0;
179             opt.fip = v == 7 ? 0x200 : 0;  /* MS-DOS 7.0+ wants this ip */
180             opt.sseg = 0x8000;
181             opt.file = argv[i] + v;
182             opt.setbpb = true;
183             /* opt.save = true; */
184             opt.hand = false;
185         } else if (!strncmp(argv[i], "drmk=", 5)) {
186             opt.fseg = 0x70;    /* DRMK wants this address */
187             opt.foff = 0;
188             opt.fip = 0;
189             opt.sseg = 0x2000;
190             opt.soff = 0;
191             opt.sip = 0;
192             opt.file = argv[i] + 5;
193             /* opt.drmk = true; */
194             opt.setbpb = true;
195             /* opt.save = true; */
196             opt.hand = false;
197         } else if (!strncmp(argv[i], "grub=", 5)) {
198             opt.fseg = 0x800;   /* stage2 wants this address */
199             opt.foff = 0;
200             opt.fip = 0x200;
201             opt.file = argv[i] + 5;
202             opt.grub = true;
203             opt.hand = false;
204             opt.sect = false;
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;
209             opt.grldr = true;
210             opt.hand = false;
211             opt.sect = false;
212         } else if (!strcmp(argv[i], "keeppxe")) {
213             opt.keeppxe = 3;
214         } else if (!strcmp(argv[i], "nokeeppxe")) {
215             opt.keeppxe = 0;
216         } else if (!strcmp(argv[i], "maps")) {
217             opt.maps = true;
218         } else if (!strcmp(argv[i], "nomaps")) {
219             opt.maps = false;
220         } else if (!strcmp(argv[i], "hand")) {
221             opt.hand = true;
222         } else if (!strcmp(argv[i], "nohand")) {
223             opt.hand = false;
224         } else if (!strcmp(argv[i], "hptr")) {
225             opt.hptr = true;
226         } else if (!strcmp(argv[i], "nohptr")) {
227             opt.hptr = false;
228         } else if (!strcmp(argv[i], "swap")) {
229             opt.swap = true;
230         } else if (!strcmp(argv[i], "noswap")) {
231             opt.swap = false;
232         } else if (!strcmp(argv[i], "nohide")) {
233             opt.hide = 0;
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")) {
243             opt.setbpb = true;
244         } else if (!strcmp(argv[i], "nosetbpb")) {
245             opt.setbpb = false;
246         } else if (!strcmp(argv[i], "filebpb")) {
247             opt.filebpb = true;
248         } else if (!strcmp(argv[i], "nofilebpb")) {
249             opt.filebpb = false;
250         } else if (!strncmp(argv[i], "sect=", 5) ||
251                    !strcmp(argv[i], "sect")) {
252             if (argv[i][4]) {
253                 if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0x7c00))
254                     goto bail;
255                 if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
256                     error("Arguments of 'sect=' are invalid - resulting address too big.\n");
257                     goto bail;
258                 }
259             }
260             opt.sect = true;
261         } else if (!strcmp(argv[i], "nosect")) {
262             opt.sect = false;
263         } else if (!strcmp(argv[i], "save")) {
264             opt.save = true;
265         } else if (!strcmp(argv[i], "nosave")) {
266             opt.save = false;
267         } else if (!strcmp(argv[i], "mbrchs")) {
268             opt.mbrchs = true;
269         } else if (!strcmp(argv[i], "nombrchs")) {
270             opt.mbrchs = false;
271         } else if (!strcmp(argv[i], "warn")) {
272             opt.warn = true;
273         } else if (!strcmp(argv[i], "nowarn")) {
274             opt.warn = false;
275         } else if (!strcmp(argv[i], "chain")) {
276             opt.chain = true;
277         } else if (!strcmp(argv[i], "nochain")) {
278             opt.chain = false;
279             opt.file = NULL;
280             opt.maps = false;
281             opt.hand = false;
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, ',');
296             else
297                 p = NULL;
298             if (p) {
299                 *p = '\0';
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];
304             }
305         } else {
306             usage();
307             goto bail;
308         }
309     }
310
311     if (opt.grubcfg && !opt.grub) {
312         error("grubcfg=<filename> must be used together with grub=<loader>.\n");
313         goto bail;
314     }
315
316 #if 0
317     if ((!opt.maps || !opt.sect) && !opt.file) {
318         error("You have to load something.\n");
319         goto bail;
320     }
321 #endif
322
323     if (opt.filebpb && !opt.file) {
324         error("Option 'filebpb' requires a file.\n");
325         goto bail;
326     }
327
328     if (opt.save && !opt.sect) {
329         error("Option 'save' requires a sector.\n");
330         goto bail;
331     }
332
333     if (opt.setbpb && !opt.sect) {
334         error("Option 'setbpb' requires a sector.\n");
335         goto bail;
336     }
337
338     return 0;
339 bail:
340     return -1;
341 }
342
343 /* vim: set ts=8 sts=4 sw=4 noet: */