chain.c: Split chain into smaller files
[syslinux/sherbszt.git] / com32 / chain / options.c
blobefb563d7e035942ea45d6c1e879a311bc77fcd2b
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"
9 int soi_s2n(char *ptr, unsigned int *seg,
10 unsigned int *off,
11 unsigned int *ip)
13 unsigned int segval = 0, offval = 0, ipval = 0, val;
14 char *p;
16 segval = strtoul(ptr, &p, 0);
17 if (*p == ':')
18 offval = strtoul(p+1, &p, 0);
19 if (*p == ':')
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");
26 goto bail;
29 val = (segval << 4) + ipval;
31 if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
32 error("Invalid seg:*:ip address specified.\n");
33 goto bail;
36 if (seg)
37 *seg = segval;
38 if (off)
39 *off = offval;
40 if (ip)
41 *ip = ipval;
43 return 0;
44 bail:
45 return -1;
48 void usage(void)
50 static const char *const usage[] = { "\
51 Usage:\n\
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\
80 ", "\
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"
95 error(usage[0]);
96 error("Press any key...\n");
97 wait_key();
98 error(usage[1]);
101 int parse_args(int argc, char *argv[])
103 int i;
104 unsigned int v;
105 char *p;
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")) {
111 opt.file = NULL;
112 } else if (!strncmp(argv[i], "seg=", 4)) {
113 if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip))
114 goto bail;
115 } else if (!strncmp(argv[i], "isolinux=", 9)) {
116 opt.file = argv[i] + 9;
117 opt.isolinux = true;
118 opt.hand = false;
119 opt.sect = false;
120 } else if (!strncmp(argv[i], "ntldr=", 6)) {
121 opt.fseg = 0x2000; /* NTLDR wants this address */
122 opt.foff = 0;
123 opt.fip = 0;
124 opt.file = argv[i] + 6;
125 opt.sethid = true;
126 opt.setgeo = true;
127 opt.setdrv = true;
128 opt.drvoff = 0x24;
129 /* opt.save = true; */
130 opt.hand = false;
131 } else if (!strncmp(argv[i], "cmldr=", 6)) {
132 opt.fseg = 0x2000; /* CMLDR wants this address */
133 opt.foff = 0;
134 opt.fip = 0;
135 opt.file = argv[i] + 6;
136 opt.cmldr = true;
137 opt.sethid = true;
138 opt.setgeo = true;
139 opt.setdrv = true;
140 opt.drvoff = 0x24;
141 /* opt.save = true; */
142 opt.hand = false;
143 } else if (!strncmp(argv[i], "freedos=", 8)) {
144 opt.fseg = 0x60; /* FREEDOS wants this address */
145 opt.foff = 0;
146 opt.fip = 0;
147 opt.sseg = 0x9000;
148 opt.soff = 0;
149 opt.sip = 0;
150 opt.file = argv[i] + 8;
151 opt.sethid = true;
152 opt.setgeo = true;
153 opt.setdrv = true;
154 opt.drvoff = ~0u;
155 /* opt.save = true; */
156 opt.hand = false;
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 */
161 opt.foff = 0;
162 opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
163 opt.sseg = 0x9000;
164 opt.soff = 0;
165 opt.sip = 0;
166 opt.file = argv[i] + v;
167 opt.sethid = true;
168 opt.setgeo = true;
169 opt.setdrv = true;
170 opt.drvoff = ~0u;
171 /* opt.save = true; */
172 opt.hand = false;
173 } else if (!strncmp(argv[i], "drmk=", 5)) {
174 opt.fseg = 0x70; /* DRMK wants this address */
175 opt.foff = 0;
176 opt.fip = 0;
177 opt.sseg = 0x2000;
178 opt.soff = 0;
179 opt.sip = 0;
180 opt.file = argv[i] + 5;
181 /* opt.drmk = true; */
182 opt.sethid = true;
183 opt.setgeo = true;
184 opt.setdrv = true;
185 opt.drvoff = ~0u;
186 /* opt.save = true; */
187 opt.hand = false;
188 } else if (!strncmp(argv[i], "grub=", 5)) {
189 opt.fseg = 0x800; /* stage2 wants this address */
190 opt.foff = 0;
191 opt.fip = 0x200;
192 opt.file = argv[i] + 5;
193 opt.grub = true;
194 opt.hand = false;
195 opt.sect = false;
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;
200 opt.grldr = true;
201 opt.hand = false;
202 opt.sect = false;
203 } else if (!strcmp(argv[i], "keeppxe")) {
204 opt.keeppxe = 3;
205 } else if (!strcmp(argv[i], "nokeeppxe")) {
206 opt.keeppxe = 0;
207 } else if (!strcmp(argv[i], "maps")) {
208 opt.maps = true;
209 } else if (!strcmp(argv[i], "nomaps")) {
210 opt.maps = false;
211 } else if (!strcmp(argv[i], "hand")) {
212 opt.hand = true;
213 } else if (!strcmp(argv[i], "nohand")) {
214 opt.hand = false;
215 } else if (!strcmp(argv[i], "hptr")) {
216 opt.hptr = true;
217 } else if (!strcmp(argv[i], "nohptr")) {
218 opt.hptr = false;
219 } else if (!strcmp(argv[i], "swap")) {
220 opt.swap = true;
221 } else if (!strcmp(argv[i], "noswap")) {
222 opt.swap = false;
223 } else if (!strcmp(argv[i], "hide")) {
224 opt.hide = true;
225 } else if (!strcmp(argv[i], "nohide")) {
226 opt.hide = false;
227 } else if (!strcmp(argv[i], "sethid") ||
228 !strcmp(argv[i], "sethidden")) {
229 opt.sethid = true;
230 } else if (!strcmp(argv[i], "nosethid") ||
231 !strcmp(argv[i], "nosethidden")) {
232 opt.sethid = false;
233 } else if (!strcmp(argv[i], "setgeo")) {
234 opt.setgeo = true;
235 } else if (!strcmp(argv[i], "nosetgeo")) {
236 opt.setgeo = false;
237 } else if (!strncmp(argv[i], "setdrv",6)) {
238 if (!argv[i][6])
239 v = ~0u; /* autodetect */
240 else if (argv[i][6] == '@' ||
241 argv[i][6] == '=' ||
242 argv[i][6] == ':') {
243 v = strtoul(argv[i] + 7, NULL, 0);
244 if (!(v == 0x24 || v == 0x40)) {
245 error("Invalid 'setdrv' offset.\n");
246 goto bail;
248 } else {
249 error("Invalid 'setdrv' specification.\n");
250 goto bail;
252 opt.setdrv = true;
253 opt.drvoff = v;
254 } else if (!strcmp(argv[i], "nosetdrv")) {
255 opt.setdrv = false;
256 } else if (!strcmp(argv[i], "setbpb")) {
257 opt.setdrv = true;
258 opt.drvoff = ~0u;
259 opt.setgeo = true;
260 opt.sethid = true;
261 } else if (!strcmp(argv[i], "nosetbpb")) {
262 opt.setdrv = false;
263 opt.setgeo = false;
264 opt.sethid = false;
265 } else if (!strncmp(argv[i], "sect=", 5) ||
266 !strcmp(argv[i], "sect")) {
267 if (argv[i][4]) {
268 if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip))
269 goto bail;
270 if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
271 error("Arguments of 'sect=' are invalid - resulting address too big.\n");
272 goto bail;
275 opt.sect = true;
276 } else if (!strcmp(argv[i], "nosect")) {
277 opt.sect = false;
278 } else if (!strcmp(argv[i], "save")) {
279 opt.save = true;
280 } else if (!strcmp(argv[i], "nosave")) {
281 opt.save = false;
282 } else if (!strcmp(argv[i], "filebpb")) {
283 opt.filebpb = true;
284 } else if (!strcmp(argv[i], "nofilebpb")) {
285 opt.filebpb = false;
286 } else if (!strcmp(argv[i], "warn")) {
287 opt.warn = true;
288 } else if (!strcmp(argv[i], "nowarn")) {
289 opt.warn = false;
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, ',');
303 if (p) {
304 *p = '\0';
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];
310 } else {
311 usage();
312 goto bail;
316 if (opt.grubcfg && !opt.grub) {
317 error("grubcfg=<filename> must be used together with grub=<loader>.\n");
318 goto bail;
321 if ((!opt.maps || !opt.sect) && !opt.file) {
322 error("You have to load something.\n");
323 goto bail;
326 if (opt.filebpb && !opt.file) {
327 error("Option 'filebpb' requires file.\n");
328 goto bail;
331 return 0;
332 bail:
333 return -1;
336 /* vim: set ts=8 sts=4 sw=4 noet: */