xref: /haiku/src/system/kernel/debug/safemode_settings.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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
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
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
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
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
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
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
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
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
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