1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <kernel/cmdline.h>
8 
9 #include <stdbool.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 char __kernel_cmdline[CMDLINE_MAX];
14 size_t __kernel_cmdline_size;
15 size_t __kernel_cmdline_count;
16 
17 // import into kernel commandline, converting invalid
18 // characters to '.', combining multiple spaces, and
19 // converting into a \0 separated, \0\0 terminated
20 // style environment string
cmdline_append(const char * data)21 void cmdline_append(const char* data) {
22     if (data == NULL || *data == 0) {
23         return;
24     }
25 
26     size_t i = __kernel_cmdline_size;
27     if (i == CMDLINE_MAX) {
28         return;
29     }
30 
31     // if there is a double-null terminator at i, then step back
32     if (i > 1) {
33         if (__kernel_cmdline[i] == 0 && __kernel_cmdline[i - 1] == 0) {
34             i--;
35         }
36     }
37     size_t max = CMDLINE_MAX - 2;
38 
39     // if the existing arguments are missing a null separator, add one
40     if (i < max && i > 0 && __kernel_cmdline[i] != 0) {
41         i++; // i should have always been null, but it wasn't
42         __kernel_cmdline[i++] = 0;
43     }
44 
45     bool found_equal = false;
46     while (i < max) {
47         unsigned c = *data++;
48         if (c == 0) {
49             // finish an in-progress argument
50             if (__kernel_cmdline[i - 1] != 0) {
51                 if (!found_equal) {
52                     __kernel_cmdline[i++] = '=';
53                 }
54                 __kernel_cmdline[i++] = 0;
55                 __kernel_cmdline_count++;
56             }
57             break;
58         }
59         if (c == '=') {
60             found_equal = true;
61         }
62         if ((c < ' ') || (c > 127)) {
63             if ((c == '\n') || (c == '\r') || (c == '\t')) {
64                 c = ' ';
65             } else {
66                 c = '.';
67             }
68         }
69         if (c == ' ') {
70             // spaces become \0's, but do not double up
71             if ((i == 0) || (__kernel_cmdline[i - 1] == 0)) {
72                 continue;
73             } else {
74                 if (!found_equal && i < max) {
75                     __kernel_cmdline[i++] = '=';
76                 }
77                 c = 0;
78                 found_equal = false;
79                 ++__kernel_cmdline_count;
80             }
81         }
82         __kernel_cmdline[i++] = static_cast<char>(c);
83     }
84 
85     // ensure a double-\0 terminator
86     __kernel_cmdline[i++] = 0;
87     __kernel_cmdline[i] = 0;
88     __kernel_cmdline_size = i;
89 }
90 
cmdline_get(const char * key)91 const char* cmdline_get(const char* key) {
92     if (!key) {
93         return __kernel_cmdline;
94     }
95     size_t sz = strlen(key);
96     const char* ptr = __kernel_cmdline;
97     for (;;) {
98         if (!strncmp(ptr, key, sz) && (ptr[sz] == '=' || ptr[sz] == '\0')) {
99             break;
100         }
101         ptr = strchr(ptr, 0) + 1;
102         if (*ptr == 0) {
103             return NULL;
104         }
105     }
106     ptr += sz;
107     if (*ptr == '=') {
108         ptr++;
109     }
110     return ptr;
111 }
112 
cmdline_get_bool(const char * key,bool _default)113 bool cmdline_get_bool(const char* key, bool _default) {
114     const char* value = cmdline_get(key);
115     if (value == NULL) {
116         return _default;
117     }
118     if ((strcmp(value, "0") == 0) ||
119         (strcmp(value, "false") == 0) ||
120         (strcmp(value, "off") == 0)) {
121         return false;
122     }
123     return true;
124 }
125 
cmdline_get_uint32(const char * key,uint32_t _default)126 uint32_t cmdline_get_uint32(const char* key, uint32_t _default) {
127     const char* value_str = cmdline_get(key);
128     if (value_str == NULL || *value_str == '\0') {
129         return _default;
130     }
131 
132     char* end;
133     auto res = strtol(value_str, &end, 0);
134     uint32_t value = (res < 0) ? _default : static_cast<uint32_t>(res);
135     if (*end != '\0') {
136         return _default;
137     }
138     return value;
139 }
140 
cmdline_get_uint64(const char * key,uint64_t _default)141 uint64_t cmdline_get_uint64(const char* key, uint64_t _default) {
142     const char* value_str = cmdline_get(key);
143     if (value_str == NULL || *value_str == '\0') {
144         return _default;
145     }
146 
147     char* end;
148     long long value = strtoll(value_str, &end, 0);
149     if (*end != '\0') {
150         return _default;
151     }
152     return value;
153 }
154