1/* 2 * Copyright (c) 1997 Metro Link Incorporated 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the Metro Link shall not be 23 * used in advertising or otherwise to promote the sale, use or other dealings 24 * in this Software without prior written authorization from Metro Link. 25 * 26 */ 27/* 28 * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 29 * 30 * Permission is hereby granted, free of charge, to any person obtaining a 31 * copy of this software and associated documentation files (the "Software"), 32 * to deal in the Software without restriction, including without limitation 33 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 34 * and/or sell copies of the Software, and to permit persons to whom the 35 * Software is furnished to do so, subject to the following conditions: 36 * 37 * The above copyright notice and this permission notice shall be included in 38 * all copies or substantial portions of the Software. 39 * 40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 43 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 44 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 45 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 46 * OTHER DEALINGS IN THE SOFTWARE. 47 * 48 * Except as contained in this notice, the name of the copyright holder(s) 49 * and author(s) shall not be used in advertising or otherwise to promote 50 * the sale, use or other dealings in this Software without prior written 51 * authorization from the copyright holder(s) and author(s). 52 */ 53 54 55/* View/edit this file with tab stops set to 4 */ 56 57#ifdef HAVE_XORG_CONFIG_H 58#include <xorg-config.h> 59#endif 60 61#include <ctype.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <sys/types.h> 66#include <dirent.h> 67#include <unistd.h> 68#include <stdarg.h> 69#include <X11/Xdefs.h> 70#include <X11/Xfuncproto.h> 71 72#if defined(_POSIX_SOURCE) 73#include <limits.h> 74#else 75#define _POSIX_SOURCE 76#include <limits.h> 77#undef _POSIX_SOURCE 78#endif /* _POSIX_SOURCE */ 79 80#if !defined(PATH_MAX) 81#if defined(MAXPATHLEN) 82#define PATH_MAX MAXPATHLEN 83#else 84#define PATH_MAX 1024 85#endif /* MAXPATHLEN */ 86#endif /* !PATH_MAX */ 87 88#if !defined(MAXHOSTNAMELEN) 89#define MAXHOSTNAMELEN 32 90#endif /* !MAXHOSTNAMELEN */ 91 92#include "Configint.h" 93#include "xf86tokens.h" 94 95#define CONFIG_BUF_LEN 1024 96#define CONFIG_MAX_FILES 64 97 98static int StringToToken (char *, xf86ConfigSymTabRec *); 99 100static struct { 101 FILE *file; 102 char *path; 103} configFiles[CONFIG_MAX_FILES]; 104static const char **builtinConfig = NULL; 105static int builtinIndex = 0; 106static int configPos = 0; /* current readers position */ 107static int configLineNo = 0; /* linenumber */ 108static char *configBuf, *configRBuf; /* buffer for lines */ 109static char *configPath; /* path to config file */ 110static char *configDirPath; /* path to config dir */ 111static char *configSection = NULL; /* name of current section being parsed */ 112static int numFiles = 0; /* number of config files */ 113static int curFileIndex = 0; /* index of current config file */ 114static int pushToken = LOCK_TOKEN; 115static int eol_seen = 0; /* private state to handle comments */ 116LexRec val; 117 118/* 119 * xf86getNextLine -- 120 * 121 * read from the configFiles FILE stream until we encounter a new 122 * line; this is effectively just a big wrapper for fgets(3). 123 * 124 * xf86getToken() assumes that we will read up to the next 125 * newline; we need to grow configBuf and configRBuf as needed to 126 * support that. 127 */ 128 129static char* 130xf86getNextLine(void) 131{ 132 static int configBufLen = CONFIG_BUF_LEN; 133 char *tmpConfigBuf, *tmpConfigRBuf; 134 int c, i, pos = 0, eolFound = 0; 135 char *ret = NULL; 136 137 /* 138 * reallocate the string if it was grown last time (i.e., is no 139 * longer CONFIG_BUF_LEN); we malloc the new strings first, so 140 * that if either of the mallocs fail, we can fall back on the 141 * existing buffer allocations 142 */ 143 144 if (configBufLen != CONFIG_BUF_LEN) { 145 146 tmpConfigBuf = malloc(CONFIG_BUF_LEN); 147 tmpConfigRBuf = malloc(CONFIG_BUF_LEN); 148 149 if (!tmpConfigBuf || !tmpConfigRBuf) { 150 151 /* 152 * at least one of the mallocs failed; keep the old buffers 153 * and free any partial allocations 154 */ 155 156 free(tmpConfigBuf); 157 free(tmpConfigRBuf); 158 159 } else { 160 161 /* 162 * malloc succeeded; free the old buffers and use the new 163 * buffers 164 */ 165 166 configBufLen = CONFIG_BUF_LEN; 167 168 free(configBuf); 169 free(configRBuf); 170 171 configBuf = tmpConfigBuf; 172 configRBuf = tmpConfigRBuf; 173 } 174 } 175 176 /* read in another block of chars */ 177 178 do { 179 ret = fgets(configBuf + pos, configBufLen - pos - 1, 180 configFiles[curFileIndex].file); 181 182 if (!ret) { 183 /* 184 * if the file doesn't end in a newline, add one 185 * and trigger another read 186 */ 187 if (pos != 0) { 188 strcpy(&configBuf[pos], "\n"); 189 ret = configBuf; 190 } else 191 break; 192 } 193 194 /* search for EOL in the new block of chars */ 195 196 for (i = pos; i < (configBufLen - 1); i++) { 197 c = configBuf[i]; 198 199 if (c == '\0') break; 200 201 if ((c == '\n') || (c == '\r')) { 202 eolFound = 1; 203 break; 204 } 205 } 206 207 /* 208 * if we didn't find EOL, then grow the string and 209 * read in more 210 */ 211 212 if (!eolFound) { 213 214 tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN); 215 tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN); 216 217 if (!tmpConfigBuf || !tmpConfigRBuf) { 218 219 /* 220 * at least one of the reallocations failed; use the 221 * new allocation that succeeded, but we have to 222 * fallback to the previous configBufLen size and use 223 * the string we have, even though we don't have an 224 * EOL 225 */ 226 227 if (tmpConfigBuf) configBuf = tmpConfigBuf; 228 if (tmpConfigRBuf) configRBuf = tmpConfigRBuf; 229 230 break; 231 232 } else { 233 234 /* reallocation succeeded */ 235 236 configBuf = tmpConfigBuf; 237 configRBuf = tmpConfigRBuf; 238 pos = i; 239 configBufLen += CONFIG_BUF_LEN; 240 } 241 } 242 243 } while (!eolFound); 244 245 return ret; 246} 247 248/* 249 * xf86getToken -- 250 * Read next Token from the config file. Handle the global variable 251 * pushToken. 252 */ 253int 254xf86getToken (xf86ConfigSymTabRec * tab) 255{ 256 int c, i; 257 258 /* 259 * First check whether pushToken has a different value than LOCK_TOKEN. 260 * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the 261 * oth * case the next token must be read from the input. 262 */ 263 if (pushToken == EOF_TOKEN) 264 return EOF_TOKEN; 265 else if (pushToken == LOCK_TOKEN) 266 { 267 /* 268 * eol_seen is only set for the first token after a newline. 269 */ 270 eol_seen = 0; 271 272 c = configBuf[configPos]; 273 274 /* 275 * Get start of next Token. EOF is handled, 276 * whitespaces are skipped. 277 */ 278 279again: 280 if (!c) 281 { 282 char *ret; 283 if (numFiles > 0) 284 ret = xf86getNextLine(); 285 else { 286 if (builtinConfig[builtinIndex] == NULL) 287 ret = NULL; 288 else { 289 ret = strncpy(configBuf, builtinConfig[builtinIndex], 290 CONFIG_BUF_LEN); 291 builtinIndex++; 292 } 293 } 294 if (ret == NULL) 295 { 296 /* 297 * if necessary, move to the next file and 298 * read the first line 299 */ 300 if (curFileIndex + 1 < numFiles) { 301 curFileIndex++; 302 configLineNo = 0; 303 goto again; 304 } 305 else 306 return pushToken = EOF_TOKEN; 307 } 308 configLineNo++; 309 configPos = 0; 310 eol_seen = 1; 311 } 312 313 i = 0; 314 for (;;) { 315 c = configBuf[configPos++]; 316 configRBuf[i++] = c; 317 switch (c) { 318 case ' ': 319 case '\t': 320 case '\r': 321 continue; 322 case '\n': 323 i = 0; 324 continue; 325 } 326 break; 327 } 328 if (c == '\0') 329 goto again; 330 331 if (c == '#') 332 { 333 do 334 { 335 configRBuf[i++] = (c = configBuf[configPos++]); 336 } 337 while ((c != '\n') && (c != '\r') && (c != '\0')); 338 configRBuf[i] = '\0'; 339 /* XXX no private copy. 340 * Use xf86addComment when setting a comment. 341 */ 342 val.str = configRBuf; 343 return COMMENT; 344 } 345 346 /* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */ 347 else if ((c == ',') && !isalpha (configBuf[configPos])) 348 { 349 return COMMA; 350 } 351 else if ((c == '-') && !isalpha (configBuf[configPos])) 352 { 353 return DASH; 354 } 355 356 /* 357 * Numbers are returned immediately ... 358 */ 359 if (isdigit (c)) 360 { 361 int base; 362 363 if (c == '0') 364 if ((configBuf[configPos] == 'x') || 365 (configBuf[configPos] == 'X')) 366 { 367 base = 16; 368 val.numType = PARSE_HEX; 369 } 370 else 371 { 372 base = 8; 373 val.numType = PARSE_OCTAL; 374 } 375 else 376 { 377 base = 10; 378 val.numType = PARSE_DECIMAL; 379 } 380 381 configRBuf[0] = c; 382 i = 1; 383 while (isdigit (c = configBuf[configPos++]) || 384 (c == '.') || (c == 'x') || (c == 'X') || 385 ((base == 16) && (((c >= 'a') && (c <= 'f')) || 386 ((c >= 'A') && (c <= 'F'))))) 387 configRBuf[i++] = c; 388 configPos--; /* GJA -- one too far */ 389 configRBuf[i] = '\0'; 390 val.num = strtoul (configRBuf, NULL, 0); 391 val.realnum = atof (configRBuf); 392 return NUMBER; 393 } 394 395 /* 396 * All Strings START with a \" ... 397 */ 398 else if (c == '\"') 399 { 400 i = -1; 401 do 402 { 403 configRBuf[++i] = (c = configBuf[configPos++]); 404 } 405 while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0')); 406 configRBuf[i] = '\0'; 407 val.str = malloc (strlen (configRBuf) + 1); 408 strcpy (val.str, configRBuf); /* private copy ! */ 409 return STRING; 410 } 411 412 /* 413 * ... and now we MUST have a valid token. The search is 414 * handled later along with the pushed tokens. 415 */ 416 else 417 { 418 configRBuf[0] = c; 419 i = 0; 420 do 421 { 422 configRBuf[++i] = (c = configBuf[configPos++]); 423 } 424 while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0') && (c != '#')); 425 --configPos; 426 configRBuf[i] = '\0'; 427 i = 0; 428 } 429 430 } 431 else 432 { 433 434 /* 435 * Here we deal with pushed tokens. Reinitialize pushToken again. If 436 * the pushed token was NUMBER || STRING return them again ... 437 */ 438 int temp = pushToken; 439 pushToken = LOCK_TOKEN; 440 441 if (temp == COMMA || temp == DASH) 442 return temp; 443 if (temp == NUMBER || temp == STRING) 444 return temp; 445 } 446 447 /* 448 * Joop, at last we have to lookup the token ... 449 */ 450 if (tab) 451 { 452 i = 0; 453 while (tab[i].token != -1) 454 if (xf86nameCompare (configRBuf, tab[i].name) == 0) 455 return tab[i].token; 456 else 457 i++; 458 } 459 460 return ERROR_TOKEN; /* Error catcher */ 461} 462 463int 464xf86getSubToken (char **comment) 465{ 466 int token; 467 468 for (;;) { 469 token = xf86getToken(NULL); 470 if (token == COMMENT) { 471 if (comment) 472 *comment = xf86addComment(*comment, val.str); 473 } 474 else 475 return token; 476 } 477 /*NOTREACHED*/ 478} 479 480int 481xf86getSubTokenWithTab (char **comment, xf86ConfigSymTabRec *tab) 482{ 483 int token; 484 485 for (;;) { 486 token = xf86getToken(tab); 487 if (token == COMMENT) { 488 if (comment) 489 *comment = xf86addComment(*comment, val.str); 490 } 491 else 492 return token; 493 } 494 /*NOTREACHED*/ 495} 496 497void 498xf86unGetToken (int token) 499{ 500 pushToken = token; 501} 502 503char * 504xf86tokenString (void) 505{ 506 return configRBuf; 507} 508 509int 510xf86pathIsAbsolute(const char *path) 511{ 512 if (path && path[0] == '/') 513 return 1; 514 return 0; 515} 516 517/* A path is "safe" if it is relative and if it contains no ".." elements. */ 518int 519xf86pathIsSafe(const char *path) 520{ 521 if (xf86pathIsAbsolute(path)) 522 return 0; 523 524 /* Compare with ".." */ 525 if (!strcmp(path, "..")) 526 return 0; 527 528 /* Look for leading "../" */ 529 if (!strncmp(path, "../", 3)) 530 return 0; 531 532 /* Look for trailing "/.." */ 533 if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/..")) 534 return 0; 535 536 /* Look for "/../" */ 537 if (strstr(path, "/../")) 538 return 0; 539 540 return 1; 541} 542 543/* 544 * This function substitutes the following escape sequences: 545 * 546 * %A cmdline argument as an absolute path (must be absolute to match) 547 * %R cmdline argument as a relative path 548 * %S cmdline argument as a "safe" path (relative, and no ".." elements) 549 * %X default config file name ("xorg.conf") 550 * %H hostname 551 * %E config file environment ($XORGCONFIG) as an absolute path 552 * %F config file environment ($XORGCONFIG) as a relative path 553 * %G config file environment ($XORGCONFIG) as a safe path 554 * %P projroot 555 * %C sysconfdir 556 * %D datadir 557 * %% % 558 */ 559 560#ifndef XCONFIGFILE 561#define XCONFIGFILE "xorg.conf" 562#endif 563#ifndef XCONFIGDIR 564#define XCONFIGDIR "xorg.conf.d" 565#endif 566#ifndef XCONFIGSUFFIX 567#define XCONFIGSUFFIX ".conf" 568#endif 569#ifndef PROJECTROOT 570#define PROJECTROOT "/usr/X11R6" 571#endif 572#ifndef SYSCONFDIR 573#define SYSCONFDIR PROJECTROOT "/etc" 574#endif 575#ifndef DATADIR 576#define DATADIR PROJECTROOT "/share" 577#endif 578#ifndef XCONFENV 579#define XCONFENV "XORGCONFIG" 580#endif 581 582#define BAIL_OUT do { \ 583 free(result); \ 584 return NULL; \ 585 } while (0) 586 587#define CHECK_LENGTH do { \ 588 if (l > PATH_MAX) { \ 589 BAIL_OUT; \ 590 } \ 591 } while (0) 592 593#define APPEND_STR(s) do { \ 594 if (strlen(s) + l > PATH_MAX) { \ 595 BAIL_OUT; \ 596 } else { \ 597 strcpy(result + l, s); \ 598 l += strlen(s); \ 599 } \ 600 } while (0) 601 602static char * 603DoSubstitution(const char *template, const char *cmdline, const char *projroot, 604 int *cmdlineUsed, int *envUsed, 605 const char *XConfigFile) 606{ 607 char *result; 608 int i, l; 609 static const char *env = NULL; 610 static char *hostname = NULL; 611 612 if (!template) 613 return NULL; 614 615 if (cmdlineUsed) 616 *cmdlineUsed = 0; 617 if (envUsed) 618 *envUsed = 0; 619 620 result = malloc(PATH_MAX + 1); 621 l = 0; 622 for (i = 0; template[i]; i++) { 623 if (template[i] != '%') { 624 result[l++] = template[i]; 625 CHECK_LENGTH; 626 } else { 627 switch (template[++i]) { 628 case 'A': 629 if (cmdline && xf86pathIsAbsolute(cmdline)) { 630 APPEND_STR(cmdline); 631 if (cmdlineUsed) 632 *cmdlineUsed = 1; 633 } else 634 BAIL_OUT; 635 break; 636 case 'R': 637 if (cmdline && !xf86pathIsAbsolute(cmdline)) { 638 APPEND_STR(cmdline); 639 if (cmdlineUsed) 640 *cmdlineUsed = 1; 641 } else 642 BAIL_OUT; 643 break; 644 case 'S': 645 if (cmdline && xf86pathIsSafe(cmdline)) { 646 APPEND_STR(cmdline); 647 if (cmdlineUsed) 648 *cmdlineUsed = 1; 649 } else 650 BAIL_OUT; 651 break; 652 case 'X': 653 APPEND_STR(XConfigFile); 654 break; 655 case 'H': 656 if (!hostname) { 657 if ((hostname = malloc(MAXHOSTNAMELEN + 1))) { 658 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 659 hostname[MAXHOSTNAMELEN] = '\0'; 660 } else { 661 free(hostname); 662 hostname = NULL; 663 } 664 } 665 } 666 if (hostname) 667 APPEND_STR(hostname); 668 break; 669 case 'E': 670 if (!env) 671 env = getenv(XCONFENV); 672 if (env && xf86pathIsAbsolute(env)) { 673 APPEND_STR(env); 674 if (envUsed) 675 *envUsed = 1; 676 } else 677 BAIL_OUT; 678 break; 679 case 'F': 680 if (!env) 681 env = getenv(XCONFENV); 682 if (env && !xf86pathIsAbsolute(env)) { 683 APPEND_STR(env); 684 if (envUsed) 685 *envUsed = 1; 686 } else 687 BAIL_OUT; 688 break; 689 case 'G': 690 if (!env) 691 env = getenv(XCONFENV); 692 if (env && xf86pathIsSafe(env)) { 693 APPEND_STR(env); 694 if (envUsed) 695 *envUsed = 1; 696 } else 697 BAIL_OUT; 698 break; 699 case 'P': 700 if (projroot && xf86pathIsAbsolute(projroot)) 701 APPEND_STR(projroot); 702 else 703 BAIL_OUT; 704 break; 705 case 'C': 706 APPEND_STR(SYSCONFDIR); 707 break; 708 case 'D': 709 APPEND_STR(DATADIR); 710 break; 711 case '%': 712 result[l++] = '%'; 713 CHECK_LENGTH; 714 break; 715 default: 716 fprintf(stderr, "invalid escape %%%c found in path template\n", 717 template[i]); 718 BAIL_OUT; 719 break; 720 } 721 } 722 } 723#ifdef DEBUG 724 fprintf(stderr, "Converted `%s' to `%s'\n", template, result); 725#endif 726 return result; 727} 728 729/* 730 * Given some searching parameters, locate and open the xorg config file. 731 */ 732static char * 733OpenConfigFile(const char *path, const char *cmdline, const char *projroot, 734 const char *confname) 735{ 736 char *filepath = NULL; 737 char *pathcopy; 738 const char *template; 739 int cmdlineUsed = 0; 740 FILE *file = NULL; 741 742 pathcopy = strdup(path); 743 for (template = strtok(pathcopy, ","); template && !file; 744 template = strtok(NULL, ",")) { 745 filepath = DoSubstitution(template, cmdline, projroot, 746 &cmdlineUsed, NULL, confname); 747 if (!filepath) 748 continue; 749 if (cmdline && !cmdlineUsed) { 750 free(filepath); 751 filepath = NULL; 752 continue; 753 } 754 file = fopen(filepath, "r"); 755 if (!file) { 756 free(filepath); 757 filepath = NULL; 758 } 759 } 760 761 free(pathcopy); 762 if (file) { 763 configFiles[numFiles].file = file; 764 configFiles[numFiles].path = strdup(filepath); 765 numFiles++; 766 } 767 return filepath; 768} 769 770/* 771 * Match non-hidden files in the xorg config directory with a .conf 772 * suffix. This filter is passed to scandir(3). 773 */ 774static int 775ConfigFilter(const struct dirent *de) 776{ 777 const char *name = de->d_name; 778 size_t len; 779 size_t suflen = strlen(XCONFIGSUFFIX); 780 781 if (!name || name[0] == '.') 782 return 0; 783 len = strlen(name); 784 if(len <= suflen) 785 return 0; 786 if (strcmp(&name[len-suflen], XCONFIGSUFFIX) != 0) 787 return 0; 788 return 1; 789} 790 791static Bool 792AddConfigDirFiles(const char *dirpath, struct dirent **list, int num) 793{ 794 int i; 795 Bool openedFile = FALSE; 796 Bool warnOnce = FALSE; 797 798 for (i = 0; i < num; i++) { 799 char *path; 800 FILE *file; 801 802 if (numFiles >= CONFIG_MAX_FILES) { 803 if (!warnOnce) { 804 ErrorF("Maximum number of configuration " 805 "files opened\n"); 806 warnOnce = TRUE; 807 } 808 free(list[i]); 809 continue; 810 } 811 812 path = malloc(PATH_MAX + 1); 813 snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, 814 list[i]->d_name); 815 free(list[i]); 816 file = fopen(path, "r"); 817 if (!file) { 818 free(path); 819 continue; 820 } 821 openedFile = TRUE; 822 823 configFiles[numFiles].file = file; 824 configFiles[numFiles].path = path; 825 numFiles++; 826 } 827 828 return openedFile; 829} 830 831/* 832 * Given some searching parameters, locate and open the xorg config 833 * directory. The directory does not need to contain config files. 834 */ 835static char * 836OpenConfigDir(const char *path, const char *cmdline, const char *projroot, 837 const char *confname) 838{ 839 char *dirpath, *pathcopy; 840 const char *template; 841 Bool found = FALSE; 842 int cmdlineUsed = 0; 843 844 pathcopy = strdup(path); 845 for (template = strtok(pathcopy, ","); template && !found; 846 template = strtok(NULL, ",")) { 847 struct dirent **list = NULL; 848 int num; 849 850 dirpath = DoSubstitution(template, cmdline, projroot, 851 &cmdlineUsed, NULL, confname); 852 if (!dirpath) 853 continue; 854 if (cmdline && !cmdlineUsed) { 855 free(dirpath); 856 dirpath = NULL; 857 continue; 858 } 859 860 /* match files named *.conf */ 861 num = scandir(dirpath, &list, ConfigFilter, alphasort); 862 found = AddConfigDirFiles(dirpath, list, num); 863 if (!found) { 864 free(dirpath); 865 dirpath = NULL; 866 free(list); 867 } 868 } 869 870 free(pathcopy); 871 return dirpath; 872} 873 874/* 875 * xf86initConfigFiles -- Setup global variables and buffers. 876 */ 877void 878xf86initConfigFiles(void) 879{ 880 curFileIndex = 0; 881 configPos = 0; 882 configLineNo = 0; 883 pushToken = LOCK_TOKEN; 884 885 configBuf = malloc(CONFIG_BUF_LEN); 886 configRBuf = malloc(CONFIG_BUF_LEN); 887 configBuf[0] = '\0'; /* sanity ... */ 888} 889 890/* 891 * xf86openConfigFile -- 892 * 893 * This function take a config file search path (optional), a command-line 894 * specified file name (optional) and the ProjectRoot path (optional) and 895 * locates and opens a config file based on that information. If a 896 * command-line file name is specified, then this function fails if none 897 * of the located files. 898 * 899 * The return value is a pointer to the actual name of the file that was 900 * opened. When no file is found, the return value is NULL. 901 * 902 * The escape sequences allowed in the search path are defined above. 903 * 904 */ 905 906#ifndef DEFAULT_CONF_PATH 907#define DEFAULT_CONF_PATH "/etc/X11/%S," \ 908 "%P/etc/X11/%S," \ 909 "/etc/X11/%G," \ 910 "%P/etc/X11/%G," \ 911 "/etc/X11/%X-%M," \ 912 "/etc/X11/%X," \ 913 "/etc/%X," \ 914 "%P/etc/X11/%X.%H," \ 915 "%P/etc/X11/%X-%M," \ 916 "%P/etc/X11/%X," \ 917 "%P/lib/X11/%X.%H," \ 918 "%P/lib/X11/%X-%M," \ 919 "%P/lib/X11/%X" 920#endif 921 922const char * 923xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) 924{ 925 if (!path || !path[0]) 926 path = DEFAULT_CONF_PATH; 927 if (!projroot || !projroot[0]) 928 projroot = PROJECTROOT; 929 930 /* Search for a config file */ 931 configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE); 932 return configPath; 933} 934 935/* 936 * xf86openConfigDirFiles -- 937 * 938 * This function take a config directory search path (optional), a 939 * command-line specified directory name (optional) and the ProjectRoot path 940 * (optional) and locates and opens a config directory based on that 941 * information. If a command-line name is specified, then this function 942 * fails if it is not found. 943 * 944 * The return value is a pointer to the actual name of the direcoty that was 945 * opened. When no directory is found, the return value is NULL. 946 * 947 * The escape sequences allowed in the search path are defined above. 948 * 949 */ 950const char * 951xf86openConfigDirFiles(const char *path, const char *cmdline, 952 const char *projroot) 953{ 954 if (!path || !path[0]) 955 path = DEFAULT_CONF_PATH; 956 if (!projroot || !projroot[0]) 957 projroot = PROJECTROOT; 958 959 /* Search for the multiconf directory */ 960 configDirPath = OpenConfigDir(path, cmdline, projroot, XCONFIGDIR); 961 return configDirPath; 962} 963 964void 965xf86closeConfigFile (void) 966{ 967 int i; 968 969 free (configPath); 970 configPath = NULL; 971 free (configDirPath); 972 configDirPath = NULL; 973 free (configRBuf); 974 configRBuf = NULL; 975 free (configBuf); 976 configBuf = NULL; 977 978 if (numFiles == 0) { 979 builtinConfig = NULL; 980 builtinIndex = 0; 981 } 982 for (i = 0; i < numFiles; i++) { 983 fclose(configFiles[i].file); 984 configFiles[i].file = NULL; 985 free(configFiles[i].path); 986 configFiles[i].path = NULL; 987 } 988 numFiles = 0; 989} 990 991void 992xf86setBuiltinConfig(const char *config[]) 993{ 994 builtinConfig = config; 995} 996 997void 998xf86parseError (char *format,...) 999{ 1000 va_list ap; 1001 char *filename = numFiles ? configFiles[curFileIndex].path : 1002 "<builtin configuration>"; 1003 1004 ErrorF ("Parse error on line %d of section %s in file %s\n\t", 1005 configLineNo, configSection, filename); 1006 va_start (ap, format); 1007 VErrorF (format, ap); 1008 va_end (ap); 1009 1010 ErrorF ("\n"); 1011} 1012 1013void 1014xf86validationError (char *format,...) 1015{ 1016 va_list ap; 1017 char *filename = numFiles ? configFiles[curFileIndex].path : 1018 "<builtin configuration>"; 1019 1020 ErrorF ("Data incomplete in file %s\n\t", filename); 1021 va_start (ap, format); 1022 VErrorF (format, ap); 1023 va_end (ap); 1024 1025 ErrorF ("\n"); 1026} 1027 1028void 1029xf86setSection (char *section) 1030{ 1031 free(configSection); 1032 configSection = strdup(section); 1033} 1034 1035/* 1036 * xf86getToken -- 1037 * Lookup a string if it is actually a token in disguise. 1038 */ 1039int 1040xf86getStringToken (xf86ConfigSymTabRec * tab) 1041{ 1042 return StringToToken (val.str, tab); 1043} 1044 1045static int 1046StringToToken (char *str, xf86ConfigSymTabRec * tab) 1047{ 1048 int i; 1049 1050 for (i = 0; tab[i].token != -1; i++) 1051 { 1052 if (!xf86nameCompare (tab[i].name, str)) 1053 return tab[i].token; 1054 } 1055 return ERROR_TOKEN; 1056} 1057 1058 1059/* 1060 * Compare two names. The characters '_', ' ', and '\t' are ignored 1061 * in the comparison. 1062 */ 1063int 1064xf86nameCompare (const char *s1, const char *s2) 1065{ 1066 char c1, c2; 1067 1068 if (!s1 || *s1 == 0) { 1069 if (!s2 || *s2 == 0) 1070 return 0; 1071 else 1072 return 1; 1073 } 1074 1075 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1076 s1++; 1077 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1078 s2++; 1079 c1 = (isupper (*s1) ? tolower (*s1) : *s1); 1080 c2 = (isupper (*s2) ? tolower (*s2) : *s2); 1081 while (c1 == c2) 1082 { 1083 if (c1 == '\0') 1084 return 0; 1085 s1++; 1086 s2++; 1087 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1088 s1++; 1089 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1090 s2++; 1091 c1 = (isupper (*s1) ? tolower (*s1) : *s1); 1092 c2 = (isupper (*s2) ? tolower (*s2) : *s2); 1093 } 1094 return c1 - c2; 1095} 1096 1097char * 1098xf86addComment(char *cur, char *add) 1099{ 1100 char *str; 1101 int len, curlen, iscomment, hasnewline = 0, endnewline; 1102 1103 if (add == NULL || add[0] == '\0') 1104 return cur; 1105 1106 if (cur) { 1107 curlen = strlen(cur); 1108 if (curlen) 1109 hasnewline = cur[curlen - 1] == '\n'; 1110 eol_seen = 0; 1111 } 1112 else 1113 curlen = 0; 1114 1115 str = add; 1116 iscomment = 0; 1117 while (*str) { 1118 if (*str != ' ' && *str != '\t') 1119 break; 1120 ++str; 1121 } 1122 iscomment = (*str == '#'); 1123 1124 len = strlen(add); 1125 endnewline = add[len - 1] == '\n'; 1126 len += 1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen; 1127 1128 if ((str = realloc(cur, len + curlen)) == NULL) 1129 return cur; 1130 1131 cur = str; 1132 1133 if (eol_seen || (curlen && !hasnewline)) 1134 cur[curlen++] = '\n'; 1135 if (!iscomment) 1136 cur[curlen++] = '#'; 1137 strcpy(cur + curlen, add); 1138 if (!endnewline) 1139 strcat(cur, "\n"); 1140 1141 return cur; 1142} 1143 1144Bool 1145xf86getBoolValue(Bool *val, const char *str) 1146{ 1147 if (!val || !str) 1148 return FALSE; 1149 if (*str == '\0') { 1150 *val = TRUE; 1151 } else { 1152 if (xf86nameCompare(str, "1") == 0) 1153 *val = TRUE; 1154 else if (xf86nameCompare(str, "on") == 0) 1155 *val = TRUE; 1156 else if (xf86nameCompare(str, "true") == 0) 1157 *val = TRUE; 1158 else if (xf86nameCompare(str, "yes") == 0) 1159 *val = TRUE; 1160 else if (xf86nameCompare(str, "0") == 0) 1161 *val = FALSE; 1162 else if (xf86nameCompare(str, "off") == 0) 1163 *val = FALSE; 1164 else if (xf86nameCompare(str, "false") == 0) 1165 *val = FALSE; 1166 else if (xf86nameCompare(str, "no") == 0) 1167 *val = FALSE; 1168 else 1169 return FALSE; 1170 } 1171 return TRUE; 1172} 1173