xref: /haiku/src/tools/fs_shell/driver_settings.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
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 #include "fssh_driver_settings.h"
26 
27 #include <ctype.h>
28 #include <stdlib.h>
29 
30 #include "fssh_fcntl.h"
31 #include "fssh_os.h"
32 #include "fssh_stat.h"
33 #include "fssh_string.h"
34 #include "fssh_unistd.h"
35 
36 #include "list.h"
37 #include "lock.h"
38 
39 
40 using namespace FSShell;
41 
42 #define ASSERT_LOCKED_MUTEX(lock)
43 
44 
45 #define SETTINGS_DIRECTORY "/kernel/drivers/"
46 #define SETTINGS_MAGIC		'DrvS'
47 
48 // Those maximum values are independent from the implementation - they
49 // have been chosen to make the code more robust against bad files
50 #define MAX_SETTINGS_SIZE	32768
51 #define MAX_SETTINGS_LEVEL	8
52 
53 #define CONTINUE_PARAMETER	1
54 #define NO_PARAMETER 2
55 
56 
57 typedef struct settings_handle {
58 	list_link	link;
59 	char		name[FSSH_B_OS_NAME_LENGTH];
60 	int32_t		ref_count;
61 	int32_t		magic;
62 	struct		fssh_driver_settings settings;
63 	char		*text;
64 } settings_handle;
65 
66 
67 enum assignment_mode {
68 	NO_ASSIGNMENT,
69 	ALLOW_ASSIGNMENT,
70 	IGNORE_ASSIGNMENT
71 };
72 
73 
74 static struct list sHandles;
75 static mutex sLock;
76 
77 
78 //	#pragma mark - private functions
79 
80 
81 /*!
82 	Returns true for any characters that separate parameters -
83 	those are ignored in the input stream and won't be added
84 	to any words.
85 */
86 static inline bool
87 is_parameter_separator(char c)
88 {
89 	return c == '\n' || c == ';';
90 }
91 
92 
93 /** Indicates if "c" begins a new word or not.
94  */
95 
96 static inline bool
97 is_word_break(char c)
98 {
99 	return isspace(c) || is_parameter_separator(c);
100 }
101 
102 
103 static inline bool
104 check_handle(void *_handle)
105 {
106 	settings_handle *handle = (settings_handle *)_handle;
107 	if (handle == NULL
108 		|| handle->magic != SETTINGS_MAGIC)
109 		return false;
110 
111 	return true;
112 }
113 
114 
115 static fssh_driver_parameter *
116 get_parameter(settings_handle *handle, const char *name)
117 {
118 	int32_t i;
119 	for (i = handle->settings.parameter_count; i-- > 0;) {
120 		if (!fssh_strcmp(handle->settings.parameters[i].name, name))
121 			return &handle->settings.parameters[i];
122 	}
123 	return NULL;
124 }
125 
126 
127 /*!
128 	Returns the next word in the input buffer passed in via "_pos" - if
129 	this function returns, it will bump the input position after the word.
130 	It automatically cares about quoted strings and escaped characters.
131 	If "allowNewLine" is true, it reads over comments to get to the next
132 	word.
133 	Depending on the "assignmentMode" parameter, the '=' sign is either
134 	used as a work break, or not.
135 	The input buffer will be changed to contain the word without quotes
136 	or escaped characters and adds a terminating NULL byte. The "_word"
137 	parameter will be set to the beginning of the word.
138 	If the word is followed by a newline it will return FSSH_B_OK, if white
139 	spaces follows, it will return CONTINUE_PARAMETER.
140 */
141 static fssh_status_t
142 get_word(char **_pos, char **_word, int32_t assignmentMode, bool allowNewLine)
143 {
144 	char *pos = *_pos;
145 	char quoted = 0;
146 	bool newLine = false, end = false;
147 	int escaped = 0;
148 	bool charEscaped = false;
149 
150 	// Skip any white space and comments
151 	while (pos[0]
152 		&& ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0])
153 				|| pos[0] == '#'))
154 			|| (!allowNewLine && (pos[0] == '\t' || pos[0] == ' '))
155 			|| (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) {
156 		// skip any comment lines
157 		if (pos[0] == '#') {
158 			while (pos[0] && pos[0] != '\n')
159 				pos++;
160 		}
161 		pos++;
162 	}
163 
164 	if (pos[0] == '}' || pos[0] == '\0') {
165 		// if we just read some white space before an end of a
166 		// parameter, this is just no parameter at all
167 		*_pos = pos;
168 		return NO_PARAMETER;
169 	}
170 
171 	// Read in a word - might contain escaped (\) spaces, or it
172 	// might also be quoted (" or ').
173 
174 	if (pos[0] == '"' || pos[0] == '\'') {
175 		quoted = pos[0];
176 		pos++;
177 	}
178 	*_word = pos;
179 
180 	while (pos[0]) {
181 		if (charEscaped)
182 			charEscaped = false;
183 		else if (pos[0] == '\\') {
184 			charEscaped = true;
185 			escaped++;
186 		} else if ((!quoted && (is_word_break(pos[0])
187 				|| (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '=')))
188 			|| (quoted && pos[0] == quoted))
189 			break;
190 
191 		pos++;
192 	}
193 
194 	// "String exceeds line" - missing end quote
195 	if (quoted && pos[0] != quoted)
196 		return FSSH_B_BAD_DATA;
197 
198 	// last character is a backslash
199 	if (charEscaped)
200 		return FSSH_B_BAD_DATA;
201 
202 	end = pos[0] == '\0';
203 	newLine = is_parameter_separator(pos[0]) || end;
204 	pos[0] = '\0';
205 
206 	// Correct name if there were any escaped characters
207 	if (escaped) {
208 		char *word = *_word;
209 		int offset = 0;
210 		while (word <= pos) {
211 			if (word[0] == '\\') {
212 				offset--;
213 				word++;
214 			}
215 			word[offset] = word[0];
216 			word++;
217 		}
218 	}
219 
220 	if (end) {
221 		*_pos = pos;
222 		return FSSH_B_OK;
223 	}
224 
225 	// Scan for next beginning word, open brackets, or comment start
226 
227 	pos++;
228 	while (true) {
229 		*_pos = pos;
230 		if (!pos[0])
231 			return FSSH_B_NO_ERROR;
232 
233 		if (is_parameter_separator(pos[0])) {
234 			// an open bracket '{' could follow after the first
235 			// newline, but not later
236 			if (newLine)
237 				return FSSH_B_NO_ERROR;
238 
239 			newLine = true;
240 		} else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#')
241 			return FSSH_B_NO_ERROR;
242 		else if (!isspace(pos[0]))
243 			return newLine ? FSSH_B_NO_ERROR : CONTINUE_PARAMETER;
244 
245 		pos++;
246 	}
247 }
248 
249 
250 static fssh_status_t
251 parse_parameter(struct fssh_driver_parameter *parameter, char **_pos, int32_t level)
252 {
253 	char *pos = *_pos;
254 	fssh_status_t status;
255 
256 	// initialize parameter first
257 	fssh_memset(parameter, 0, sizeof(struct fssh_driver_parameter));
258 
259 	status = get_word(&pos, &parameter->name, NO_ASSIGNMENT, true);
260 	if (status == CONTINUE_PARAMETER) {
261 		while (status == CONTINUE_PARAMETER) {
262 			char **newArray, *value;
263 			status = get_word(&pos, &value, parameter->value_count == 0
264 				? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false);
265 			if (status < FSSH_B_OK)
266 				break;
267 
268 			// enlarge value array and save the value
269 
270 			newArray = (char**)realloc(parameter->values,
271 				(parameter->value_count + 1) * sizeof(char *));
272 			if (newArray == NULL)
273 				return FSSH_B_NO_MEMORY;
274 
275 			parameter->values = newArray;
276 			parameter->values[parameter->value_count++] = value;
277 		}
278 	}
279 
280 	*_pos = pos;
281 	return status;
282 }
283 
284 
285 static fssh_status_t
286 parse_parameters(struct fssh_driver_parameter **_parameters, int *_count,
287 	char **_pos, int32_t level)
288 {
289 	if (level > MAX_SETTINGS_LEVEL)
290 		return FSSH_B_LINK_LIMIT;
291 
292 	while (true) {
293 		struct fssh_driver_parameter parameter;
294 		struct fssh_driver_parameter *newArray;
295 		fssh_status_t status;
296 
297 		status = parse_parameter(&parameter, _pos, level);
298 		if (status < FSSH_B_OK)
299 			return status;
300 
301 		if (status != NO_PARAMETER) {
302 			fssh_driver_parameter *newParameter;
303 
304 			newArray = (fssh_driver_parameter*)realloc(*_parameters, (*_count + 1)
305 				* sizeof(struct fssh_driver_parameter));
306 			if (newArray == NULL)
307 				return FSSH_B_NO_MEMORY;
308 
309 			fssh_memcpy(&newArray[*_count], &parameter, sizeof(struct fssh_driver_parameter));
310 			newParameter = &newArray[*_count];
311 
312 			*_parameters = newArray;
313 			(*_count)++;
314 
315 			// check for level beginning and end
316 			if (**_pos == '{') {
317 				// if we go a level deeper, just start all over again...
318 				(*_pos)++;
319 				status = parse_parameters(&newParameter->parameters,
320 							&newParameter->parameter_count, _pos, level + 1);
321 				if (status < FSSH_B_OK)
322 					return status;
323 			}
324 		}
325 
326 		if ((**_pos == '}' && level > 0)
327 			|| (**_pos == '\0' && level == 0)) {
328 			// take the closing bracket from the stack
329 			(*_pos)++;
330 			return FSSH_B_OK;
331 		}
332 
333 		// obviously, something has gone wrong
334 		if (**_pos == '}' || **_pos == '\0')
335 			return FSSH_B_ERROR;
336 	}
337 }
338 
339 
340 static fssh_status_t
341 parse_settings(settings_handle *handle)
342 {
343 	char *text = handle->text;
344 
345 	fssh_memset(&handle->settings, 0, sizeof(struct fssh_driver_settings));
346 
347 	// empty settings are allowed
348 	if (text == NULL)
349 		return FSSH_B_OK;
350 
351 	return parse_parameters(&handle->settings.parameters,
352 		&handle->settings.parameter_count, &text, 0);
353 }
354 
355 
356 static void
357 free_parameter(struct fssh_driver_parameter *parameter)
358 {
359 	int32_t i;
360 	for (i = parameter->parameter_count; i-- > 0;)
361 		free_parameter(&parameter->parameters[i]);
362 
363 	free(parameter->parameters);
364 	free(parameter->values);
365 }
366 
367 
368 static void
369 free_settings(settings_handle *handle)
370 {
371 	int32_t i;
372 	for (i = handle->settings.parameter_count; i-- > 0;)
373 		free_parameter(&handle->settings.parameters[i]);
374 
375 	free(handle->settings.parameters);
376 	free(handle->text);
377 	free(handle);
378 }
379 
380 
381 static settings_handle *
382 new_settings(char *buffer, const char *driverName)
383 {
384 	settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
385 	if (handle == NULL)
386 		return NULL;
387 
388 	handle->magic = SETTINGS_MAGIC;
389 	handle->text = buffer;
390 
391 	fssh_strlcpy(handle->name, driverName, sizeof(handle->name));
392 
393 	if (parse_settings(handle) == FSSH_B_OK)
394 		return handle;
395 
396 	free(handle);
397 	return NULL;
398 }
399 
400 
401 static settings_handle *
402 load_driver_settings_from_file(int file, const char *driverName)
403 {
404 	struct fssh_stat stat;
405 
406 	// Allocate a buffer and read the whole file into it.
407 	// We will keep this buffer in memory, until the settings
408 	// are unloaded.
409 	// The fssh_driver_parameter::name field will point directly
410 	// to this buffer.
411 
412 	if (fssh_fstat(file, &stat) < FSSH_B_OK)
413 		return NULL;
414 
415 	if (stat.fssh_st_size > FSSH_B_OK && stat.fssh_st_size < MAX_SETTINGS_SIZE) {
416 		char *text = (char *)malloc(stat.fssh_st_size + 1);
417 		if (text != NULL && fssh_read(file, text, stat.fssh_st_size) == stat.fssh_st_size) {
418 			settings_handle *handle;
419 
420 			text[stat.fssh_st_size] = '\0';
421 				// make sure the string is null terminated
422 				// to avoid misbehaviour
423 
424 			handle = new_settings(text, driverName);
425 			if (handle != NULL) {
426 				// everything went fine!
427 				return handle;
428 			}
429 
430 			free(handle);
431 		}
432 		// "text" might be NULL here, but that's allowed
433 		free(text);
434 	}
435 
436 	return NULL;
437 }
438 
439 
440 static bool
441 put_string(char **_buffer, fssh_size_t *_bufferSize, char *string)
442 {
443 	fssh_size_t length, reserved, quotes;
444 	char *buffer = *_buffer, c;
445 	bool quoted;
446 
447 	if (string == NULL)
448 		return true;
449 
450 	for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
451 		if (c == '"')
452 			quotes++;
453 		else if (is_word_break(c))
454 			reserved++;
455 	}
456 	quoted = reserved || quotes;
457 
458 	// update _bufferSize in any way, so that we can chain several
459 	// of these calls without having to check the return value
460 	// everytime
461 	*_bufferSize -= length + (quoted ? 2 + quotes : 0);
462 
463 	if (*_bufferSize <= 0)
464 		return false;
465 
466 	if (quoted)
467 		*(buffer++) = '"';
468 
469 	for (;(c = string[0]) != '\0'; string++) {
470 		if (c == '"')
471 			*(buffer++) = '\\';
472 
473 		*(buffer++) = c;
474 	}
475 
476 	if (quoted)
477 		*(buffer++) = '"';
478 
479 	buffer[0] = '\0';
480 
481 	// update the buffer position
482 	*_buffer = buffer;
483 
484 	return true;
485 }
486 
487 
488 static bool
489 put_chars(char **_buffer, fssh_size_t *_bufferSize, const char *chars)
490 {
491 	char *buffer = *_buffer;
492 	fssh_size_t length;
493 
494 	if (chars == NULL)
495 		return true;
496 
497 	length = fssh_strlen(chars);
498 	*_bufferSize -= length;
499 
500 	if (*_bufferSize <= 0)
501 		return false;
502 
503 	fssh_memcpy(buffer, chars, length);
504 	buffer += length;
505 	buffer[0] = '\0';
506 
507 	// update the buffer position
508 	*_buffer = buffer;
509 
510 	return true;
511 }
512 
513 
514 static bool
515 put_char(char **_buffer, fssh_size_t *_bufferSize, char c)
516 {
517 	char *buffer = *_buffer;
518 
519 	*_bufferSize -= 1;
520 
521 	if (*_bufferSize <= 0)
522 		return false;
523 
524 	buffer[0] = c;
525 	buffer[1] = '\0';
526 
527 	// update the buffer position
528 	*_buffer = buffer + 1;
529 
530 	return true;
531 }
532 
533 
534 static void
535 put_level_space(char **_buffer, fssh_size_t *_bufferSize, int32_t level)
536 {
537 	while (level-- > 0)
538 		put_char(_buffer, _bufferSize, '\t');
539 }
540 
541 
542 static bool
543 put_parameter(char **_buffer, fssh_size_t *_bufferSize,
544 	struct fssh_driver_parameter *parameter, int32_t level, bool flat)
545 {
546 	int32_t i;
547 
548 	if (!flat)
549 		put_level_space(_buffer, _bufferSize, level);
550 
551 	put_string(_buffer, _bufferSize, parameter->name);
552 	if (flat && parameter->value_count > 0)
553 		put_chars(_buffer, _bufferSize, " =");
554 
555 	for (i = 0; i < parameter->value_count; i++) {
556 		put_char(_buffer, _bufferSize, ' ');
557 		put_string(_buffer, _bufferSize, parameter->values[i]);
558 	}
559 
560 	if (parameter->parameter_count > 0) {
561 		put_chars(_buffer, _bufferSize, " {");
562 		if (!flat)
563 			put_char(_buffer, _bufferSize, '\n');
564 
565 		for (i = 0; i < parameter->parameter_count; i++) {
566 			put_parameter(_buffer, _bufferSize, &parameter->parameters[i],
567 				level + 1, flat);
568 
569 			if (parameter->parameters[i].parameter_count == 0)
570 				put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
571 		}
572 
573 		if (!flat)
574 			put_level_space(_buffer, _bufferSize, level);
575 		put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
576 	}
577 
578 	return *_bufferSize >= 0;
579 }
580 
581 
582 //	#pragma mark - Kernel only functions
583 
584 
585 static settings_handle *
586 find_driver_settings(const char *name)
587 {
588 	settings_handle *handle = NULL;
589 
590 	ASSERT_LOCKED_MUTEX(&sLock);
591 
592 	while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) != NULL) {
593 		if (!fssh_strcmp(handle->name, name))
594 			return handle;
595 	}
596 
597 	return NULL;
598 }
599 
600 
601 namespace FSShell {
602 
603 fssh_status_t
604 driver_settings_init()
605 {
606 	return mutex_init(&sLock, "driver settings");
607 }
608 
609 }
610 
611 
612 //	#pragma mark - public API
613 
614 
615 fssh_status_t
616 fssh_unload_driver_settings(void *handle)
617 {
618 	if (!check_handle(handle))
619 		return FSSH_B_BAD_VALUE;
620 
621 #if 0
622 	mutex_lock(&sLock);
623 	// ToDo: as soon as "/boot" is accessible, we should start throwing away settings
624 	if (--handle->ref_count == 0) {
625 		list_remove_link(&handle->link);
626 	} else
627 		handle = NULL;
628 	mutex_unlock(&sLock);
629 #endif
630 
631 	if (handle != NULL)
632 		free_settings((settings_handle*)handle);
633 
634 	return FSSH_B_OK;
635 }
636 
637 
638 void *
639 fssh_load_driver_settings(const char *driverName)
640 {
641 	settings_handle *handle;
642 	int file = -1;
643 
644 	if (driverName == NULL)
645 		return NULL;
646 
647 	// see if we already have these settings loaded
648 	mutex_lock(&sLock);
649 	handle = find_driver_settings(driverName);
650 	if (handle != NULL) {
651 		handle->ref_count++;
652 
653 		// we got it, now let's see if it already has been parsed
654 		if (handle->magic != SETTINGS_MAGIC) {
655 			handle->magic = SETTINGS_MAGIC;
656 
657 			if (parse_settings(handle) != FSSH_B_OK) {
658 				// no valid settings, let's cut down its memory requirements
659 				free(handle->text);
660 				handle->text = NULL;
661 				handle = NULL;
662 			}
663 		}
664 		mutex_unlock(&sLock);
665 		return handle;
666 	}
667 
668 	// open the settings from the standardized location
669 	if (driverName[0] != '/') {
670 		char path[FSSH_B_FILE_NAME_LENGTH + 64];
671 
672 		// This location makes at least a bit sense under BeOS compatible
673 		// systems.
674 		fssh_strcpy(path, "/boot/home/config/settings/fs_shell");
675 
676 		{
677 			fssh_strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
678 			fssh_strlcat(path, driverName, sizeof(path));
679 		}
680 
681 		file = fssh_open(path, FSSH_O_RDONLY);
682 	} else
683 		file = fssh_open(driverName, FSSH_O_RDONLY);
684 
685 	if (file < FSSH_B_OK) {
686 		mutex_unlock(&sLock);
687 		return NULL;
688 	}
689 
690 	handle = load_driver_settings_from_file(file, driverName);
691 
692 	if (handle != NULL)
693 		list_add_item(&sHandles, handle);
694 	mutex_unlock(&sLock);
695 
696 	fssh_close(file);
697 	return (void *)handle;
698 }
699 
700 
701 /** Loads a driver settings file using the full path, instead of
702  *	only defining the leaf name (as load_driver_settings() does).
703  *	I am not sure if this function is really necessary - I would
704  *	probably prefer something like a search order (if it's not
705  *	an absolute path):
706  *		~/config/settings/kernel/driver
707  *		current directory
708  *	That would render this function useless.
709  */
710 
711 #if 0
712 void *
713 fssh_load_driver_settings_from_path(const char *path)
714 {
715 	settings_handle *handle;
716 	int file;
717 
718 	if (path == NULL)
719 		return NULL;
720 
721 	file = fssh_open(path, FSSH_O_RDONLY);
722 	if (file < FSSH_B_OK)
723 		return NULL;
724 
725 	handle = load_driver_settings_from_file(file);
726 
727 	fssh_close(file);
728 	return (void *)handle;
729 }
730 #endif
731 
732 
733 /*!
734 	Returns a new driver_settings handle that has the parsed contents
735 	of the passed string.
736 	You can get an empty driver_settings object when you pass NULL as
737 	the "settingsString" parameter.
738 */
739 void *
740 fssh_parse_driver_settings_string(const char *settingsString)
741 {
742 	// we simply copy the whole string to use it as our internal buffer
743 	char *text = fssh_strdup(settingsString);
744 	if (settingsString == NULL || text != NULL) {
745 		settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
746 		if (handle != NULL) {
747 			handle->magic = SETTINGS_MAGIC;
748 			handle->text = text;
749 
750 			if (parse_settings(handle) == FSSH_B_OK)
751 				return handle;
752 
753 			free(handle);
754 		}
755 		free(text);
756 	}
757 
758 	return NULL;
759 }
760 
761 
762 /*!
763 	This function prints out a driver settings structure to a human
764 	readable string.
765 	It's either in standard style or the single line style speficied
766 	by the "flat" parameter.
767 	If the buffer is too small to hold the string, FSSH_B_BUFFER_OVERFLOW
768 	is returned, and the needed amount of bytes if placed in the
769 	"_bufferSize" parameter.
770 	If the "handle" parameter is not a valid driver settings handle, or
771 	the "buffer" parameter is NULL, FSSH_B_BAD_VALUE is returned.
772 */
773 fssh_status_t
774 fssh_get_driver_settings_string(void *_handle, char *buffer,
775 	fssh_size_t *_bufferSize, bool flat)
776 {
777 	settings_handle *handle = (settings_handle *)_handle;
778 	fssh_size_t bufferSize = *_bufferSize;
779 	int32_t i;
780 
781 	if (!check_handle(handle) || !buffer || *_bufferSize == 0)
782 		return FSSH_B_BAD_VALUE;
783 
784 	for (i = 0; i < handle->settings.parameter_count; i++) {
785 		put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
786 			0, flat);
787 	}
788 
789 	*_bufferSize -= bufferSize;
790 	return bufferSize >= 0 ? FSSH_B_OK : FSSH_B_BUFFER_OVERFLOW;
791 }
792 
793 
794 /*!
795 	Matches the first value of the parameter matching "keyName" with a set
796 	of boolean values like 1/true/yes/on/enabled/...
797 	Returns "unknownValue" if the parameter could not be found or doesn't
798 	have any valid boolean setting, and "noArgValue" if the parameter
799 	doesn't have any values.
800 	Also returns "unknownValue" if the handle passed in was not valid.
801 */
802 bool
803 fssh_get_driver_boolean_parameter(void *handle, const char *keyName,
804 	bool unknownValue, bool noArgValue)
805 {
806 	fssh_driver_parameter *parameter;
807 	char *boolean;
808 
809 	if (!check_handle(handle))
810 		return unknownValue;
811 
812 	// check for the parameter
813 	if ((parameter = get_parameter((settings_handle*)handle, keyName)) == NULL)
814 		return unknownValue;
815 
816 	// check for the argument
817 	if (parameter->value_count <= 0)
818 		return noArgValue;
819 
820 	boolean = parameter->values[0];
821 	if (!fssh_strcmp(boolean, "1")
822 		|| !fssh_strcasecmp(boolean, "true")
823 		|| !fssh_strcasecmp(boolean, "yes")
824 		|| !fssh_strcasecmp(boolean, "on")
825 		|| !fssh_strcasecmp(boolean, "enable")
826 		|| !fssh_strcasecmp(boolean, "enabled"))
827 		return true;
828 
829 	if (!fssh_strcmp(boolean, "0")
830 		|| !fssh_strcasecmp(boolean, "false")
831 		|| !fssh_strcasecmp(boolean, "no")
832 		|| !fssh_strcasecmp(boolean, "off")
833 		|| !fssh_strcasecmp(boolean, "disable")
834 		|| !fssh_strcasecmp(boolean, "disabled"))
835 		return false;
836 
837 	// if no known keyword is found, "unknownValue" is returned
838 	return unknownValue;
839 }
840 
841 
842 const char *
843 fssh_get_driver_parameter(void *handle, const char *keyName,
844 	const char *unknownValue, const char *noArgValue)
845 {
846 	struct fssh_driver_parameter *parameter;
847 
848 	if (!check_handle(handle))
849 		return unknownValue;
850 
851 	// check for the parameter
852 	if ((parameter = get_parameter((settings_handle*)handle, keyName)) == NULL)
853 		return unknownValue;
854 
855 	// check for the argument
856 	if (parameter->value_count <= 0)
857 		return noArgValue;
858 
859 	return parameter->values[0];
860 }
861 
862 
863 const fssh_driver_settings *
864 fssh_get_driver_settings(void *handle)
865 {
866 	if (!check_handle(handle))
867 		return NULL;
868 
869 	return &((settings_handle *)handle)->settings;
870 }
871 
872 
873 fssh_status_t
874 fssh_delete_driver_settings(void *handle)
875 {
876 	return fssh_unload_driver_settings(handle);
877 }
878