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