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