mirror of
https://github.com/grub4dos/ntloader.git
synced 2025-05-09 04:01:08 +08:00
352 lines
10 KiB
C
352 lines
10 KiB
C
/*
|
|
* ntloader -- Microsoft Windows NT6+ loader
|
|
* Copyright (C) 2025 A1ive.
|
|
*
|
|
* ntloader is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* ntloader is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <ctype.h>
|
|
#include <wchar.h>
|
|
#include "ntloader.h"
|
|
#include "cmdline.h"
|
|
#include "bcd.h"
|
|
|
|
static struct nt_args args =
|
|
{
|
|
.textmode = NTARG_BOOL_FALSE,
|
|
.testmode = NTARG_BOOL_FALSE,
|
|
.hires = NTARG_BOOL_UNSET, // wim = yes
|
|
.hal = NTARG_BOOL_TRUE,
|
|
.minint = NTARG_BOOL_UNSET, // wim = yes
|
|
.novga = NTARG_BOOL_FALSE,
|
|
.novesa = NTARG_BOOL_FALSE,
|
|
.safemode = NTARG_BOOL_FALSE,
|
|
.altshell = NTARG_BOOL_FALSE,
|
|
.exportcd = NTARG_BOOL_FALSE,
|
|
.advmenu = NTARG_BOOL_FALSE,
|
|
.optedit = NTARG_BOOL_FALSE,
|
|
|
|
.nx = NX_OPTIN,
|
|
.pae = PAE_DEFAULT,
|
|
.timeout = 0,
|
|
.safeboot = SAFE_MINIMAL,
|
|
.gfxmode = GFXMODE_1024X768,
|
|
.imgofs = 65536,
|
|
|
|
.loadopt = BCD_DEFAULT_CMDLINE,
|
|
.winload = "",
|
|
.sysroot = BCD_DEFAULT_SYSROOT,
|
|
|
|
.boottype = NTBOOT_WOS,
|
|
.fsuuid = "",
|
|
.partid = { 0 },
|
|
.diskid = { 0 },
|
|
.partmap = 0x01,
|
|
|
|
.initrd_path = "\\initrd.cpio",
|
|
.bcd = NULL,
|
|
.bcd_length = 0,
|
|
.bootmgr = NULL,
|
|
.bootmgr_length = 0,
|
|
};
|
|
|
|
struct nt_args *nt_cmdline;
|
|
|
|
static void
|
|
convert_path (char *str, int backslash)
|
|
{
|
|
char *p = str;
|
|
while (*p)
|
|
{
|
|
if (*p == '/' && backslash)
|
|
*p = '\\';
|
|
if (*p == ':')
|
|
*p = ' ';
|
|
if (*p == '\r' || *p == '\n')
|
|
*p = '\0';
|
|
p++;
|
|
}
|
|
}
|
|
|
|
static uint8_t
|
|
convert_bool (const char *str)
|
|
{
|
|
uint8_t value = NTARG_BOOL_FALSE;
|
|
if (! str ||
|
|
strcasecmp (str, "yes") == 0 ||
|
|
strcasecmp (str, "on") == 0 ||
|
|
strcasecmp (str, "true") == 0 ||
|
|
strcasecmp (str, "1") == 0)
|
|
value = NTARG_BOOL_TRUE;
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Process command line
|
|
*
|
|
* @v cmdline Command line
|
|
*/
|
|
void process_cmdline (char *cmdline)
|
|
{
|
|
char *tmp = cmdline;
|
|
char *key;
|
|
char *value;
|
|
char chr;
|
|
|
|
nt_cmdline = &args;
|
|
|
|
/* Do nothing if we have no command line */
|
|
if ((cmdline == NULL) || (cmdline[0] == '\0'))
|
|
return;
|
|
|
|
/* Show command line */
|
|
printf ("Command line: \"%s\"\n", cmdline);
|
|
|
|
/* Parse command line */
|
|
while (*tmp)
|
|
{
|
|
|
|
/* Skip whitespace */
|
|
while (isspace (*tmp))
|
|
tmp++;
|
|
|
|
/* Find value (if any) and end of this argument */
|
|
key = tmp;
|
|
value = NULL;
|
|
while ((chr = *tmp))
|
|
{
|
|
if (isspace (chr))
|
|
{
|
|
*(tmp++) = '\0';
|
|
break;
|
|
}
|
|
else if ((chr == '=') && (! value))
|
|
{
|
|
*(tmp++) = '\0';
|
|
value = tmp;
|
|
}
|
|
else
|
|
tmp++;
|
|
}
|
|
|
|
/* Process this argument */
|
|
if (strcmp (key, "uuid") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "uuid");
|
|
snprintf (args.fsuuid, 17, "%s", value);
|
|
}
|
|
else if (strcmp (key, "wim") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "wim");
|
|
snprintf (args.filepath, 256, "%s", value);
|
|
convert_path (args.filepath, 1);
|
|
args.boottype = NTBOOT_WIM;
|
|
}
|
|
else if (strcmp (key, "vhd") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "vhd");
|
|
snprintf (args.filepath, 256, "%s", value);
|
|
convert_path (args.filepath, 1);
|
|
args.boottype = NTBOOT_VHD;
|
|
}
|
|
else if (strcmp (key, "ram") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "ram");
|
|
snprintf (args.filepath, 256, "%s", value);
|
|
convert_path (args.filepath, 1);
|
|
args.boottype = NTBOOT_RAM;
|
|
}
|
|
else if (strcmp (key, "file") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "file");
|
|
snprintf (args.filepath, 256, "%s", value);
|
|
convert_path (args.filepath, 1);
|
|
char *ext = strrchr (value, '.');
|
|
if (ext && strcasecmp(ext, ".wim") == 0)
|
|
args.boottype = NTBOOT_WIM;
|
|
else
|
|
args.boottype = NTBOOT_VHD;
|
|
}
|
|
else if (strcmp (key, "text") == 0)
|
|
{
|
|
args.textmode = NTARG_BOOL_TRUE;
|
|
}
|
|
else if (strcmp (key, "testmode") == 0)
|
|
{
|
|
args.testmode = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "hires") == 0)
|
|
{
|
|
args.hires = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "detecthal") == 0)
|
|
{
|
|
args.hal = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "minint") == 0)
|
|
{
|
|
args.minint = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "novga") == 0)
|
|
{
|
|
args.novga = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "novesa") == 0)
|
|
{
|
|
args.novesa = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "altshell") == 0)
|
|
{
|
|
args.altshell = convert_bool (value);
|
|
args.safemode = NTARG_BOOL_TRUE;
|
|
}
|
|
else if (strcmp (key, "exportascd") == 0)
|
|
{
|
|
args.exportcd = convert_bool (value);
|
|
}
|
|
else if (strcmp (key, "f8") == 0)
|
|
{
|
|
args.advmenu = NTARG_BOOL_TRUE;
|
|
args.textmode = NTARG_BOOL_TRUE;
|
|
}
|
|
else if (strcmp (key, "edit") == 0)
|
|
{
|
|
args.optedit = NTARG_BOOL_TRUE;
|
|
args.textmode = NTARG_BOOL_TRUE;
|
|
}
|
|
else if (strcmp (key, "nx") == 0)
|
|
{
|
|
if (! value || strcasecmp (value, "OptIn") == 0)
|
|
args.nx = NX_OPTIN;
|
|
else if (strcasecmp (value, "OptOut") == 0)
|
|
args.nx = NX_OPTOUT;
|
|
else if (strcasecmp (value, "AlwaysOff") == 0)
|
|
args.nx = NX_ALWAYSOFF;
|
|
else if (strcasecmp (value, "AlwaysOn") == 0)
|
|
args.nx = NX_ALWAYSON;
|
|
}
|
|
else if (strcmp (key, "pae") == 0)
|
|
{
|
|
if (! value || strcasecmp (value, "Default") == 0)
|
|
args.pae = PAE_DEFAULT;
|
|
else if (strcasecmp (value, "Enable") == 0)
|
|
args.pae = PAE_ENABLE;
|
|
else if (strcasecmp (value, "Disable") == 0)
|
|
args.pae = PAE_DISABLE;
|
|
}
|
|
else if (strcmp (key, "safemode") == 0)
|
|
{
|
|
args.safemode = NTARG_BOOL_TRUE;
|
|
if (! value || strcasecmp (value, "Minimal") == 0)
|
|
args.safeboot = SAFE_MINIMAL;
|
|
else if (strcasecmp (value, "Network") == 0)
|
|
args.safeboot = SAFE_NETWORK;
|
|
else if (strcasecmp (value, "DsRepair") == 0)
|
|
args.safeboot = SAFE_DSREPAIR;
|
|
}
|
|
else if (strcmp (key, "gfxmode") == 0)
|
|
{
|
|
args.hires = NTARG_BOOL_NA;
|
|
if (! value || strcasecmp (value, "1024x768") == 0)
|
|
args.gfxmode = GFXMODE_1024X768;
|
|
else if (strcasecmp (value, "800x600") == 0)
|
|
args.gfxmode = GFXMODE_800X600;
|
|
else if (strcasecmp (value, "1024x600") == 0)
|
|
args.gfxmode = GFXMODE_1024X600;
|
|
}
|
|
else if (strcmp (key, "imgofs") == 0)
|
|
{
|
|
char *endp;
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "imgofs");
|
|
args.imgofs = strtoul (value, &endp, 0);
|
|
if (*endp)
|
|
die ("Invalid imgofs \"%s\"\n", value);
|
|
}
|
|
else if (strcmp (key, "loadopt") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "loadopt");
|
|
snprintf (args.loadopt, 128, "%s", value);
|
|
convert_path (args.loadopt, 0);
|
|
}
|
|
else if (strcmp (key, "winload") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "winload");
|
|
snprintf (args.winload, 64, "%s", value);
|
|
convert_path (args.winload, 1);
|
|
}
|
|
else if (strcmp (key, "sysroot") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "sysroot");
|
|
snprintf (args.sysroot, 32, "%s", value);
|
|
convert_path (args.sysroot, 1);
|
|
}
|
|
else if (strcmp (key, "initrdfile") == 0 ||
|
|
strcmp (key, "initrd") == 0)
|
|
{
|
|
if (! value || ! value[0])
|
|
die ("Argument \"%s\" needs a value\n", "initrd");
|
|
|
|
snprintf (args.initrd_path, MAX_PATH + 1, "%s", value);
|
|
convert_path (args.initrd_path, 1);
|
|
}
|
|
else
|
|
{
|
|
/* Ignore unknown arguments */
|
|
}
|
|
|
|
/* Undo modifications to command line */
|
|
if (chr)
|
|
tmp[-1] = chr;
|
|
if (value)
|
|
value[-1] = '=';
|
|
}
|
|
|
|
if (args.hires == NTARG_BOOL_UNSET)
|
|
{
|
|
if (args.boottype == NTBOOT_WIM)
|
|
args.hires = NTARG_BOOL_TRUE;
|
|
else
|
|
args.hires = NTARG_BOOL_FALSE;
|
|
}
|
|
|
|
if (args.minint == NTARG_BOOL_UNSET)
|
|
{
|
|
if (args.boottype == NTBOOT_WIM)
|
|
args.minint = NTARG_BOOL_TRUE;
|
|
else
|
|
args.minint = NTARG_BOOL_FALSE;
|
|
}
|
|
if (args.winload[0] == '\0')
|
|
{
|
|
if (args.boottype == NTBOOT_WIM)
|
|
snprintf (args.winload, 64, "%s", BCD_LONG_WINLOAD);
|
|
else
|
|
snprintf (args.winload, 64, "%s", BCD_SHORT_WINLOAD);
|
|
}
|
|
}
|