toaruos/kernel/misc/args.c

157 lines
4.0 KiB
C
Raw Normal View History

2021-05-31 04:47:02 +03:00
/**
* @brief Kernel commandline argument parser.
2018-03-16 15:56:19 +03:00
*
* Arguments to the kernel are provided from the bootloader and
* provide information such as what mode to pass to init, or what
2021-05-31 04:47:02 +03:00
* hard disk partition should be mounted as root. We parse them
* into a hash table for easy lookup by key.
2018-03-16 15:56:19 +03:00
*
* An argument may be value-less (having no '='), in which case
* its value in the hash table will be NULL but it will be present.
* Examples of value-less arguments are @c lfbwc or @c noi965.
*
* Arguments with values can have quoted or unquoted values. Unquoted
* values are terminated by a space or the end of the command line and
* are not processed for escapes. Examples of arguments with
* unquoted values are @c root=/dev/ram0 or @c start=live-session.
*
* Quoted values must started immediately with a double quote (").
* Double quotes within the value may be escaped with a backslash (\).
* Backslash can also be escaped. Any other character after a
* backslash results in both a literal backslash and the following
* character.
*
* If a quoted value is not properly terminated with an unescaped
* double quote character, the entire argument will be ignored.
*
2021-05-31 04:47:02 +03:00
* @copyright This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2011-2023 K. Lange
2018-03-16 15:56:19 +03:00
*/
#ifdef _KERNEL_
# include <kernel/string.h>
# include <kernel/args.h>
# include <kernel/tokenize.h>
# include <kernel/hashmap.h>
#endif
2018-03-16 15:56:19 +03:00
hashmap_t * kernel_args_map = NULL;
/**
2021-05-31 04:47:02 +03:00
* @brief Determine if an argument was passed to the kernel.
*
2018-03-16 15:56:19 +03:00
* Check if an argument was provided to the kernel. If the argument is
* a simple switch, a response of 1 can be considered "on" for that
* argument; otherwise, this just notes that the argument was present,
* so the caller should check whether it is correctly set.
*/
2021-05-31 04:47:02 +03:00
int args_present(const char * karg) {
if (!kernel_args_map) return 0;
2018-03-16 15:56:19 +03:00
return hashmap_has(kernel_args_map, karg);
}
/**
2021-05-31 04:47:02 +03:00
* @brief Return the value associated with an argument provided to the kernel.
2018-03-16 15:56:19 +03:00
*/
2021-05-31 04:47:02 +03:00
char * args_value(const char * karg) {
if (!kernel_args_map) return 0;
2018-03-16 15:56:19 +03:00
return hashmap_get(kernel_args_map, karg);
}
/**
2021-05-31 04:47:02 +03:00
* @brief Parse the given arguments to the kernel.
2018-03-16 15:56:19 +03:00
*
* @param arg A string containing all arguments, separated by spaces.
*/
void args_parse(const char * cmdline) {
2018-03-16 15:56:19 +03:00
/* Sanity check... */
if (!cmdline) { return; }
if (!kernel_args_map) { kernel_args_map = hashmap_create(10); }
char * argbuf = strdup(cmdline);
char * x = argbuf;
2018-03-16 15:56:19 +03:00
for (;;) {
while (*x && *x == ' ') x++; /* skip spaces */
if (!*x) break;
2018-03-16 15:56:19 +03:00
char * value = NULL;
char * key = x;
while (*x && *x != '=' && *x != ' ') x++;
if (*x == '=') {
*x++ = '\0';
if (*x == '"') {
/* Start of quoted value */
x++;
value = x;
char * w = x;
while (*x && *x != '"') {
if (*x == '\\') {
x++;
switch (*x) {
case '"': *w++ = '"'; x++; break;
case '\\': *w++ = '\\'; x++; break;
case '\0': goto _parse_error;
default: *w++ = '\\'; *w++ = *x++; break;
}
} else {
*w++ = *x++;
}
}
2018-03-16 15:56:19 +03:00
if (*x == '"') {
*w = '\0';
x++;
} else if (*x == '\0') {
goto _parse_error;
}
} else {
/* Start of unquoted value */
value = x;
while (*x && *x != ' ') x++;
if (*x == ' ') {
*x = '\0';
x++;
}
2018-03-16 15:56:19 +03:00
}
} else if (*x == ' ') {
/* Value-less argument where we need to set nil byte */
*x++ = '\0';
2018-03-16 15:56:19 +03:00
}
hashmap_set(kernel_args_map, key, value ? strdup(value) : NULL);
2018-03-16 15:56:19 +03:00
}
_parse_error:
free(argbuf);
return;
2018-03-16 15:56:19 +03:00
}
#ifndef _KERNEL_
char * args_from_procfs(void) {
/* Open */
FILE * f = fopen("/proc/cmdline", "r");
if (!f) return NULL;
/* Determine size */
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
/* Read */
char * cmdline = calloc(size + 1, 1);
size_t rsize = fread(cmdline, 1, size, f);
if (cmdline[rsize-1] == '\n') cmdline[rsize-1] = '\0';
fclose(f);
/* Parse */
kernel_args_map = hashmap_create(10);
args_parse(cmdline);
return cmdline;
}
#endif