Fix build error by adding -fno-stack-protector to CFLAGS in usr/LBuild (#63)
[lunaix-os.git] / lunaix-os / kernel / kcmd.c
1 #include <lunaix/kcmd.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/spike.h>
5
6 #include <klibc/string.h>
7
8 LOG_MODULE("kcmd");
9
10 struct substr {
11     int pos;
12     size_t len;
13 };
14
15 struct extractor {
16     char* cmdline;
17     int pos;
18
19     struct substr key;
20     struct substr val;
21 };
22
23 static DECLARE_HASHTABLE(options, 8);
24
25 static bool
26 extract_next_option(struct extractor* ctx) 
27 {
28 #define is_valid_char(c) ((unsigned int)(((c) & ~0x80) - 'A') < 'Z')
29 #define PARSE_KEY 0
30 #define PARSE_VAL 1
31     char c;
32     int i = ctx->pos, state = PARSE_KEY;
33     struct substr* s = &ctx->key;
34     s->len = 0;
35     s->pos = i;
36
37     if (!ctx->cmdline[i]) {
38         return false;
39     }
40
41     while((c = ctx->cmdline[i++])) {
42         if (c == ' ') {
43             while ((c = ctx->cmdline[i++]) && c == ' ');
44             break;
45         }
46
47         if (c == '=') {
48             if (state == PARSE_KEY) {
49                 if (s->len == 0) {
50                     WARN("unexpected character: '=' (pos:%d). skipping...\n", i + 1);
51                     while ((c = ctx->cmdline[i++]) && c != ' ');
52                     break;
53                 }
54                 state = PARSE_VAL;
55                 s = &ctx->val;
56                 s->len = 0;
57                 s->pos = i;
58                 continue;
59             }
60         }
61
62         s->len++;
63     }
64
65     ctx->pos = i - 1;
66
67     return true;
68 }
69
70 #define MAX_KEYSIZE 16
71
72 void 
73 kcmd_parse_cmdline(char* cmd_line) 
74 {
75     struct extractor ctx = { .cmdline = cmd_line, .pos = 0 };
76     
77     INFO("active kcmds");
78
79     // first option is always kernel itself
80     extract_next_option(&ctx);
81
82     while (extract_next_option(&ctx)) {
83         if (!ctx.key.len) {
84             continue;
85         }
86         
87         size_t maxlen = sizeof(struct koption) - offsetof(struct koption, buf);
88
89         if (ctx.key.len >= maxlen) {
90             WARN("option key too big. skipping...\n");
91             continue;
92         }
93
94         if (ctx.val.len >= 256) {
95             WARN("option value too big. skipping...\n");
96             continue;
97         }
98
99         struct koption* kopt = 
100             (struct koption*) vzalloc(sizeof(*kopt));
101         
102         memcpy(kopt->buf, &cmd_line[ctx.key.pos], ctx.key.len);
103         
104         kopt->hashkey = HSTR(kopt->buf, ctx.key.len);
105         hstr_rehash(&kopt->hashkey, HSTR_FULL_HASH);
106
107         if (ctx.val.len) {
108             kopt->value = &kopt->buf[ctx.key.len + 1];
109             size_t max_val_len = maxlen - ctx.key.len;
110
111             // value too big to fit inplace
112             if (max_val_len <= ctx.val.len) {
113                 kopt->value = vzalloc(ctx.val.len + 1);
114             }
115
116             memcpy(kopt->value, &cmd_line[ctx.val.pos], ctx.val.len);
117             INFO("   %-10s =%s", kopt->hashkey.value, kopt->value);
118         }
119         else {
120             INFO("   %s", kopt->hashkey.value);
121         }
122         
123         hashtable_hash_in(options, &kopt->node, kopt->hashkey.hash);
124     }
125 }
126
127 bool 
128 kcmd_get_option(char* key, char** out_value) 
129 {
130     struct hstr hkey = HSTR(key, strlen(key));
131     hstr_rehash(&hkey, HSTR_FULL_HASH);
132
133     struct koption *pos, *n;
134     hashtable_hash_foreach(options, hkey.hash, pos, n, node) {
135         if (HSTR_EQ(&pos->hashkey, &hkey)) {
136             goto found;
137         }
138     }
139
140     return false;
141
142 found:
143     if (out_value) {
144         *out_value = pos->value;
145     }
146
147     return true;
148 }