xref: /haiku/src/tools/fs_shell/driver_settings.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 		// "text" might be NULL here, but that's allowed
428 		free(text);
429 	}
430 
431 	return NULL;
432 }
433 
434 
435 static bool
436 put_string(char **_buffer, fssh_ssize_t *_bufferSize, char *string)
437 {
438 	fssh_size_t length, reserved, quotes;
439 	char *buffer = *_buffer, c;
440 	bool quoted;
441 
442 	if (string == NULL)
443 		return true;
444 
445 	for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
446 		if (c == '"')
447 			quotes++;
448 		else if (is_word_break(c))
449 			reserved++;
450 	}
451 	quoted = reserved || quotes;
452 
453 	// update _bufferSize in any way, so that we can chain several
454 	// of these calls without having to check the return value
455 	// everytime
456 	*_bufferSize -= length + (quoted ? 2 + quotes : 0);
457 
458 	if (*_bufferSize <= 0)
459 		return false;
460 
461 	if (quoted)
462 		*(buffer++) = '"';
463 
464 	for (;(c = string[0]) != '\0'; string++) {
465 		if (c == '"')
466 			*(buffer++) = '\\';
467 
468 		*(buffer++) = c;
469 	}
470 
471 	if (quoted)
472 		*(buffer++) = '"';
473 
474 	buffer[0] = '\0';
475 
476 	// update the buffer position
477 	*_buffer = buffer;
478 
479 	return true;
480 }
481 
482 
483 static bool
484 put_chars(char **_buffer, fssh_ssize_t *_bufferSize, const char *chars)
485 {
486 	char *buffer = *_buffer;
487 	fssh_size_t length;
488 
489 	if (chars == NULL)
490 		return true;
491 
492 	length = fssh_strlen(chars);
493 	*_bufferSize -= length;
494 
495 	if (*_bufferSize <= 0)
496 		return false;
497 
498 	fssh_memcpy(buffer, chars, length);
499 	buffer += length;
500 	buffer[0] = '\0';
501 
502 	// update the buffer position
503 	*_buffer = buffer;
504 
505 	return true;
506 }
507 
508 
509 static bool
510 put_char(char **_buffer, fssh_ssize_t *_bufferSize, char c)
511 {
512 	char *buffer = *_buffer;
513 
514 	*_bufferSize -= 1;
515 
516 	if (*_bufferSize <= 0)
517 		return false;
518 
519 	buffer[0] = c;
520 	buffer[1] = '\0';
521 
522 	// update the buffer position
523 	*_buffer = buffer + 1;
524 
525 	return true;
526 }
527 
528 
529 static void
530 put_level_space(char **_buffer, fssh_ssize_t *_bufferSize, int32_t level)
531 {
532 	while (level-- > 0)
533 		put_char(_buffer, _bufferSize, '\t');
534 }
535 
536 
537 static void
538 put_parameter(char **_buffer, fssh_ssize_t *_bufferSize,
539 	struct fssh_driver_parameter *parameter, int32_t level, bool flat)
540 {
541 	int32_t i;
542 
543 	if (!flat)
544 		put_level_space(_buffer, _bufferSize, level);
545 
546 	put_string(_buffer, _bufferSize, parameter->name);
547 	if (flat && parameter->value_count > 0)
548 		put_chars(_buffer, _bufferSize, " =");
549 
550 	for (i = 0; i < parameter->value_count; i++) {
551 		put_char(_buffer, _bufferSize, ' ');
552 		put_string(_buffer, _bufferSize, parameter->values[i]);
553 	}
554 
555 	if (parameter->parameter_count > 0) {
556 		put_chars(_buffer, _bufferSize, " {");
557 		if (!flat)
558 			put_char(_buffer, _bufferSize, '\n');
559 
560 		for (i = 0; i < parameter->parameter_count; i++) {
561 			put_parameter(_buffer, _bufferSize, &parameter->parameters[i],
562 				level + 1, flat);
563 
564 			if (parameter->parameters[i].parameter_count == 0)
565 				put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
566 		}
567 
568 		if (!flat)
569 			put_level_space(_buffer, _bufferSize, level);
570 		put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
571 	}
572 }
573 
574 
575 //	#pragma mark - Kernel only functions
576 
577 
578 static settings_handle *
579 find_driver_settings(const char *name)
580 {
581 	settings_handle *handle = NULL;
582 
583 	FSSH_ASSERT_LOCKED_MUTEX(&sLock);
584 
585 	while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) != NULL) {
586 		if (!fssh_strcmp(handle->name, name))
587 			return handle;
588 	}
589 
590 	return NULL;
591 }
592 
593 
594 namespace FSShell {
595 
596 fssh_status_t
597 driver_settings_init()
598 {
599 	fssh_mutex_init(&sLock, "driver settings");
600 	return FSSH_B_OK;
601 }
602 
603 }	// namespace FSShell
604 
605 
606 //	#pragma mark - public API
607 
608 
609 fssh_status_t
610 fssh_unload_driver_settings(void *handle)
611 {
612 	if (!check_handle(handle))
613 		return FSSH_B_BAD_VALUE;
614 
615 #if 0
616 	fssh_mutex_lock(&sLock);
617 	// ToDo: as soon as "/boot" is accessible, we should start throwing away settings
618 	if (--handle->ref_count == 0) {
619 		list_remove_link(&handle->link);
620 	} else
621 		handle = NULL;
622 	fssh_mutex_unlock(&sLock);
623 #endif
624 
625 	if (handle != NULL)
626 		free_settings((settings_handle*)handle);
627 
628 	return FSSH_B_OK;
629 }
630 
631 
632 void *
633 fssh_load_driver_settings(const char *driverName)
634 {
635 	settings_handle *handle;
636 	int file = -1;
637 
638 	if (driverName == NULL)
639 		return NULL;
640 
641 	// see if we already have these settings loaded
642 	fssh_mutex_lock(&sLock);
643 	handle = find_driver_settings(driverName);
644 	if (handle != NULL) {
645 		handle->ref_count++;
646 
647 		// we got it, now let's see if it already has been parsed
648 		if (handle->magic != SETTINGS_MAGIC) {
649 			handle->magic = SETTINGS_MAGIC;
650 
651 			if (parse_settings(handle) != FSSH_B_OK) {
652 				// no valid settings, let's cut down its memory requirements
653 				free(handle->text);
654 				handle->text = NULL;
655 				handle = NULL;
656 			}
657 		}
658 		fssh_mutex_unlock(&sLock);
659 		return handle;
660 	}
661 
662 	// open the settings from the standardized location
663 	if (driverName[0] != '/') {
664 		char path[FSSH_B_FILE_NAME_LENGTH + 64];
665 
666 		// This location makes at least a bit sense under BeOS compatible
667 		// systems.
668 		fssh_strcpy(path, "/boot/home/config/settings/fs_shell");
669 
670 		{
671 			fssh_strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
672 			fssh_strlcat(path, driverName, sizeof(path));
673 		}
674 
675 		file = fssh_open(path, FSSH_O_RDONLY);
676 	} else
677 		file = fssh_open(driverName, FSSH_O_RDONLY);
678 
679 	if (file < FSSH_B_OK) {
680 		fssh_mutex_unlock(&sLock);
681 		return NULL;
682 	}
683 
684 	handle = load_driver_settings_from_file(file, driverName);
685 
686 	if (handle != NULL)
687 		list_add_item(&sHandles, handle);
688 	fssh_mutex_unlock(&sLock);
689 
690 	fssh_close(file);
691 	return (void *)handle;
692 }
693 
694 
695 /** Loads a driver settings file using the full path, instead of
696  *	only defining the leaf name (as load_driver_settings() does).
697  *	I am not sure if this function is really necessary - I would
698  *	probably prefer something like a search order (if it's not
699  *	an absolute path):
700  *		~/config/settings/kernel/driver
701  *		current directory
702  *	That would render this function useless.
703  */
704 
705 #if 0
706 void *
707 fssh_load_driver_settings_from_path(const char *path)
708 {
709 	settings_handle *handle;
710 	int file;
711 
712 	if (path == NULL)
713 		return NULL;
714 
715 	file = fssh_open(path, FSSH_O_RDONLY);
716 	if (file < FSSH_B_OK)
717 		return NULL;
718 
719 	handle = load_driver_settings_from_file(file);
720 
721 	fssh_close(file);
722 	return (void *)handle;
723 }
724 #endif
725 
726 
727 /*!
728 	Returns a new driver_settings handle that has the parsed contents
729 	of the passed string.
730 	You can get an empty driver_settings object when you pass NULL as
731 	the "settingsString" parameter.
732 */
733 void *
734 fssh_parse_driver_settings_string(const char *settingsString)
735 {
736 	// we simply copy the whole string to use it as our internal buffer
737 	char *text = fssh_strdup(settingsString);
738 	if (settingsString == NULL || text != NULL) {
739 		settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
740 		if (handle != NULL) {
741 			handle->magic = SETTINGS_MAGIC;
742 			handle->text = text;
743 
744 			if (parse_settings(handle) == FSSH_B_OK)
745 				return handle;
746 
747 			free(handle);
748 		}
749 		free(text);
750 	}
751 
752 	return NULL;
753 }
754 
755 
756 /*!
757 	This function prints out a driver settings structure to a human
758 	readable string.
759 	It's either in standard style or the single line style speficied
760 	by the "flat" parameter.
761 	If the buffer is too small to hold the string, FSSH_B_BUFFER_OVERFLOW
762 	is returned, and the needed amount of bytes if placed in the
763 	"_bufferSize" parameter.
764 	If the "handle" parameter is not a valid driver settings handle, or
765 	the "buffer" parameter is NULL, FSSH_B_BAD_VALUE is returned.
766 */
767 fssh_status_t
768 fssh_get_driver_settings_string(void *_handle, char *buffer,
769 	fssh_ssize_t *_bufferSize, bool flat)
770 {
771 	settings_handle *handle = (settings_handle *)_handle;
772 	fssh_ssize_t bufferSize = *_bufferSize;
773 	int32_t i;
774 
775 	if (!check_handle(handle) || !buffer || *_bufferSize == 0)
776 		return FSSH_B_BAD_VALUE;
777 
778 	for (i = 0; i < handle->settings.parameter_count; i++) {
779 		put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
780 			0, flat);
781 	}
782 
783 	*_bufferSize -= bufferSize;
784 	return bufferSize >= 0 ? FSSH_B_OK : FSSH_B_BUFFER_OVERFLOW;
785 }
786 
787 
788 /*!
789 	Matches the first value of the parameter matching "keyName" with a set
790 	of boolean values like 1/true/yes/on/enabled/...
791 	Returns "unknownValue" if the parameter could not be found or doesn't
792 	have any valid boolean setting, and "noArgValue" if the parameter
793 	doesn't have any values.
794 	Also returns "unknownValue" if the handle passed in was not valid.
795 */
796 bool
797 fssh_get_driver_boolean_parameter(void *handle, const char *keyName,
798 	bool unknownValue, bool noArgValue)
799 {
800 	fssh_driver_parameter *parameter;
801 	char *boolean;
802 
803 	if (!check_handle(handle))
804 		return unknownValue;
805 
806 	// check for the parameter
807 	if ((parameter = get_parameter((settings_handle*)handle, keyName)) == NULL)
808 		return unknownValue;
809 
810 	// check for the argument
811 	if (parameter->value_count <= 0)
812 		return noArgValue;
813 
814 	boolean = parameter->values[0];
815 	if (!fssh_strcmp(boolean, "1")
816 		|| !fssh_strcasecmp(boolean, "true")
817 		|| !fssh_strcasecmp(boolean, "yes")
818 		|| !fssh_strcasecmp(boolean, "on")
819 		|| !fssh_strcasecmp(boolean, "enable")
820 		|| !fssh_strcasecmp(boolean, "enabled"))
821 		return true;
822 
823 	if (!fssh_strcmp(boolean, "0")
824 		|| !fssh_strcasecmp(boolean, "false")
825 		|| !fssh_strcasecmp(boolean, "no")
826 		|| !fssh_strcasecmp(boolean, "off")
827 		|| !fssh_strcasecmp(boolean, "disable")
828 		|| !fssh_strcasecmp(boolean, "disabled"))
829 		return false;
830 
831 	// if no known keyword is found, "unknownValue" is returned
832 	return unknownValue;
833 }
834 
835 
836 const char *
837 fssh_get_driver_parameter(void *handle, const char *keyName,
838 	const char *unknownValue, const char *noArgValue)
839 {
840 	struct fssh_driver_parameter *parameter;
841 
842 	if (!check_handle(handle))
843 		return unknownValue;
844 
845 	// check for the parameter
846 	if ((parameter = get_parameter((settings_handle*)handle, keyName)) == NULL)
847 		return unknownValue;
848 
849 	// check for the argument
850 	if (parameter->value_count <= 0)
851 		return noArgValue;
852 
853 	return parameter->values[0];
854 }
855 
856 
857 const fssh_driver_settings *
858 fssh_get_driver_settings(void *handle)
859 {
860 	if (!check_handle(handle))
861 		return NULL;
862 
863 	return &((settings_handle *)handle)->settings;
864 }
865 
866 
867 fssh_status_t
868 fssh_delete_driver_settings(void *handle)
869 {
870 	return fssh_unload_driver_settings(handle);
871 }
872