1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cmdline.h>
6 
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "osboot.h"
12 
13 #include <stdio.h>
14 
15 #define CMDLINE_MAX_ITEMS 128
16 #define CMDLINE_MAX_STRINGDATA (PAGE_SIZE * 3)
17 
18 static char buffer[CMDLINE_MAX_STRINGDATA];
19 static size_t buffer_next = 0;
20 
21 typedef struct {
22     char* key;
23     char* val;
24     size_t klen;
25     size_t vlen;
26 } kv_t;
27 
28 static kv_t entry[CMDLINE_MAX_ITEMS];
29 static size_t entry_count;
30 
cmdline_to_string(char * ptr,size_t max)31 size_t cmdline_to_string(char* ptr, size_t max) {
32     char* start = ptr;
33 
34     if (max == 0) {
35         return 0;
36     }
37 
38     for (size_t n = 0; n < entry_count; n++) {
39         if ((entry[n].klen + entry[n].vlen + 3) > max) {
40             // require space for: space + key + equal + value + null
41             break;
42         }
43         if (n > 0) {
44             *ptr++ = ' ';
45             max--;
46         }
47         memcpy(ptr, entry[n].key, entry[n].klen);
48         ptr += entry[n].klen;
49         max -= entry[n].klen;
50         if (entry[n].vlen) {
51             *ptr++ = '=';
52             max--;
53             memcpy(ptr, entry[n].val, entry[n].vlen);
54             ptr += entry[n].vlen;
55             max -= entry[n].vlen;
56         }
57     }
58     *ptr++ = 0;
59     return ptr - start;
60 }
61 
entry_add(const char * key,size_t klen,const char * val,size_t vlen)62 static void entry_add(const char* key, size_t klen, const char* val, size_t vlen) {
63     if (klen == 0) {
64         // empty keys are not allowed
65         return;
66     }
67 
68     if ((klen > 1024) || (vlen > 1024)) {
69         // huge keys and values are not allowed
70         return;
71     }
72 
73     if ((sizeof(buffer) - buffer_next) < (klen + vlen + 2)) {
74         // give up if it won't fit
75         return;
76     }
77 
78     size_t n;
79     for (n = 0; n < entry_count; n++) {
80         if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) {
81             goto write_value;
82         }
83     }
84     if (n == CMDLINE_MAX_ITEMS) {
85         // no space in table
86         return;
87     }
88 
89     // new entry
90     entry_count++;
91     entry[n].key = buffer + buffer_next;
92     entry[n].klen = klen;
93     memcpy(entry[n].key, key, klen);
94     entry[n].key[klen] = 0;
95     buffer_next += klen + 1;
96 
97 write_value:
98     entry[n].val = buffer + buffer_next;
99     entry[n].vlen = vlen;
100     memcpy(entry[n].val, val, vlen);
101     entry[n].val[vlen] = 0;
102     buffer_next += vlen + 1;
103 }
104 
cmdline_set(const char * key,const char * val)105 void cmdline_set(const char* key, const char* val) {
106     entry_add(key, strlen(key), val, strlen(val));
107 }
108 
cmdline_append(const char * ptr,size_t len)109 void cmdline_append(const char* ptr, size_t len) {
110     const char* key;
111     const char* val;
112 
113 restart:
114     while (len > 0) {
115         if (isspace(*ptr)) {
116             ptr++;
117             len--;
118             continue;
119         }
120         key = ptr;
121         while (len > 0) {
122             if (*ptr == '=') {
123                 size_t klen = ptr - key;
124                 ptr++;
125                 len--;
126                 val = ptr;
127                 while ((len > 0) && !isspace(*ptr)) {
128                     len--;
129                     ptr++;
130                 }
131                 size_t vlen = ptr - val;
132                 entry_add(key, klen, val, vlen);
133                 goto restart;
134             }
135             if (isspace(*ptr)) {
136                 break;
137             }
138             ptr++;
139             len--;
140         }
141         size_t klen = ptr - key;
142         entry_add(key, klen, NULL, 0);
143     }
144 }
145 
cmdline_get(const char * key,const char * _default)146 const char* cmdline_get(const char* key, const char* _default) {
147     size_t klen = strlen(key);
148     for (size_t n = 0; n < entry_count; n++) {
149         if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) {
150             return entry[n].val;
151         }
152     }
153     return _default;
154 }
155 
cmdline_get_uint32(const char * key,uint32_t _default)156 uint32_t cmdline_get_uint32(const char* key, uint32_t _default) {
157     const char* val = cmdline_get(key, NULL);
158     if (val == NULL) {
159         return _default;
160     }
161     return atol(val);
162 }
163