You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

306 lines
9.6 KiB

// SPDX-License-Identifier: GPL-2.0
// Parts are copied from the linux kernel
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
// CODE FROM LINUX KERNEL START
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
#define _D 0x04 /* digit */
#define _C 0x08 /* cntrl */
#define _P 0x10 /* punct */
#define _S 0x20 /* white space (space/lf/tab) */
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
const unsigned char _ctype[] = {
_C, _C, _C, _C, _C, _C, _C, _C, /* 0-7 */
_C, _C | _S, _C | _S, _C | _S, _C | _S, _C | _S, _C, _C, /* 8-15 */
_C, _C, _C, _C, _C, _C, _C, _C, /* 16-23 */
_C, _C, _C, _C, _C, _C, _C, _C, /* 24-31 */
_S | _SP, _P, _P, _P, _P, _P, _P, _P, /* 32-39 */
_P, _P, _P, _P, _P, _P, _P, _P, /* 40-47 */
_D, _D, _D, _D, _D, _D, _D, _D, /* 48-55 */
_D, _D, _P, _P, _P, _P, _P, _P, /* 56-63 */
_P, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U, /* 64-71 */
_U, _U, _U, _U, _U, _U, _U, _U, /* 72-79 */
_U, _U, _U, _U, _U, _U, _U, _U, /* 80-87 */
_U, _U, _U, _P, _P, _P, _P, _P, /* 88-95 */
_P, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L, /* 96-103 */
_L, _L, _L, _L, _L, _L, _L, _L, /* 104-111 */
_L, _L, _L, _L, _L, _L, _L, _L, /* 112-119 */
_L, _L, _L, _P, _P, _P, _P, _C, /* 120-127 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
_S | _SP, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, /* 160-175 */
_P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, /* 176-191 */
_U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, /* 192-207 */
_U, _U, _U, _U, _U, _U, _U, _P, _U, _U, _U, _U, _U, _U, _U, _L, /* 208-223 */
_L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, /* 224-239 */
_L, _L, _L, _L, _L, _L, _L, _P, _L, _L, _L, _L, _L, _L, _L, _L /* 240-255 */
};
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define kernel_isspace(c) ((__ismask(c)&(_S)) != 0)
static char *skip_spaces(const char *str)
{
while (kernel_isspace(*str))
++str;
return (char *)str;
}
/*
* Parse a string to get a param value pair.
* You can use " around spaces, but can't escape ".
* Hyphens and underscores equivalent in parameter names.
*/
static char *next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0, quoted = 0;
char *next;
if (*args == '"') {
args++;
in_quote = 1;
quoted = 1;
}
for (i = 0; args[i]; i++) {
if (kernel_isspace(args[i]) && !in_quote)
break;
if (equals == 0) {
if (args[i] == '=')
equals = i;
}
if (args[i] == '"')
in_quote = !in_quote;
}
*param = args;
if (!equals)
*val = NULL;
else {
args[equals] = '\0';
*val = args + equals + 1;
/* Don't include quotes in value. */
if (**val == '"') {
(*val)++;
if (args[i - 1] == '"')
args[i - 1] = '\0';
}
}
if (quoted && args[i - 1] == '"')
args[i - 1] = '\0';
if (args[i]) {
args[i] = '\0';
next = args + i + 1;
} else
next = args + i;
/* Chew up trailing spaces. */
return skip_spaces(next);
}
// CODE FROM LINUX KERNEL STOP
enum EXEC_MODE {
UNDEFINED,
GETARG,
GETARGS,
};
static void usage(enum EXEC_MODE enumExecMode, int ret, char *msg)
{
switch (enumExecMode) {
case UNDEFINED:
fprintf(stderr, "ERROR: 'dracut-util' has to be called via a symlink to the tool name.");
break;
case GETARG:
fprintf(stderr, "ERROR: %s\nUsage: dracut-getarg <KEY>[=[<VALUE>]]\n", msg);
break;
case GETARGS:
fprintf(stderr, "ERROR: %s\nUsage: dracut-getargs <KEY>[=]\n", msg);
break;
}
exit(ret);
}
#define ARGV0_GETARG "dracut-getarg"
#define ARGV0_GETARGS "dracut-getargs"
static enum EXEC_MODE get_mode(const char *argv_0)
{
struct _mode_table {
enum EXEC_MODE mode;
const char *arg;
size_t arg_len;
const char *s_arg;
} modeTable[] = {
{GETARG, ARGV0_GETARG, sizeof(ARGV0_GETARG), "/" ARGV0_GETARG},
{GETARGS, ARGV0_GETARGS, sizeof(ARGV0_GETARGS), "/" ARGV0_GETARGS},
{UNDEFINED, NULL, 0, NULL}
};
int i;
size_t argv_0_len = strlen(argv_0);
if (!argv_0_len)
return UNDEFINED;
for (i = 0; modeTable[i].mode != UNDEFINED; i++) {
if (argv_0_len == (modeTable[i].arg_len - 1)) {
if (strncmp(argv_0, modeTable[i].arg, argv_0_len) == 0) {
return modeTable[i].mode;
}
}
if (modeTable[i].arg_len > argv_0_len)
continue;
if (strncmp(argv_0 + argv_0_len - modeTable[i].arg_len, modeTable[i].s_arg, modeTable[i].arg_len) == 0)
return modeTable[i].mode;
}
return UNDEFINED;
}
static int getarg(int argc, char **argv)
{
char *search_key;
char *search_value;
char *end_value = NULL;
bool bool_value = false;
char *cmdline = NULL;
char *p = getenv("CMDLINE");
if (p == NULL) {
usage(GETARG, EXIT_FAILURE, "CMDLINE env not set");
}
cmdline = strdup(p);
if (argc != 2) {
usage(GETARG, EXIT_FAILURE, "Number of arguments invalid");
}
search_key = argv[1];
search_value = strchr(argv[1], '=');
if (search_value != NULL) {
*search_value = 0;
search_value++;
if (*search_value == 0)
search_value = NULL;
}
if (strlen(search_key) == 0)
usage(GETARG, EXIT_FAILURE, "search key undefined");
do {
char *key = NULL, *value = NULL;
cmdline = next_arg(cmdline, &key, &value);
if (strcmp(key, search_key) == 0) {
if (value) {
end_value = value;
bool_value = -1;
} else {
end_value = NULL;
bool_value = true;
}
}
} while (cmdline[0]);
if (search_value) {
if (end_value && strcmp(end_value, search_value) == 0) {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
if (end_value) {
// includes "=0"
puts(end_value);
return EXIT_SUCCESS;
}
if (bool_value) {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
static int getargs(int argc, char **argv)
{
char *search_key;
char *search_value;
bool found_value = false;
char *cmdline = NULL;
char *p = getenv("CMDLINE");
if (p == NULL) {
usage(GETARGS, EXIT_FAILURE, "CMDLINE env not set");
}
cmdline = strdup(p);
if (argc != 2) {
usage(GETARGS, EXIT_FAILURE, "Number of arguments invalid");
}
search_key = argv[1];
search_value = strchr(argv[1], '=');
if (search_value != NULL) {
*search_value = 0;
search_value++;
if (*search_value == 0)
search_value = NULL;
}
if (strlen(search_key) == 0)
usage(GETARGS, EXIT_FAILURE, "search key undefined");
do {
char *key = NULL, *value = NULL;
cmdline = next_arg(cmdline, &key, &value);
if (strcmp(key, search_key) == 0) {
if (search_value) {
if (strcmp(value, search_value) == 0) {
printf("%s\n", value);
found_value = true;
}
} else {
if (value) {
printf("%s\n", value);
} else {
puts(key);
}
found_value = true;
}
}
} while (cmdline[0]);
return found_value ? EXIT_SUCCESS : EXIT_FAILURE;
}
int main(int argc, char **argv)
{
switch (get_mode(argv[0])) {
case UNDEFINED:
usage(UNDEFINED, EXIT_FAILURE, NULL);
break;
case GETARG:
return getarg(argc, argv);
case GETARGS:
return getargs(argc, argv);
}
return EXIT_FAILURE;
}