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