kernel: Support quoted values in cmdline arguments with new parser
This commit is contained in:
parent
aebb75ac75
commit
a679ef1b4c
@ -23,62 +23,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <toaru/hashmap.h>
|
#include <toaru/hashmap.h>
|
||||||
|
|
||||||
hashmap_t * args_map = NULL;
|
#include "../kernel/misc/args.c"
|
||||||
|
|
||||||
int tokenize(char * str, char * sep, char **buf) {
|
|
||||||
char * pch_i;
|
|
||||||
char * save_i;
|
|
||||||
int argc = 0;
|
|
||||||
pch_i = strtok_r(str,sep,&save_i);
|
|
||||||
if (!pch_i) { return 0; }
|
|
||||||
while (pch_i != NULL) {
|
|
||||||
buf[argc] = (char *)pch_i;
|
|
||||||
++argc;
|
|
||||||
pch_i = strtok_r(NULL,sep,&save_i);
|
|
||||||
}
|
|
||||||
buf[argc] = NULL;
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void args_parse(char * _arg) {
|
|
||||||
char * arg = strdup(_arg);
|
|
||||||
char * argv[1024];
|
|
||||||
int argc = tokenize(arg, " ", argv);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
|
||||||
char * c = strdup(argv[i]);
|
|
||||||
|
|
||||||
char * name;
|
|
||||||
char * value;
|
|
||||||
|
|
||||||
name = c;
|
|
||||||
value = NULL;
|
|
||||||
/* Find the first = and replace it with a null */
|
|
||||||
char * v = c;
|
|
||||||
while (*v) {
|
|
||||||
if (*v == '=') {
|
|
||||||
*v = '\0';
|
|
||||||
v++;
|
|
||||||
value = v;
|
|
||||||
char * tmp = value;
|
|
||||||
/* scan it for \037 and replace with spaces */
|
|
||||||
while (*tmp) {
|
|
||||||
if (*tmp == '\037') {
|
|
||||||
*tmp = ' ';
|
|
||||||
}
|
|
||||||
tmp++;
|
|
||||||
}
|
|
||||||
goto _break;
|
|
||||||
}
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_break:
|
|
||||||
hashmap_set(args_map, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_usage(int argc, char * argv[]) {
|
void show_usage(int argc, char * argv[]) {
|
||||||
printf(
|
printf(
|
||||||
@ -94,28 +39,15 @@ void show_usage(int argc, char * argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
/* Open */
|
char * cmdline = args_from_procfs();
|
||||||
FILE * f = fopen("/proc/cmdline", "r");
|
|
||||||
if (!f) return 1;
|
|
||||||
|
|
||||||
/* Read */
|
|
||||||
char * cmdline = malloc(4096); /* cmdline can't be longer than that */
|
|
||||||
memset(cmdline, 0, 4096);
|
|
||||||
size_t size = fread(cmdline, 1, 4096, f);
|
|
||||||
if (cmdline[size-1] == '\n') cmdline[size-1] = '\0';
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
/* Parse */
|
|
||||||
args_map = hashmap_create(10);
|
|
||||||
args_parse(cmdline);
|
|
||||||
|
|
||||||
/* Figure out what we're doing */
|
/* Figure out what we're doing */
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "?g:q:s")) != -1) {
|
while ((opt = getopt(argc, argv, "?g:q:s")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'g':
|
case 'g':
|
||||||
if (hashmap_has(args_map, optarg)) {
|
if (hashmap_has(kernel_args_map, optarg)) {
|
||||||
char * tmp = (char*)hashmap_get(args_map, optarg);
|
char * tmp = (char*)hashmap_get(kernel_args_map, optarg);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
printf("%s\n", optarg); /* special case = present but not set should yield name of variable */
|
printf("%s\n", optarg); /* special case = present but not set should yield name of variable */
|
||||||
} else {
|
} else {
|
||||||
@ -126,9 +58,9 @@ int main(int argc, char * argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case 'q':
|
case 'q':
|
||||||
return !hashmap_has(args_map,optarg);
|
return !hashmap_has(kernel_args_map,optarg);
|
||||||
case 's':
|
case 's':
|
||||||
return size;
|
return strlen(cmdline);
|
||||||
case '?':
|
case '?':
|
||||||
show_usage(argc, argv);
|
show_usage(argc, argv);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -37,21 +37,6 @@
|
|||||||
static int _debug = 0;
|
static int _debug = 0;
|
||||||
static FILE * _splash = NULL;
|
static FILE * _splash = NULL;
|
||||||
|
|
||||||
int tokenize(char * str, char * sep, char **buf) {
|
|
||||||
char * pch_i;
|
|
||||||
char * save_i;
|
|
||||||
int argc = 0;
|
|
||||||
pch_i = strtok_r(str,sep,&save_i);
|
|
||||||
if (!pch_i) { return 0; }
|
|
||||||
while (pch_i != NULL) {
|
|
||||||
buf[argc] = (char *)pch_i;
|
|
||||||
++argc;
|
|
||||||
pch_i = strtok_r(NULL,sep,&save_i);
|
|
||||||
}
|
|
||||||
buf[argc] = NULL;
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_link(char * source, char * dest, int mode, int uid, int gid) {
|
void copy_link(char * source, char * dest, int mode, int uid, int gid) {
|
||||||
//fprintf(stderr, "need to copy link %s to %s\n", source, dest);
|
//fprintf(stderr, "need to copy link %s to %s\n", source, dest);
|
||||||
char tmp[1024];
|
char tmp[1024];
|
||||||
@ -144,51 +129,11 @@ void free_ramdisk(char * path) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
hashmap_t * get_cmdline(void) {
|
#include "../kernel/misc/args.c"
|
||||||
int fd = open("/proc/cmdline", O_RDONLY);
|
static hashmap_t * get_cmdline(void) {
|
||||||
char * out = malloc(1024);
|
char * results = args_from_procfs();
|
||||||
size_t r = read(fd, out, 1024);
|
if (results) free(results);
|
||||||
out[r] = '\0';
|
return kernel_args_map;
|
||||||
if (out[r-1] == '\n') {
|
|
||||||
out[r-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
char * arg = strdup(out);
|
|
||||||
char * argv[1024];
|
|
||||||
int argc = tokenize(arg, " ", argv);
|
|
||||||
|
|
||||||
/* New let's parse the tokens into the arguments list so we can index by key */
|
|
||||||
|
|
||||||
hashmap_t * args = hashmap_create(10);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
|
||||||
char * c = strdup(argv[i]);
|
|
||||||
|
|
||||||
char * name;
|
|
||||||
char * value;
|
|
||||||
|
|
||||||
name = c;
|
|
||||||
value = NULL;
|
|
||||||
/* Find the first = and replace it with a null */
|
|
||||||
char * v = c;
|
|
||||||
while (*v) {
|
|
||||||
if (*v == '=') {
|
|
||||||
*v = '\0';
|
|
||||||
v++;
|
|
||||||
value = v;
|
|
||||||
goto _break;
|
|
||||||
}
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_break:
|
|
||||||
hashmap_set(args, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(arg);
|
|
||||||
free(out);
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
@ -67,69 +67,13 @@ static void say_hello(void) {
|
|||||||
update_message(hello_msg);
|
update_message(hello_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tokenize(char * str, char * sep, char **buf) {
|
#include "../kernel/misc/args.c"
|
||||||
char * pch_i;
|
|
||||||
char * save_i;
|
|
||||||
int argc = 0;
|
|
||||||
pch_i = strtok_r(str,sep,&save_i);
|
|
||||||
if (!pch_i) { return 0; }
|
|
||||||
while (pch_i != NULL) {
|
|
||||||
buf[argc] = (char *)pch_i;
|
|
||||||
++argc;
|
|
||||||
pch_i = strtok_r(NULL,sep,&save_i);
|
|
||||||
}
|
|
||||||
buf[argc] = NULL;
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static hashmap_t * get_cmdline(void) {
|
static hashmap_t * get_cmdline(void) {
|
||||||
int fd = open("/proc/cmdline", O_RDONLY);
|
char * results = args_from_procfs();
|
||||||
char * out = malloc(1024);
|
if (results) free(results);
|
||||||
size_t r = read(fd, out, 1024);
|
return kernel_args_map;
|
||||||
out[r] = '\0';
|
|
||||||
if (out[r-1] == '\n') {
|
|
||||||
out[r-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
char * arg = strdup(out);
|
|
||||||
char * argv[1024];
|
|
||||||
int argc = tokenize(arg, " ", argv);
|
|
||||||
|
|
||||||
/* New let's parse the tokens into the arguments list so we can index by key */
|
|
||||||
|
|
||||||
hashmap_t * args = hashmap_create(10);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
|
||||||
char * c = strdup(argv[i]);
|
|
||||||
|
|
||||||
char * name;
|
|
||||||
char * value;
|
|
||||||
|
|
||||||
name = c;
|
|
||||||
value = NULL;
|
|
||||||
/* Find the first = and replace it with a null */
|
|
||||||
char * v = c;
|
|
||||||
while (*v) {
|
|
||||||
if (*v == '=') {
|
|
||||||
*v = '\0';
|
|
||||||
v++;
|
|
||||||
value = v;
|
|
||||||
goto _break;
|
|
||||||
}
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_break:
|
|
||||||
hashmap_set(args, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(arg);
|
|
||||||
free(out);
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
if (getuid() != 0) {
|
if (getuid() != 0) {
|
||||||
fprintf(stderr, "%s: only root should run this\n", argv[0]);
|
fprintf(stderr, "%s: only root should run this\n", argv[0]);
|
||||||
|
@ -39,7 +39,7 @@ char * LINK_TEXT = "https://toaruos.org - https://github.com/klange/toaruos";
|
|||||||
/* Boot command line strings */
|
/* Boot command line strings */
|
||||||
#define DEFAULT_ROOT_CMDLINE "root=/dev/ram0 "
|
#define DEFAULT_ROOT_CMDLINE "root=/dev/ram0 "
|
||||||
#define DEFAULT_GRAPHICAL_CMDLINE "start=live-session "
|
#define DEFAULT_GRAPHICAL_CMDLINE "start=live-session "
|
||||||
#define DEFAULT_SINGLE_CMDLINE "start=terminal\037-F "
|
#define DEFAULT_SINGLE_CMDLINE "start=\"terminal -F\" "
|
||||||
#define DEFAULT_TEXT_CMDLINE "start=--vga vid=text "
|
#define DEFAULT_TEXT_CMDLINE "start=--vga vid=text "
|
||||||
#define DEFAULT_VID_CMDLINE "vid=auto "
|
#define DEFAULT_VID_CMDLINE "vid=auto "
|
||||||
#define MIGRATE_CMDLINE "migrate "
|
#define MIGRATE_CMDLINE "migrate "
|
||||||
|
@ -6,14 +6,34 @@
|
|||||||
* hard disk partition should be mounted as root. We parse them
|
* hard disk partition should be mounted as root. We parse them
|
||||||
* into a hash table for easy lookup by key.
|
* into a hash table for easy lookup by key.
|
||||||
*
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @copyright This file is part of ToaruOS and is released under the terms
|
* @copyright This file is part of ToaruOS and is released under the terms
|
||||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||||
* Copyright (C) 2011-2021 K. Lange
|
* Copyright (C) 2011-2023 K. Lange
|
||||||
*/
|
*/
|
||||||
#include <kernel/string.h>
|
#ifdef _KERNEL_
|
||||||
#include <kernel/args.h>
|
# include <kernel/string.h>
|
||||||
#include <kernel/tokenize.h>
|
# include <kernel/args.h>
|
||||||
#include <kernel/hashmap.h>
|
# include <kernel/tokenize.h>
|
||||||
|
# include <kernel/hashmap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
hashmap_t * kernel_args_map = NULL;
|
hashmap_t * kernel_args_map = NULL;
|
||||||
|
|
||||||
@ -43,43 +63,94 @@ char * args_value(const char * karg) {
|
|||||||
*
|
*
|
||||||
* @param arg A string containing all arguments, separated by spaces.
|
* @param arg A string containing all arguments, separated by spaces.
|
||||||
*/
|
*/
|
||||||
void args_parse(const char * _arg) {
|
void args_parse(const char * cmdline) {
|
||||||
/* Sanity check... */
|
/* Sanity check... */
|
||||||
if (!_arg) { return; }
|
if (!cmdline) { return; }
|
||||||
|
if (!kernel_args_map) { kernel_args_map = hashmap_create(10); }
|
||||||
|
char * argbuf = strdup(cmdline);
|
||||||
|
char * x = argbuf;
|
||||||
|
|
||||||
char * arg = strdup(_arg);
|
for (;;) {
|
||||||
char * argv[1024];
|
while (*x && *x == ' ') x++; /* skip spaces */
|
||||||
int argc = tokenize(arg, " ", argv);
|
if (!*x) break;
|
||||||
|
|
||||||
/* New let's parse the tokens into the arguments list so we can index by key */
|
char * value = NULL;
|
||||||
if (!kernel_args_map) {
|
char * key = x;
|
||||||
kernel_args_map = hashmap_create(10);
|
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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
if (*x == '"') {
|
||||||
char * c = strdup(argv[i]);
|
*w = '\0';
|
||||||
|
x++;
|
||||||
char * name;
|
} else if (*x == '\0') {
|
||||||
char * value;
|
goto _parse_error;
|
||||||
|
|
||||||
name = c;
|
|
||||||
value = NULL;
|
|
||||||
/* Find the first = and replace it with a null */
|
|
||||||
char * v = c;
|
|
||||||
while (*v) {
|
|
||||||
if (*v == '=') {
|
|
||||||
*v = '\0';
|
|
||||||
v++;
|
|
||||||
value = v;
|
|
||||||
goto _break;
|
|
||||||
}
|
}
|
||||||
v++;
|
} else {
|
||||||
|
/* Start of unquoted value */
|
||||||
|
value = x;
|
||||||
|
while (*x && *x != ' ') x++;
|
||||||
|
if (*x == ' ') {
|
||||||
|
*x = '\0';
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (*x == ' ') {
|
||||||
|
/* Value-less argument where we need to set nil byte */
|
||||||
|
*x++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
_break:
|
hashmap_set(kernel_args_map, key, value ? strdup(value) : NULL);
|
||||||
hashmap_set(kernel_args_map, name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(arg);
|
_parse_error:
|
||||||
|
free(argbuf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user