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