1 /*
2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <safemode.h>
8
9 #include <ctype.h>
10 #include <string.h>
11 #include <strings.h>
12
13 #include <algorithm>
14
15 #include <KernelExport.h>
16
17 #include <boot/kernel_args.h>
18 #include <kernel.h>
19 #include <syscalls.h>
20
21
22 #ifndef _BOOT_MODE
23
24
25 static status_t
get_option_from_kernel_args(kernel_args * args,const char * settingsName,const char * parameter,size_t parameterLength,char * buffer,size_t * _bufferSize)26 get_option_from_kernel_args(kernel_args* args, const char* settingsName,
27 const char* parameter, size_t parameterLength, char* buffer,
28 size_t* _bufferSize)
29 {
30 // find the settings in the kernel args
31 const char* settings = NULL;
32 for (driver_settings_file* file = args->driver_settings;
33 file != NULL; file = file->next) {
34 if (strcmp(settingsName, file->name) == 0) {
35 settings = file->buffer;
36 break;
37 }
38 }
39
40 if (settings == NULL)
41 return B_ENTRY_NOT_FOUND;
42
43 // Unfortunately we can't just use parse_driver_settings_string(), since
44 // we might not have a working heap yet. So we do very limited parsing
45 // ourselves.
46 const char* settingsEnd = settings + strlen(settings);
47 int32 parameterLevel = 0;
48
49 while (*settings != '\0') {
50 // find end of line
51 const char* lineEnd = strchr(settings, '\n');
52 const char* nextLine;
53 if (lineEnd != NULL)
54 nextLine = lineEnd + 1;
55 else
56 nextLine = lineEnd = settingsEnd;
57
58 // ignore any trailing comments
59 lineEnd = std::find(settings, lineEnd, '#');
60
61 const char* nameStart = NULL;
62 const char* nameEnd = NULL;
63 const char* valueStart = NULL;
64 const char* valueEnd = NULL;
65 const char** elementEnd = NULL;
66 bool sawSeparator = true;
67
68 for (; settings < lineEnd; settings++) {
69 switch (*settings) {
70 case '{':
71 parameterLevel++;
72 sawSeparator = true;
73 break;
74
75 case '}':
76 parameterLevel--;
77 sawSeparator = true;
78 break;
79
80 case ';':
81 // TODO: That's not correct. There should be another loop.
82 sawSeparator = true;
83 break;
84
85 default:
86 if (parameterLevel != 0)
87 break;
88
89 if (isspace(*settings)) {
90 sawSeparator = true;
91 break;
92 }
93
94 if (!sawSeparator)
95 break;
96
97 sawSeparator = false;
98
99 if (nameStart == NULL) {
100 nameStart = settings;
101 elementEnd = &nameEnd;
102 } else if (valueStart == NULL) {
103 valueStart = settings;
104 elementEnd = &valueEnd;
105 }
106 break;
107 }
108
109 if (sawSeparator && elementEnd != NULL) {
110 *elementEnd = settings;
111 elementEnd = NULL;
112 }
113 }
114
115 if (elementEnd != NULL)
116 *elementEnd = settings;
117
118 if (nameStart != NULL && size_t(nameEnd - nameStart) == parameterLength
119 && strncmp(parameter, nameStart, parameterLength) == 0) {
120 if (valueStart == NULL)
121 return B_NAME_NOT_FOUND;
122
123 size_t length = valueEnd - valueStart;
124 if (*_bufferSize > 0) {
125 size_t toCopy = std::min(length, *_bufferSize - 1);
126 memcpy(buffer, valueStart, toCopy);
127 buffer[toCopy] = '\0';
128 }
129
130 *_bufferSize = length;
131 return B_OK;
132 }
133
134 settings = nextLine;
135 }
136
137 return B_NAME_NOT_FOUND;
138 }
139
140
141 #endif // !_BOOT_MODE
142
143
144 static status_t
get_option(kernel_args * args,const char * settingsName,const char * parameter,size_t parameterLength,char * buffer,size_t * _bufferSize)145 get_option(kernel_args* args, const char* settingsName, const char* parameter,
146 size_t parameterLength, char* buffer, size_t* _bufferSize)
147 {
148 #ifndef _BOOT_MODE
149 if (args != NULL) {
150 return get_option_from_kernel_args(args, settingsName, parameter,
151 parameterLength, buffer, _bufferSize);
152 }
153 #endif
154
155 void* handle = load_driver_settings(settingsName);
156 if (handle == NULL)
157 return B_ENTRY_NOT_FOUND;
158
159 status_t status = B_NAME_NOT_FOUND;
160
161 const char* value = get_driver_parameter(handle, parameter, NULL, NULL);
162 if (value != NULL) {
163 *_bufferSize = strlcpy(buffer, value, *_bufferSize);
164 status = B_OK;
165 }
166
167 unload_driver_settings(handle);
168 return status;
169 }
170
171
172 static status_t
get_option(kernel_args * args,const char * parameter,char * buffer,size_t * _bufferSize)173 get_option(kernel_args* args, const char* parameter, char* buffer,
174 size_t* _bufferSize)
175 {
176 size_t parameterLength = strlen(parameter);
177 status_t status = get_option(args, B_SAFEMODE_DRIVER_SETTINGS, parameter,
178 parameterLength, buffer, _bufferSize);
179 if (status != B_OK) {
180 // Try kernel settings file as a fall back
181 status = get_option(args, "kernel", parameter, parameterLength, buffer,
182 _bufferSize);
183 }
184
185 return status;
186 }
187
188
189 static bool
get_boolean(kernel_args * args,const char * parameter,bool defaultValue)190 get_boolean(kernel_args* args, const char* parameter, bool defaultValue)
191 {
192 char value[16];
193 size_t length = sizeof(value);
194
195 if (get_option(args, parameter, value, &length) != B_OK)
196 return defaultValue;
197
198 return !strcasecmp(value, "on") || !strcasecmp(value, "true")
199 || !strcmp(value, "1") || !strcasecmp(value, "yes")
200 || !strcasecmp(value, "enabled");
201 }
202
203
204 // #pragma mark -
205
206
207 status_t
get_safemode_option(const char * parameter,char * buffer,size_t * _bufferSize)208 get_safemode_option(const char* parameter, char* buffer, size_t* _bufferSize)
209 {
210 return get_option(NULL, parameter, buffer, _bufferSize);
211 }
212
213
214 bool
get_safemode_boolean(const char * parameter,bool defaultValue)215 get_safemode_boolean(const char* parameter, bool defaultValue)
216 {
217 return get_boolean(NULL, parameter, defaultValue);
218 }
219
220
221 #ifndef _BOOT_MODE
222
223
224 status_t
get_safemode_option_early(kernel_args * args,const char * parameter,char * buffer,size_t * _bufferSize)225 get_safemode_option_early(kernel_args* args, const char* parameter,
226 char* buffer, size_t* _bufferSize)
227 {
228 return get_option(args, parameter, buffer, _bufferSize);
229 }
230
231
232 bool
get_safemode_boolean_early(kernel_args * args,const char * parameter,bool defaultValue)233 get_safemode_boolean_early(kernel_args* args, const char* parameter,
234 bool defaultValue)
235 {
236 return get_boolean(args, parameter, defaultValue);
237 }
238
239
240 #endif // _BOOT_MODE
241
242
243 // #pragma mark - syscalls
244
245
246 #ifndef _BOOT_MODE
247
248
249 extern "C" status_t
_user_get_safemode_option(const char * userParameter,char * userBuffer,size_t * _userBufferSize)250 _user_get_safemode_option(const char* userParameter, char* userBuffer,
251 size_t* _userBufferSize)
252 {
253 char parameter[B_FILE_NAME_LENGTH];
254 char buffer[B_PATH_NAME_LENGTH];
255 size_t bufferSize, originalBufferSize;
256
257 if (!IS_USER_ADDRESS(userParameter) || !IS_USER_ADDRESS(userBuffer)
258 || !IS_USER_ADDRESS(_userBufferSize)
259 || user_memcpy(&bufferSize, _userBufferSize, sizeof(size_t)) != B_OK
260 || user_strlcpy(parameter, userParameter, B_FILE_NAME_LENGTH) < B_OK)
261 return B_BAD_ADDRESS;
262
263 if (bufferSize > B_PATH_NAME_LENGTH)
264 bufferSize = B_PATH_NAME_LENGTH;
265
266 originalBufferSize = bufferSize;
267 status_t status = get_safemode_option(parameter, buffer, &bufferSize);
268
269 if (status == B_OK
270 && (user_strlcpy(userBuffer, buffer, originalBufferSize) < B_OK
271 || user_memcpy(_userBufferSize, &bufferSize, sizeof(size_t))
272 != B_OK))
273 return B_BAD_ADDRESS;
274
275 return status;
276 }
277
278
279 #endif // !_BOOT_MODE
280