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