summaryrefslogtreecommitdiffstats
path: root/src/util/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/util.c')
-rw-r--r--src/util/util.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/src/util/util.c b/src/util/util.c
new file mode 100644
index 0000000..b3498df
--- /dev/null
+++ b/src/util/util.c
@@ -0,0 +1,306 @@
+// 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.\n");
+ 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;
+}