1#include "internal.h"
2
3#define CMDLINE_MAX_TREE_DEPTH 16
4
5void cmdline_functional_name(const struct cmdline_entry *ent,
6 char name_out[CMDLINE_ENTRY_NAME_LEN_MAX]) {
7 const struct cmdline_entry *chain[CMDLINE_MAX_TREE_DEPTH];
8 size_t depth = 0;
9
10 for (const struct cmdline_entry *curr = ent; curr != NULL;
11 curr = curr->parent) {
12 kassert(depth < CMDLINE_MAX_TREE_DEPTH);
13 chain[depth++] = curr;
14 }
15
16 size_t idx = 0;
17 for (size_t i = depth; i > 0; i--) {
18 const struct cmdline_entry *node = chain[i - 1];
19 size_t len = strlen(str: node->name);
20 if (idx + len >= CMDLINE_ENTRY_NAME_LEN_MAX - 1)
21 len = (CMDLINE_ENTRY_NAME_LEN_MAX - 1 > idx)
22 ? (CMDLINE_ENTRY_NAME_LEN_MAX - 1 - idx)
23 : 0;
24
25 memcpy(name_out + idx, node->name, len);
26 idx += len;
27
28 if (i > 1 && idx < CMDLINE_ENTRY_NAME_LEN_MAX - 1)
29 name_out[idx++] = '.';
30 }
31 name_out[idx] = '\0';
32}
33
34void cmdline_check_for_duplicates(void) {
35 size_t count =
36 (size_t) (__ekernel_cmdline_entries - __skernel_cmdline_entries);
37 if (count == 0)
38 return;
39
40 char (*names)[CMDLINE_ENTRY_NAME_LEN_MAX] =
41 kmalloc_or_die(count * sizeof(*names));
42
43 for (size_t i = 0; i < count; i++) {
44 cmdline_functional_name(ent: &__skernel_cmdline_entries[i], name_out: names[i]);
45 }
46
47 size_t dupes = 0;
48 for (size_t i = 0; i < count; i++) {
49 const char *name_a = names[i];
50
51 for (size_t j = i + 1; j < count; j++) {
52 const char *name_b = names[j];
53
54 if (strcmp(str1: name_a, str2: name_b) == 0) {
55 log_msg(LOG_ERROR, "duplicate command line entry: %s", name_a);
56 dupes++;
57 }
58 }
59 }
60
61 kfree(names);
62
63 if (dupes)
64 panic("%zu duplicate command line entries", dupes);
65}
66
67void cmdline_check_for_unfilled(void) {
68 size_t found = 0;
69 for (struct cmdline_entry *e = __skernel_cmdline_entries;
70 e < __ekernel_cmdline_entries; e++) {
71 if ((e->flags & CMDLINE_ENTRY_REQUIRED) &&
72 e->status == CMDLINE_ENTRY_NOT_FOUND) {
73 char name[CMDLINE_ENTRY_NAME_LEN_MAX];
74 cmdline_functional_name(ent: e, name_out: name);
75 log_msg(LOG_ERROR, "Required command line entry %s not present",
76 name);
77 found++;
78 }
79 }
80 if (found)
81 panic("%zu required command line entries not present", found);
82}
83
84void cmdline_apply_defaults(void) {
85 for (struct cmdline_entry *e = __skernel_cmdline_entries;
86 e < __ekernel_cmdline_entries; e++) {
87 if (e->status == CMDLINE_ENTRY_NOT_FOUND && e->default_val) {
88 char name[CMDLINE_ENTRY_NAME_LEN_MAX];
89 cmdline_functional_name(ent: e, name_out: name);
90
91 dispatch_parse_value(e, name, var: name, val: e->default_val);
92 e->status = CMDLINE_ENTRY_DEFAULTED;
93 log_msg(LOG_INFO, "command line entry '%s' defaulted to '%s'", name,
94 e->default_val);
95 }
96 }
97}
98
99void cmdline_print_all(void) {
100#ifdef DEBUG_CMDLINE
101 for (struct cmdline_entry *e = __skernel_cmdline_entries;
102 e < __ekernel_cmdline_entries; e++) {
103 if (e->flags & CMDLINE_ENTRY_SYMBOLIC)
104 continue;
105
106 char name[CMDLINE_ENTRY_NAME_LEN_MAX];
107 cmdline_functional_name(e, name);
108 log_msg(LOG_INFO, "command line entry %s", name);
109 }
110#endif
111}
112