summaryrefslogtreecommitdiff
path: root/com32/chain/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'com32/chain/options.c')
-rw-r--r--com32/chain/options.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/com32/chain/options.c b/com32/chain/options.c
new file mode 100644
index 00000000..658a45ca
--- /dev/null
+++ b/com32/chain/options.c
@@ -0,0 +1,376 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+
+struct options opt;
+
+static int soi_s2n(char *ptr, unsigned int *seg,
+ unsigned int *off,
+ unsigned int *ip,
+ unsigned int def)
+{
+ unsigned int segval = 0, offval, ipval, val;
+ char *p;
+
+ offval = def;
+ ipval = def;
+
+ segval = strtoul(ptr, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ offval = strtoul(p+1, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ ipval = strtoul(p+1, NULL, 0);
+
+ val = (segval << 4) + offval;
+
+ if (val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:off:* address specified..\n");
+ goto bail;
+ }
+
+ val = (segval << 4) + ipval;
+
+ if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:*:ip address specified.\n");
+ goto bail;
+ }
+
+ if (seg)
+ *seg = segval;
+ if (off)
+ *off = offval;
+ if (ip)
+ *ip = ipval;
+
+ return 0;
+bail:
+ return -1;
+}
+
+static void usage(void)
+{
+ unsigned int i;
+ static const char key[] = "Press any key...\n";
+ static const char *const usage[] = {
+"\
+Usage:\n\
+ chain.c32 [options]\n\
+ chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
+ chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
+ chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
+ chain.c32 label{:|=}<label> [<part#>] [options]\n\
+ chain.c32 boot{,| }[<part#>] [options]\n\
+ chain.c32 fs [options]\n\
+", "\
+\nOptions ('no' prefix specifies default value):\n\
+ sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ maps Map loaded sector into real memory\n\
+ nosetbpb Fix BPB fields in loaded sector\n\
+ nofilebpb Apply 'setbpb' to loaded file\n\
+ nosave Write adjusted sector back to disk\n\
+ hand Prepare handover area\n\
+ nohptr Force ds:si and ds:bp to point to handover area\n\
+ noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
+ nohide Disable all hide variations (also the default)\n\
+ hide Hide primary partitions, unhide selected partition\n\
+ hideall Hide *all* partitions, unhide selected partition\n\
+ unhide Unhide primary partitions\n\
+ unhideall Unhide *all* partitions\n\
+ nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\
+ nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
+ nowarn Wait for a keypress to continue chainloading\n\
+ - useful to see emited warnings\n\
+ nobreak Actually perform the chainloading\n\
+", "\
+\nOptions continued ...\n\
+ file=<file> Load and execute <file>\n\
+ seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ isolinux=<loader> Load another version of ISOLINUX\n\
+ ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
+ reactos=<loader> Load ReactOS's loader\n\
+ cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
+ freedos=<loader> Load FreeDOS KERNEL.SYS\n\
+ msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
+ msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
+ pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
+ drmk=<loader> Load DRMK DELLBIO.BIN\n\
+ grub=<loader> Load GRUB Legacy stage2\n\
+ grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
+ grldr=<loader> Load GRUB4DOS grldr\n\
+ bss=<filename> Emulate syslinux's BSS\n\
+ bs=<filename> Emulate syslinux's BS\n\
+\nPlease see doc/chain.txt for the detailed documentation.\n\
+"
+ };
+ for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
+ if (i) {
+ error(key);
+ wait_key();
+ }
+ error(usage[i]);
+ }
+}
+
+void opt_set_defs(void)
+{
+ memset(&opt, 0, sizeof(opt));
+ opt.sect = true; /* by def. load sector */
+ opt.maps = true; /* by def. map sector */
+ opt.hand = true; /* by def. prepare handover */
+ opt.brkchain = false; /* by def. do chainload */
+ opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
+ opt.drivename = "boot";
+#ifdef DEBUG
+ opt.warn = true;
+#endif
+}
+
+int opt_parse_args(int argc, char *argv[])
+{
+ int i;
+ unsigned int v;
+ char *p;
+
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "file=", 5)) {
+ opt.file = argv[i] + 5;
+ } else if (!strcmp(argv[i], "nofile")) {
+ opt.file = NULL;
+ } else if (!strncmp(argv[i], "seg=", 4)) {
+ if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
+ goto bail;
+ } else if (!strncmp(argv[i], "bss=", 4)) {
+ opt.file = argv[i] + 4;
+ opt.bss = true;
+ opt.maps = false;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ } else if (!strncmp(argv[i], "bs=", 3)) {
+ opt.file = argv[i] + 3;
+ opt.sect = false;
+ opt.filebpb = true;
+ } else if (!strncmp(argv[i], "isolinux=", 9)) {
+ opt.file = argv[i] + 9;
+ opt.isolinux = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "ntldr=", 6)) {
+ opt.fseg = 0x2000; /* NTLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "reactos=", 8)) {
+ /*
+ * settings based on commit
+ * ad4cf1470977f648ee1dd45e97939589ccb0393c
+ * note, conflicts with:
+ * http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt
+ */
+ opt.fseg = 0;
+ opt.foff = 0x8000;
+ opt.fip = 0x8100;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "cmldr=", 6)) {
+ opt.fseg = 0x2000; /* CMLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.cmldr = true;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "freedos=", 8)) {
+ opt.fseg = 0x60; /* FREEDOS wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x1FE0;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
+ !strncmp(argv[i], "pcdos=", v)) ||
+ (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
+ opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
+ opt.foff = 0;
+ opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
+ opt.sseg = 0x8000;
+ opt.file = argv[i] + v;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "drmk=", 5)) {
+ opt.fseg = 0x70; /* DRMK wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x2000;
+ opt.soff = 0;
+ opt.sip = 0;
+ opt.file = argv[i] + 5;
+ /* opt.drmk = true; */
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "grub=", 5)) {
+ opt.fseg = 0x800; /* stage2 wants this address */
+ opt.foff = 0;
+ opt.fip = 0x200;
+ opt.file = argv[i] + 5;
+ opt.grub = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "grubcfg=", 8)) {
+ opt.grubcfg = argv[i] + 8;
+ } else if (!strncmp(argv[i], "grldr=", 6)) {
+ opt.file = argv[i] + 6;
+ opt.grldr = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strcmp(argv[i], "keeppxe")) {
+ opt.keeppxe = 3;
+ } else if (!strcmp(argv[i], "nokeeppxe")) {
+ opt.keeppxe = 0;
+ } else if (!strcmp(argv[i], "maps")) {
+ opt.maps = true;
+ } else if (!strcmp(argv[i], "nomaps")) {
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "hand")) {
+ opt.hand = true;
+ } else if (!strcmp(argv[i], "nohand")) {
+ opt.hand = false;
+ } else if (!strcmp(argv[i], "hptr")) {
+ opt.hptr = true;
+ } else if (!strcmp(argv[i], "nohptr")) {
+ opt.hptr = false;
+ } else if (!strcmp(argv[i], "swap")) {
+ opt.swap = true;
+ } else if (!strcmp(argv[i], "noswap")) {
+ opt.swap = false;
+ } else if (!strcmp(argv[i], "nohide")) {
+ opt.hide = 0;
+ } else if (!strcmp(argv[i], "hide")) {
+ opt.hide = 1; /* 001b */
+ } else if (!strcmp(argv[i], "hideall")) {
+ opt.hide = 2; /* 010b */
+ } else if (!strcmp(argv[i], "unhide")) {
+ opt.hide = 5; /* 101b */
+ } else if (!strcmp(argv[i], "unhideall")) {
+ opt.hide = 6; /* 110b */
+ } else if (!strcmp(argv[i], "setbpb")) {
+ opt.setbpb = true;
+ } else if (!strcmp(argv[i], "nosetbpb")) {
+ opt.setbpb = false;
+ } else if (!strcmp(argv[i], "filebpb")) {
+ opt.filebpb = true;
+ } else if (!strcmp(argv[i], "nofilebpb")) {
+ opt.filebpb = false;
+ } else if (!strncmp(argv[i], "sect=", 5) ||
+ !strcmp(argv[i], "sect")) {
+ if (argv[i][4]) {
+ if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0))
+ goto bail;
+ }
+ opt.sect = true;
+ } else if (!strcmp(argv[i], "nosect")) {
+ opt.sect = false;
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "save")) {
+ opt.save = true;
+ } else if (!strcmp(argv[i], "nosave")) {
+ opt.save = false;
+ } else if (!strcmp(argv[i], "fixchs")) {
+ opt.fixchs = true;
+ } else if (!strcmp(argv[i], "nofixchs")) {
+ opt.fixchs = false;
+ } else if (!strcmp(argv[i], "warn")) {
+ opt.warn = true;
+ } else if (!strcmp(argv[i], "nowarn")) {
+ opt.warn = false;
+ } else if (!strcmp(argv[i], "nobreak")) {
+ opt.brkchain = false;
+ } else if (!strcmp(argv[i], "break")) {
+ opt.brkchain = true;
+ opt.file = NULL;
+ opt.maps = false;
+ opt.hand = false;
+ } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
+ && argv[i][1] == 'd')
+ || !strncmp(argv[i], "mbr:", 4)
+ || !strncmp(argv[i], "mbr=", 4)
+ || !strncmp(argv[i], "guid:", 5)
+ || !strncmp(argv[i], "guid=", 5)
+ || !strncmp(argv[i], "label:", 6)
+ || !strncmp(argv[i], "label=", 6)
+ || !strcmp(argv[i], "boot")
+ || !strncmp(argv[i], "boot,", 5)
+ || !strcmp(argv[i], "fs")) {
+ opt.drivename = argv[i];
+ if (strncmp(argv[i], "label", 5))
+ p = strchr(opt.drivename, ',');
+ else
+ p = NULL;
+ if (p) {
+ *p = '\0';
+ opt.partition = p + 1;
+ } else if (argv[i + 1] && argv[i + 1][0] >= '0'
+ && argv[i + 1][0] <= '9') {
+ opt.partition = argv[++i];
+ }
+ } else {
+ usage();
+ goto bail;
+ }
+ }
+
+ if (opt.grubcfg && !opt.grub) {
+ error("grubcfg=<filename> must be used together with grub=<loader>.\n");
+ goto bail;
+ }
+
+#if 0
+ if ((!opt.maps || !opt.sect) && !opt.file) {
+ error("You have to load something.\n");
+ goto bail;
+ }
+#endif
+
+ if (opt.filebpb && !opt.file) {
+ error("Option 'filebpb' requires a file.\n");
+ goto bail;
+ }
+
+ if (opt.save && !opt.sect) {
+ error("Option 'save' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.setbpb && !opt.sect) {
+ error("Option 'setbpb' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.maps && !opt.sect) {
+ error("Option 'maps' requires a sector.\n");
+ goto bail;
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */