ntloader/kern/cmdline.c
2025-02-24 09:54:11 +09:00

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);
}
}