xref: /haiku/src/system/libroot/os/driver_settings.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
3  * This file may be used under the terms of the MIT License.
4  */
5 
6 /*!	\brief Implements the driver settings API
7 	This file is used by three different components with different needs:
8 	  1) the boot loader
9 		Buffers a list of settings files to move over to the kernel - the
10 		actual buffering is located in the boot loader directly, though.
11 		Creates driver_settings structures out of those on demand only.
12 	  2) the kernel
13 		Maintains a list of settings so that no disk access is required
14 		for known settings (such as those passed over from the boot
15 		loader).
16 	  3) libroot.so
17 		Exports the parser to userland applications, so that they can
18 		easily make use of driver_settings styled files.
19 
20 	The file has to be recompiled for every component separately, so that
21 	it properly exports the required functionality (which is specified by
22 	_BOOT_MODE for the boot loader, and _KERNEL_MODE for the kernel).
23 */
24 
25 // The boot loader is compiled with kernel rules, but we want to explicitely
26 // differentiate between the two here.
27 #ifdef _BOOT_MODE
28 #	undef _KERNEL_MODE
29 #endif
30 
31 #include <BeBuild.h>
32 #include <directories.h>
33 #include <driver_settings.h>
34 #include <FindDirectory.h>
35 #include <OS.h>
36 
37 #ifdef _KERNEL_MODE
38 #	include <KernelExport.h>
39 #	include <util/list.h>
40 #	include <lock.h>
41 #	include <kdriver_settings.h>
42 #	include <kernel.h>
43 #	include <boot/kernel_args.h>
44 #	include <boot_device.h>
45 #endif
46 #ifdef _BOOT_MODE
47 #	include <boot/kernel_args.h>
48 #	include <boot/stage2.h>
49 #else
50 #	include <find_directory_private.h>
51 #endif
52 
53 #include <stdlib.h>
54 #include <string.h>
55 #include <strings.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <ctype.h>
59 
60 #ifndef B_BUFFER_OVERFLOW
61 #	define B_BUFFER_OVERFLOW B_ERROR
62 #endif
63 
64 #define SETTINGS_DIRECTORY "/kernel/drivers/"
65 #define SETTINGS_MAGIC		'DrvS'
66 
67 // Those maximum values are independent from the implementation - they
68 // have been chosen to make the code more robust against bad files
69 #define MAX_SETTINGS_SIZE	32768
70 #define MAX_SETTINGS_LEVEL	8
71 
72 #define CONTINUE_PARAMETER	1
73 #define NO_PARAMETER 2
74 
75 
76 typedef struct settings_handle {
77 #ifdef _KERNEL_MODE
78 	list_link	link;
79 	char		name[B_OS_NAME_LENGTH];
80 	int32		ref_count;
81 		// A negative ref_count means the node is not reference counted and not
82 		// stored in the list.
83 #endif
84 	int32		magic;
85 	struct		driver_settings settings;
86 	char		*text;
87 } settings_handle;
88 
89 
90 enum assignment_mode {
91 	NO_ASSIGNMENT,
92 	ALLOW_ASSIGNMENT,
93 	IGNORE_ASSIGNMENT
94 };
95 
96 
97 #ifdef _KERNEL_MODE
98 static struct list sHandles;
99 static mutex sLock = MUTEX_INITIALIZER("driver settings");
100 #endif
101 
102 
103 //	#pragma mark - private functions
104 
105 
106 /*!
107 	\brief Returns true for any characters that separate parameters
108 
109 	Those characters are ignored in the input stream and won't be added
110 	to any words.
111 */
112 static inline bool
113 is_parameter_separator(char c)
114 {
115 	return c == '\n' || c == ';';
116 }
117 
118 
119 /*! Indicates if "c" begins a new word or not.
120 */
121 static inline bool
122 is_word_break(char c)
123 {
124 	return isspace(c) || is_parameter_separator(c);
125 }
126 
127 
128 static inline bool
129 check_handle(settings_handle *handle)
130 {
131 	if (handle == NULL
132 		|| handle->magic != SETTINGS_MAGIC)
133 		return false;
134 
135 	return true;
136 }
137 
138 
139 static driver_parameter *
140 get_parameter(settings_handle *handle, const char *name)
141 {
142 	int32 i;
143 	for (i = handle->settings.parameter_count; i-- > 0;) {
144 		if (!strcmp(handle->settings.parameters[i].name, name))
145 			return &handle->settings.parameters[i];
146 	}
147 	return NULL;
148 }
149 
150 
151 /*!
152 	Returns the next word in the input buffer passed in via "_pos" - if
153 	this function returns, it will bump the input position after the word.
154 	It automatically cares about quoted strings and escaped characters.
155 	If "allowNewLine" is true, it reads over comments to get to the next
156 	word.
157 	Depending on the "assignmentMode" parameter, the '=' sign is either
158 	used as a work break, or not.
159 	The input buffer will be changed to contain the word without quotes
160 	or escaped characters and adds a terminating NULL byte. The "_word"
161 	parameter will be set to the beginning of the word.
162 	If the word is followed by a newline it will return B_OK, if white
163 	spaces follows, it will return CONTINUE_PARAMETER.
164 */
165 static status_t
166 get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine)
167 {
168 	char *pos = *_pos;
169 	char quoted = 0;
170 	bool newLine = false, end = false;
171 	int escaped = 0;
172 	bool charEscaped = false;
173 
174 	// Skip any white space and comments
175 	while (pos[0]
176 		&& ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0])
177 				|| pos[0] == '#'))
178 			|| (!allowNewLine && (pos[0] == '\t' || pos[0] == ' '))
179 			|| (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) {
180 		// skip any comment lines
181 		if (pos[0] == '#') {
182 			while (pos[0] && pos[0] != '\n')
183 				pos++;
184 		}
185 		pos++;
186 	}
187 
188 	if (pos[0] == '}' || pos[0] == '\0') {
189 		// if we just read some white space before an end of a
190 		// parameter, this is just no parameter at all
191 		*_pos = pos;
192 		return NO_PARAMETER;
193 	}
194 
195 	// Read in a word - might contain escaped (\) spaces, or it
196 	// might also be quoted (" or ').
197 
198 	if (pos[0] == '"' || pos[0] == '\'') {
199 		quoted = pos[0];
200 		pos++;
201 	}
202 	*_word = pos;
203 
204 	while (pos[0]) {
205 		if (charEscaped)
206 			charEscaped = false;
207 		else if (pos[0] == '\\') {
208 			charEscaped = true;
209 			escaped++;
210 		} else if ((!quoted && (is_word_break(pos[0])
211 				|| (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '=')))
212 			|| (quoted && pos[0] == quoted))
213 			break;
214 
215 		pos++;
216 	}
217 
218 	// "String exceeds line" - missing end quote
219 	if (quoted && pos[0] != quoted)
220 		return B_BAD_DATA;
221 
222 	// last character is a backslash
223 	if (charEscaped)
224 		return B_BAD_DATA;
225 
226 	end = pos[0] == '\0';
227 	newLine = is_parameter_separator(pos[0]) || end;
228 	pos[0] = '\0';
229 
230 	// Correct name if there were any escaped characters
231 	if (escaped) {
232 		char *word = *_word;
233 		int offset = 0;
234 		while (word <= pos) {
235 			if (word[0] == '\\') {
236 				offset--;
237 				word++;
238 			}
239 			word[offset] = word[0];
240 			word++;
241 		}
242 	}
243 
244 	if (end) {
245 		*_pos = pos;
246 		return B_OK;
247 	}
248 
249 	// Scan for next beginning word, open brackets, or comment start
250 
251 	pos++;
252 	while (true) {
253 		*_pos = pos;
254 		if (!pos[0])
255 			return B_NO_ERROR;
256 
257 		if (is_parameter_separator(pos[0])) {
258 			// an open bracket '{' could follow after the first
259 			// newline, but not later
260 			if (newLine)
261 				return B_NO_ERROR;
262 
263 			newLine = true;
264 		} else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#')
265 			return B_NO_ERROR;
266 		else if (!isspace(pos[0]))
267 			return newLine ? B_NO_ERROR : CONTINUE_PARAMETER;
268 
269 		pos++;
270 	}
271 }
272 
273 
274 static status_t
275 parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level)
276 {
277 	char *pos = *_pos;
278 	status_t status;
279 
280 	// initialize parameter first
281 	memset(parameter, 0, sizeof(struct driver_parameter));
282 
283 	status = get_word(&pos, &parameter->name, NO_ASSIGNMENT, true);
284 	if (status == CONTINUE_PARAMETER) {
285 		while (status == CONTINUE_PARAMETER) {
286 			char **newArray, *value = NULL;
287 			status = get_word(&pos, &value, parameter->value_count == 0
288 				? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false);
289 			if (status < B_OK)
290 				break;
291 
292 			// enlarge value array and save the value
293 
294 			newArray = (char**)realloc(parameter->values,
295 				(parameter->value_count + 1) * sizeof(char *));
296 			if (newArray == NULL)
297 				return B_NO_MEMORY;
298 
299 			parameter->values = newArray;
300 			parameter->values[parameter->value_count++] = value;
301 		}
302 	}
303 
304 	*_pos = pos;
305 	return status;
306 }
307 
308 
309 static status_t
310 parse_parameters(struct driver_parameter **_parameters, int *_count,
311 	char **_pos, int32 level)
312 {
313 	if (level > MAX_SETTINGS_LEVEL)
314 		return B_LINK_LIMIT;
315 
316 	while (true) {
317 		struct driver_parameter parameter;
318 		struct driver_parameter *newArray;
319 		status_t status;
320 
321 		status = parse_parameter(&parameter, _pos, level);
322 		if (status < B_OK)
323 			return status;
324 
325 		if (status != NO_PARAMETER) {
326 			driver_parameter *newParameter;
327 
328 			newArray = (driver_parameter*)realloc(*_parameters, (*_count + 1)
329 				* sizeof(struct driver_parameter));
330 			if (newArray == NULL)
331 				return B_NO_MEMORY;
332 
333 			memcpy(&newArray[*_count], &parameter, sizeof(struct driver_parameter));
334 			newParameter = &newArray[*_count];
335 
336 			*_parameters = newArray;
337 			(*_count)++;
338 
339 			// check for level beginning and end
340 			if (**_pos == '{') {
341 				// if we go a level deeper, just start all over again...
342 				(*_pos)++;
343 				status = parse_parameters(&newParameter->parameters,
344 							&newParameter->parameter_count, _pos, level + 1);
345 				if (status < B_OK)
346 					return status;
347 			}
348 		}
349 
350 		if ((**_pos == '}' && level > 0)
351 			|| (**_pos == '\0' && level == 0)) {
352 			// take the closing bracket from the stack
353 			(*_pos)++;
354 			return B_OK;
355 		}
356 
357 		// obviously, something has gone wrong
358 		if (**_pos == '}' || **_pos == '\0')
359 			return B_ERROR;
360 	}
361 }
362 
363 
364 static status_t
365 parse_settings(settings_handle *handle)
366 {
367 	char *text = handle->text;
368 
369 	memset(&handle->settings, 0, sizeof(struct driver_settings));
370 
371 	// empty settings are allowed
372 	if (text == NULL)
373 		return B_OK;
374 
375 	return parse_parameters(&handle->settings.parameters,
376 		&handle->settings.parameter_count, &text, 0);
377 }
378 
379 
380 static void
381 free_parameter(struct driver_parameter *parameter)
382 {
383 	int32 i;
384 	for (i = parameter->parameter_count; i-- > 0;)
385 		free_parameter(&parameter->parameters[i]);
386 
387 	free(parameter->parameters);
388 	free(parameter->values);
389 }
390 
391 
392 static void
393 free_settings(settings_handle *handle)
394 {
395 	int32 i;
396 	for (i = handle->settings.parameter_count; i-- > 0;)
397 		free_parameter(&handle->settings.parameters[i]);
398 
399 	free(handle->settings.parameters);
400 	free(handle->text);
401 	free(handle);
402 }
403 
404 
405 static settings_handle *
406 new_settings(char *buffer, const char *driverName)
407 {
408 	settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
409 	if (handle == NULL)
410 		return NULL;
411 
412 	handle->magic = SETTINGS_MAGIC;
413 	handle->text = buffer;
414 
415 #ifdef _KERNEL_MODE
416 	if (driverName != NULL) {
417 		handle->ref_count = 1;
418 		strlcpy(handle->name, driverName, sizeof(handle->name));
419 	} else {
420 		handle->ref_count = -1;
421 		handle->name[0] = 0;
422 	}
423 #endif
424 
425 	if (parse_settings(handle) == B_OK)
426 		return handle;
427 
428 	free(handle);
429 	return NULL;
430 }
431 
432 
433 static settings_handle *
434 load_driver_settings_from_file(int file, const char *driverName)
435 {
436 	struct stat stat;
437 
438 	// Allocate a buffer and read the whole file into it.
439 	// We will keep this buffer in memory, until the settings
440 	// are unloaded.
441 	// The driver_parameter::name field will point directly
442 	// to this buffer.
443 
444 	if (fstat(file, &stat) < B_OK)
445 		return NULL;
446 
447 	if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) {
448 		char *text = (char *)malloc(stat.st_size + 1);
449 		if (text != NULL && read(file, text, stat.st_size) == stat.st_size) {
450 			settings_handle *handle;
451 
452 			text[stat.st_size] = '\0';
453 				// make sure the string is null terminated
454 				// to avoid misbehaviour
455 
456 			handle = new_settings(text, driverName);
457 			if (handle != NULL) {
458 				// everything went fine!
459 				return handle;
460 			}
461 		}
462 		// "text" might be NULL here, but that's allowed
463 		free(text);
464 	}
465 
466 	return NULL;
467 }
468 
469 
470 static bool
471 put_string(char **_buffer, ssize_t *_bufferSize, char *string)
472 {
473 	size_t length, reserved, quotes;
474 	char *buffer = *_buffer, c;
475 	bool quoted;
476 
477 	if (string == NULL)
478 		return true;
479 
480 	for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
481 		if (c == '"')
482 			quotes++;
483 		else if (is_word_break(c))
484 			reserved++;
485 	}
486 	quoted = reserved || quotes;
487 
488 	// update _bufferSize in any way, so that we can chain several
489 	// of these calls without having to check the return value
490 	// everytime
491 	*_bufferSize -= length + (quoted ? 2 + quotes : 0);
492 
493 	if (*_bufferSize <= 0)
494 		return false;
495 
496 	if (quoted)
497 		*(buffer++) = '"';
498 
499 	for (;(c = string[0]) != '\0'; string++) {
500 		if (c == '"')
501 			*(buffer++) = '\\';
502 
503 		*(buffer++) = c;
504 	}
505 
506 	if (quoted)
507 		*(buffer++) = '"';
508 
509 	buffer[0] = '\0';
510 
511 	// update the buffer position
512 	*_buffer = buffer;
513 
514 	return true;
515 }
516 
517 
518 static bool
519 put_chars(char **_buffer, ssize_t *_bufferSize, const char *chars)
520 {
521 	char *buffer = *_buffer;
522 	size_t length;
523 
524 	if (chars == NULL)
525 		return true;
526 
527 	length = strlen(chars);
528 	*_bufferSize -= length;
529 
530 	if (*_bufferSize <= 0)
531 		return false;
532 
533 	memcpy(buffer, chars, length);
534 	buffer += length;
535 	buffer[0] = '\0';
536 
537 	// update the buffer position
538 	*_buffer = buffer;
539 
540 	return true;
541 }
542 
543 
544 static bool
545 put_char(char **_buffer, ssize_t *_bufferSize, char c)
546 {
547 	char *buffer = *_buffer;
548 
549 	*_bufferSize -= 1;
550 
551 	if (*_bufferSize <= 0)
552 		return false;
553 
554 	buffer[0] = c;
555 	buffer[1] = '\0';
556 
557 	// update the buffer position
558 	*_buffer = buffer + 1;
559 
560 	return true;
561 }
562 
563 
564 static void
565 put_level_space(char **_buffer, ssize_t *_bufferSize, int32 level)
566 {
567 	while (level-- > 0)
568 		put_char(_buffer, _bufferSize, '\t');
569 }
570 
571 
572 static void
573 put_parameter(char **_buffer, ssize_t *_bufferSize,
574 	struct driver_parameter *parameter, int32 level, bool flat)
575 {
576 	int32 i;
577 
578 	if (!flat)
579 		put_level_space(_buffer, _bufferSize, level);
580 
581 	put_string(_buffer, _bufferSize, parameter->name);
582 	if (flat && parameter->value_count > 0)
583 		put_chars(_buffer, _bufferSize, " =");
584 
585 	for (i = 0; i < parameter->value_count; i++) {
586 		put_char(_buffer, _bufferSize, ' ');
587 		put_string(_buffer, _bufferSize, parameter->values[i]);
588 	}
589 
590 	if (parameter->parameter_count > 0) {
591 		put_chars(_buffer, _bufferSize, " {");
592 		if (!flat)
593 			put_char(_buffer, _bufferSize, '\n');
594 
595 		for (i = 0; i < parameter->parameter_count; i++) {
596 			put_parameter(_buffer, _bufferSize, &parameter->parameters[i],
597 				level + 1, flat);
598 
599 			if (parameter->parameters[i].parameter_count == 0)
600 				put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
601 		}
602 
603 		if (!flat)
604 			put_level_space(_buffer, _bufferSize, level);
605 		put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
606 	}
607 }
608 
609 
610 //	#pragma mark - Kernel only functions
611 
612 
613 #ifdef _KERNEL_MODE
614 static settings_handle *
615 find_driver_settings(const char *name)
616 {
617 	settings_handle *handle = NULL;
618 
619 	ASSERT_LOCKED_MUTEX(&sLock);
620 
621 	while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle))
622 			!= NULL) {
623 		if (!strcmp(handle->name, name))
624 			return handle;
625 	}
626 
627 	return NULL;
628 }
629 
630 
631 status_t
632 driver_settings_init(kernel_args *args)
633 {
634 	struct driver_settings_file *settings = args->driver_settings;
635 
636 	// Move the preloaded driver settings over to the kernel
637 
638 	list_init(&sHandles);
639 
640 	while (settings != NULL) {
641 		settings_handle *handle
642 			= (settings_handle*)malloc(sizeof(settings_handle));
643 		if (handle == NULL)
644 			return B_NO_MEMORY;
645 
646 		if (settings->size != 0) {
647 			handle->text = (char*)malloc(settings->size + 1);
648 			if (handle->text == NULL) {
649 				free(handle);
650 				return B_NO_MEMORY;
651 			}
652 
653 			memcpy(handle->text, settings->buffer, settings->size);
654 			handle->text[settings->size] = '\0';
655 				// null terminate the buffer
656 		} else
657 			handle->text = NULL;
658 
659 		strlcpy(handle->name, settings->name, sizeof(handle->name));
660 		handle->settings.parameters = NULL;
661 		handle->settings.parameter_count = 0;
662 		handle->magic = 0;
663 			// this triggers parsing the settings when they are actually used
664 
665 		if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) {
666 			// These settings cannot be reloaded, so we better don't throw
667 			// them away.
668 			handle->ref_count = 1;
669 		} else
670 			handle->ref_count = 0;
671 
672 		list_add_item(&sHandles, handle);
673 
674 		settings = settings->next;
675 	}
676 
677 	return B_OK;
678 }
679 #endif
680 
681 
682 //	#pragma mark - public API
683 
684 
685 status_t
686 unload_driver_settings(void *_handle)
687 {
688 	settings_handle *handle = (settings_handle *)_handle;
689 	if (!check_handle(handle))
690 		return B_BAD_VALUE;
691 
692 #ifdef _KERNEL_MODE
693 	mutex_lock(&sLock);
694 
695 	if (handle->ref_count > 0) {
696 		if (--handle->ref_count == 0 && gBootDevice > 0) {
697 			// don't unload an handle when /boot is not available
698 			list_remove_link(&handle->link);
699 		} else
700 			handle = NULL;
701 	}
702 	mutex_unlock(&sLock);
703 #endif
704 
705 	if (handle != NULL)
706 		free_settings(handle);
707 
708 	return B_OK;
709 }
710 
711 
712 void *
713 load_driver_settings(const char *driverName)
714 {
715 	settings_handle *handle;
716 	int file = -1;
717 
718 	if (driverName == NULL)
719 		return NULL;
720 
721 #ifdef _KERNEL_MODE
722 	// see if we already have these settings loaded
723 	mutex_lock(&sLock);
724 	handle = find_driver_settings(driverName);
725 	if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) {
726 		// A handle with a zero ref_count should be unloaded if /boot is
727 		// available.
728 		list_remove_link(&handle->link);
729 		free_settings(handle);
730 	} else if (handle != NULL) {
731 		handle->ref_count++;
732 
733 		// we got it, now let's see if it already has been parsed
734 		if (handle->magic != SETTINGS_MAGIC) {
735 			handle->magic = SETTINGS_MAGIC;
736 
737 			if (parse_settings(handle) != B_OK) {
738 				// no valid settings, let's cut down its memory requirements
739 				free(handle->text);
740 				handle->text = NULL;
741 				handle = NULL;
742 			}
743 		}
744 		mutex_unlock(&sLock);
745 		return handle;
746 	}
747 
748 	// we are allowed to call the driver settings pretty early in the boot process
749 	if (gKernelStartup) {
750 		mutex_unlock(&sLock);
751 		return NULL;
752 	}
753 #endif	// _KERNEL_MODE
754 #ifdef _BOOT_MODE
755 	// see if we already have these settings loaded
756 	{
757 		struct driver_settings_file *settings = gKernelArgs.driver_settings;
758 		while (settings != NULL) {
759 			if (!strcmp(settings->name, driverName)) {
760 				// we have it - since the buffer is clobbered, we have to
761 				// copy its contents, though
762 				char *text = (char*)malloc(settings->size + 1);
763 				if (text == NULL)
764 					return NULL;
765 
766 				memcpy(text, settings->buffer, settings->size + 1);
767 				settings_handle *handle =  new_settings(text, driverName);
768 				if (handle == NULL)
769 					free(text);
770 				return handle;
771 			}
772 			settings = settings->next;
773 		}
774 	}
775 #endif	// _BOOT_MODE
776 
777 	// open the settings from the standardized location
778 	if (driverName[0] != '/') {
779 		char path[B_FILE_NAME_LENGTH + 64];
780 
781 #ifdef _BOOT_MODE
782 		strcpy(path, kUserSettingsDirectory);
783 #else
784 		// TODO: use B_SYSTEM_SETTINGS_DIRECTORY instead!
785 		if (__find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path,
786 				sizeof(path)) == B_OK)
787 #endif
788 		{
789 			strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
790 			strlcat(path, driverName, sizeof(path));
791 		}
792 
793 		file = open(path, O_RDONLY);
794 	} else
795 		file = open(driverName, O_RDONLY);
796 
797 	if (file < B_OK) {
798 #ifdef _KERNEL_MODE
799 		mutex_unlock(&sLock);
800 #endif
801 		return NULL;
802 	}
803 
804 	handle = load_driver_settings_from_file(file, driverName);
805 
806 #ifdef _KERNEL_MODE
807 	if (handle != NULL)
808 		list_add_item(&sHandles, handle);
809 	mutex_unlock(&sLock);
810 #endif
811 
812 	close(file);
813 	return (void *)handle;
814 }
815 
816 
817 void*
818 load_driver_settings_file(int fd)
819 {
820 	return load_driver_settings_from_file(fd, NULL);
821 }
822 
823 
824 /*!
825 	Returns a new driver_settings handle that has the parsed contents
826 	of the passed string.
827 	You can get an empty driver_settings object when you pass NULL as
828 	the "settingsString" parameter.
829 */
830 void *
831 parse_driver_settings_string(const char *settingsString)
832 {
833 	char *text = NULL;
834 	if (settingsString != NULL) {
835 		// we simply copy the whole string to use it as our internal buffer
836 		text = strdup(settingsString);
837 		if (text == NULL)
838 			return NULL;
839 	}
840 
841 	settings_handle *handle = new_settings(text, NULL);
842 	if (handle == NULL)
843 		free(text);
844 	return handle;
845 }
846 
847 
848 /*!
849 	This function prints out a driver settings structure to a human
850 	readable string.
851 	It's either in standard style or the single line style speficied
852 	by the "flat" parameter.
853 	If the buffer is too small to hold the string, B_BUFFER_OVERFLOW
854 	is returned, and the needed amount of bytes if placed in the
855 	"_bufferSize" parameter.
856 	If the "handle" parameter is not a valid driver settings handle, or
857 	the "buffer" parameter is NULL, B_BAD_VALUE is returned.
858 */
859 status_t
860 get_driver_settings_string(void *_handle, char *buffer, ssize_t *_bufferSize,
861 	bool flat)
862 {
863 	settings_handle *handle = (settings_handle *)_handle;
864 	ssize_t bufferSize = *_bufferSize;
865 	int32 i;
866 
867 	if (!check_handle(handle) || !buffer || *_bufferSize == 0)
868 		return B_BAD_VALUE;
869 
870 	for (i = 0; i < handle->settings.parameter_count; i++) {
871 		put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
872 			0, flat);
873 	}
874 
875 	*_bufferSize -= bufferSize;
876 	return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW;
877 }
878 
879 
880 /*!
881 	Matches the first value of the parameter matching "keyName" with a set
882 	of boolean values like 1/true/yes/on/enabled/...
883 	Returns "unknownValue" if the parameter could not be found or doesn't
884 	have any valid boolean setting, and "noArgValue" if the parameter
885 	doesn't have any values.
886 	Also returns "unknownValue" if the handle passed in was not valid.
887 */
888 bool
889 get_driver_boolean_parameter(void *_handle, const char *keyName,
890 	bool unknownValue, bool noArgValue)
891 {
892 	settings_handle *handle = (settings_handle*)_handle;
893 	driver_parameter *parameter;
894 	char *boolean;
895 
896 	if (!check_handle(handle))
897 		return unknownValue;
898 
899 	// check for the parameter
900 	if ((parameter = get_parameter(handle, keyName)) == NULL)
901 		return unknownValue;
902 
903 	// check for the argument
904 	if (parameter->value_count <= 0)
905 		return noArgValue;
906 
907 	boolean = parameter->values[0];
908 	if (!strcmp(boolean, "1")
909 		|| !strcasecmp(boolean, "true")
910 		|| !strcasecmp(boolean, "yes")
911 		|| !strcasecmp(boolean, "on")
912 		|| !strcasecmp(boolean, "enable")
913 		|| !strcasecmp(boolean, "enabled"))
914 		return true;
915 
916 	if (!strcmp(boolean, "0")
917 		|| !strcasecmp(boolean, "false")
918 		|| !strcasecmp(boolean, "no")
919 		|| !strcasecmp(boolean, "off")
920 		|| !strcasecmp(boolean, "disable")
921 		|| !strcasecmp(boolean, "disabled"))
922 		return false;
923 
924 	// if no known keyword is found, "unknownValue" is returned
925 	return unknownValue;
926 }
927 
928 
929 const char *
930 get_driver_parameter(void *_handle, const char *keyName,
931 	const char *unknownValue, const char *noArgValue)
932 {
933 	settings_handle* handle = (settings_handle*)_handle;
934 	struct driver_parameter *parameter;
935 
936 	if (!check_handle(handle))
937 		return unknownValue;
938 
939 	// check for the parameter
940 	if ((parameter = get_parameter(handle, keyName)) == NULL)
941 		return unknownValue;
942 
943 	// check for the argument
944 	if (parameter->value_count <= 0)
945 		return noArgValue;
946 
947 	return parameter->values[0];
948 }
949 
950 
951 const driver_settings *
952 get_driver_settings(void *handle)
953 {
954 	if (!check_handle((settings_handle*)handle))
955 		return NULL;
956 
957 	return &((settings_handle *)handle)->settings;
958 }
959 
960 
961 #if defined(HAIKU_TARGET_PLATFORM_HAIKU) \
962 	&& (defined(__i386__) || defined(__x86_64__))
963 
964 // Obsolete function, use unload_driver_settings instead. Introduced by
965 // accident in hrev3530 (2003) and present in public headers for a long time.
966 B_DEFINE_WEAK_ALIAS(unload_driver_settings, delete_driver_settings);
967 
968 #endif
969