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