kernel: add boot argument parsing
This commit is contained in:
125
kernel/arg.c
Normal file
125
kernel/arg.c
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <socks/arg.h>
|
||||
#include <socks/libc/string.h>
|
||||
#include <socks/libc/ctype.h>
|
||||
|
||||
static char g_cmdline[CMDLINE_MAX + 1] = {0};
|
||||
|
||||
static kern_status_t remove_quotes(char *s, size_t max)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i < max) {
|
||||
if (s[i] != '"') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t start = i;
|
||||
size_t end = i + 1;
|
||||
while (s[end] != '"' && end < max) {
|
||||
end++;
|
||||
}
|
||||
|
||||
if (s[end] != '"') {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* length of quoted string (excluding quotes) */
|
||||
size_t len = end - start - 1;
|
||||
|
||||
/* remove trailing quote */
|
||||
s[end] = 0;
|
||||
|
||||
/* add 1 to len to include the null terminator */
|
||||
memmove(s + start, s + start + 1, len + 1);
|
||||
|
||||
i = end + 1;
|
||||
}
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t parse_cmdline(const char *cmdline)
|
||||
{
|
||||
strncpy(g_cmdline, cmdline, sizeof g_cmdline - 1);
|
||||
g_cmdline[sizeof g_cmdline - 1] = 0;
|
||||
|
||||
bool in_string = false;
|
||||
|
||||
for (size_t i = 0; g_cmdline[i]; i++) {
|
||||
char c = g_cmdline[i];
|
||||
|
||||
if (c == '"') {
|
||||
in_string = !in_string;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isspace(c) && !in_string) {
|
||||
g_cmdline[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_string) {
|
||||
/* unterminated string on command line */
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
remove_quotes(g_cmdline, sizeof g_cmdline);
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
static char *advance_to_next_arg(char *s, char *max)
|
||||
{
|
||||
while (*s && s < max) {
|
||||
s++;
|
||||
}
|
||||
|
||||
while (!*s && s < max) {
|
||||
s++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
const char *arg_value(const char *arg_name)
|
||||
{
|
||||
char *s = g_cmdline;
|
||||
char *end = s + sizeof g_cmdline;
|
||||
|
||||
while (s < end) {
|
||||
size_t len = strlen(s);
|
||||
size_t name_len = strcspn(s, "=");
|
||||
|
||||
if (!strncmp(s, arg_name, name_len)) {
|
||||
if (len == name_len) {
|
||||
/* arg has no value */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s + name_len + 1;
|
||||
}
|
||||
|
||||
s = advance_to_next_arg(s, end);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool arg_is_set(const char *arg_name)
|
||||
{
|
||||
char *s = g_cmdline;
|
||||
char *end = s + sizeof g_cmdline;
|
||||
|
||||
while (s < end) {
|
||||
size_t name_len = strcspn(s, "=");
|
||||
|
||||
if (!strncmp(s, arg_name, name_len)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
s = advance_to_next_arg(s, end);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user