config.c revision bbe1b32b
1/* $Xorg: config.c,v 1.4 2001/02/09 02:05:44 xorgcvs Exp $ */ 2/* 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 * Copyright 1990, 1991 Network Computing Devices; 25 * Portions Copyright 1987 by Digital Equipment Corporation 26 * 27 * Permission to use, copy, modify, distribute, and sell this software and its 28 * documentation for any purpose is hereby granted without fee, provided that 29 * the above copyright notice appear in all copies and that both that 30 * copyright notice and this permission notice appear in supporting 31 * documentation, and that the names of Network Computing Devices, 32 * or Digital not be used in advertising or 33 * publicity pertaining to distribution of the software without specific, 34 * written prior permission. Network Computing Devices, or Digital 35 * make no representations about the 36 * suitability of this software for any purpose. It is provided "as is" 37 * without express or implied warranty. 38 * 39 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH 40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 41 * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, OR DIGITAL BE 42 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 43 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 44 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 45 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 46 * 47 * $NCDXorg: @(#)config.c,v 4.6 1991/07/09 14:08:09 lemke Exp $ 48 * 49 */ 50/* $XFree86: xc/programs/xfs/os/config.c,v 3.15 2002/05/31 18:46:12 dawes Exp $ */ 51 52#include <xfs-config.h> 53 54#include <stdio.h> 55#include <stdlib.h> 56#include <ctype.h> 57#include <X11/Xtrans/Xtrans.h> 58#include <X11/Xos.h> 59#include "misc.h" 60#include "configstr.h" 61#include "osdep.h" 62#include "globals.h" 63#include "access.h" 64#include "difsutils.h" 65#ifdef FONTCACHE 66#include <X11/extensions/fontcacheP.h> 67#endif 68#include <X11/fonts/fontutil.h> 69#include "difs.h" 70 71static const char * const default_config_files[] = { 72#ifdef DEFAULT_CONFIG_FILE 73 DEFAULT_CONFIG_FILE, 74#else 75 "/usr/lib/X11/fs/config", 76#endif 77 NULL 78}; 79 80extern int portFromCmdline; 81 82static char *font_catalogue = NULL; 83 84static char *config_set_int(ConfigOptionPtr parm, char *val); 85static char *config_set_bool(ConfigOptionPtr parm, char *val); 86static char *config_set_catalogue(ConfigOptionPtr parm, char *val); 87static char *config_set_glyph_caching_mode(ConfigOptionPtr parm, char *val); 88static char *config_set_list(ConfigOptionPtr parm, char *val); 89static char *config_set_file(ConfigOptionPtr parm, char *val); 90static char *config_set_resolutions(ConfigOptionPtr parm, char *val); 91static char *config_set_ignored_transports(ConfigOptionPtr parm, char *val); 92static char *config_set_snf_format(ConfigOptionPtr parm, char *val); 93 94/* these need to be in lower case and alphabetical order so a 95 * binary search lookup can be used 96 */ 97static ConfigOptionRec config_options[] = { 98 {"alternate-servers", config_set_list}, 99#ifdef FONTCACHE 100 {"cache-balance", config_set_int}, 101 {"cache-hi-mark", config_set_int}, 102 {"cache-low-mark", config_set_int}, 103#endif 104 {"catalogue", config_set_catalogue}, 105 {"client-limit", config_set_int}, 106 {"clone-self", config_set_bool}, 107 {"default-point-size", config_set_int}, 108 {"default-resolutions", config_set_resolutions}, 109 {"deferglyphs", config_set_glyph_caching_mode}, 110 {"error-file", config_set_file}, 111 {"no-listen", config_set_ignored_transports}, 112 {"port", config_set_int}, 113 {"server-number", config_set_int}, 114 {"snf-format", config_set_snf_format}, 115 {"trusted-clients", config_set_list}, 116 {"use-syslog", config_set_bool}, 117 {(char *) 0, 0}, 118}; 119 120char *ConfigErrors[] = { 121 "", 122 "CONFIG: insufficient memory to load configuration file \"%s\"\n", 123 "CONFIG: can't open configuration file \"%s\"\n", 124 "CONFIG: error reading configuration file \"%s\"\n", 125 "CONFIG: bad value \"%s\" for parameter \"%s\"\n", 126 "CONFIG: unknown parameter \"%s\"\n", 127 "CONFIG: missing '=' after parameter \"%s\"\n", 128 "CONFIG: value out of range for parameter \"%s\"\n", 129 "CONFIG: syntax error near parameter \"%s\"\n", 130 "CONFIG: missing value for parameter \"%s\"\n", 131 "CONFIG: extra value for parameter \"%s\"\n", 132}; 133 134#define iseol(c) ((c) == '\n' || (c) == '\r' || (c) == '\f') 135#define skip_whitespace(c) while(isspace(*(c)) || *(c) == ',') (c)++; 136#define skip_val(c) while(!isspace(*(c)) && *(c) != ',' && *(c) != '\0')\ 137 (c) ++; 138#define skip_list_val(c) while(!isspace(*(c)) && *(c) != '\0')\ 139 (c) ++; 140#define blank_comment(c) while (!iseol(*(c)) && *(c) != '\0') \ 141 *(c)++= ' '; 142 143static char * 144next_assign(char *c) 145{ 146 int nesting = 0; 147 148 while (*c != '\0') { 149 if (*c == '(') 150 nesting++; 151 else if (*c == ')') 152 nesting--; 153 else if (*c == '=' && nesting == 0) 154 return c; 155 c++; 156 } 157 return (char *) 0; 158} 159 160static void 161strip_comments(char *data) 162{ 163 char *c; 164 165 c = data; 166 while ((c = strchr(c, '#')) != NULL) { 167 if (c == data || *(c - 1) != '\\') { 168 blank_comment(c); 169 } else { 170 c++; 171 } 172 } 173} 174 175static ConfigOptionPtr 176match_param_name(char *name) 177{ 178 int pos, 179 rc, 180 low, 181 high; 182 183 low = 0; 184 high = sizeof(config_options) / sizeof(ConfigOptionRec) - 2; 185 pos = high >> 1; 186 187 while (low <= high) { 188 rc = strcmp(name, config_options[pos].parm_name); 189 if (rc == 0) { 190 return &config_options[pos]; 191 } else if (rc < 0) { 192 high = pos - 1; 193 } else { 194 low = pos + 1; 195 } 196 pos = ((high + low) >> 1); 197 } 198 return 0; 199} 200 201static int 202parse_config(char *data) 203{ 204 char *c, 205 *val = NULL, 206 *next_eq, 207 *consumed, 208 *p; 209 char param_name[64]; 210 Bool equals_missing; 211 ConfigOptionPtr param; 212 213 c = data; 214 skip_whitespace(c); 215 216 while (*c != '\0') { 217 equals_missing = FALSE; 218 219 /* get parm name in lower case */ 220 p = c; 221 while (isalnum(*c) || *c == '-') { 222 if (isupper(*c)) 223 *c = tolower(*c); 224 c++; 225 } 226 memmove( param_name, p, min(sizeof(param_name), (int) (c - p))); 227 param_name[(int) (c - p)] = '\0'; 228 229 /* check for junk */ 230 if (!isspace(*c) && *c != '=') { 231 ErrorF(ConfigErrors[CONFIG_ERR_SYNTAX], param_name); 232 /* eat garbage */ 233 while (!isspace(*c) && *c != '=' && *c != '\0') 234 c++; 235 } 236 skip_whitespace(c); 237 if (*c != '=') { 238 ErrorF(ConfigErrors[CONFIG_ERR_NOEQUALS], param_name); 239 equals_missing = TRUE; 240 } else { 241 c++; 242 } 243 244 skip_whitespace(c); 245 246 /* find next assignment to guess where the value ends */ 247 if ((next_eq = next_assign(c)) != NULL) { 248 /* back up over whitespace */ 249 for (val = next_eq - 1; val >= c && 250 (isspace(*val) || *val == ','); 251 val--); 252 253 /* back over parm name */ 254 for (; val >= c && (isalnum(*val) || *val == '-'); val--); 255 256 if (val <= c) { 257 /* no value, ignore */ 258 ErrorF(ConfigErrors[CONFIG_ERR_NOVALUE], param_name); 259 continue; 260 } 261 *val = '\0'; 262 } else if (*c == '\0') { 263 /* no value, ignore */ 264 ErrorF(ConfigErrors[CONFIG_ERR_NOVALUE], param_name); 265 continue; 266 } 267 /* match parm name */ 268 if (equals_missing) { 269 equals_missing = FALSE; 270 } else if ((param = match_param_name(param_name)) == NULL) { 271 ErrorF(ConfigErrors[CONFIG_ERR_UNKNOWN], param_name); 272 } else { 273 consumed = (param->set_func) (param, c); 274 275 skip_whitespace(consumed); 276 if (*consumed != '\0') { 277 ErrorF(ConfigErrors[CONFIG_ERR_EXTRAVALUE], 278 param_name); 279 } 280 } 281 282 if (next_eq != NULL) 283 c = val + 1; 284 else /* last setting */ 285 break; 286 } 287 return FSSuccess; 288} 289 290/* 291 * handles anything that should be set once the file is parsed 292 */ 293void 294SetConfigValues(void) 295{ 296 int err, 297 num; 298 299 if (font_catalogue == NULL) { 300 FatalError("font catalogue is missing/empty\n"); 301 } 302 303 err = SetFontCatalogue(font_catalogue, &num); 304 if (err != FSSuccess) { 305 FatalError("element #%d (starting at 0) of font path is bad or has a bad font:\n\"%s\"\n", 306 num, font_catalogue); 307 } 308 InitErrors(); 309 fsfree((char *) font_catalogue); 310 font_catalogue = NULL; 311} 312 313#ifdef __UNIXOS2__ 314char *__XFSRedirRoot(char *fname) 315{ 316 static char redirname[300]; /* enough for long filenames */ 317 char *root; 318 319 /* if name does not start with /, assume it is not root-based */ 320 if (fname==0 || !(fname[0]=='/' || fname[0]=='\\')) 321 return fname; 322 323 root = (char*)getenv("X11ROOT"); 324 if (root==0 || 325 (fname[1]==':' && isalpha(fname[0])) || 326 ((strlen(fname)+strlen(root)+2) > 300)) 327 return fname; 328 sprintf(redirname,"%s%s",root,fname); 329 return redirname; 330} 331#endif 332 333/* If argument is NULL, uses first file found from default_config_files */ 334int 335ReadConfigFile(const char *filename) 336{ 337 FILE *fp; 338 int ret; 339 int len; 340 int i; 341 char *data; 342 343 data = (char *) fsalloc(CONFIG_MAX_FILESIZE); 344 if (!data) { 345 ErrorF(ConfigErrors[CONFIG_ERR_MEMORY], filename); 346 return FSBadAlloc; 347 } 348 if (filename != NULL) { 349#ifdef __UNIXOS2__ 350 filename = __XFSRedirRoot(filename); 351#endif 352 fp = fopen(filename, "r"); 353 if (fp == NULL) { 354 ErrorF(ConfigErrors[CONFIG_ERR_OPEN], filename); 355 } 356 } else { 357 for (i = 0; default_config_files[i] != NULL; i++) { 358 filename = default_config_files[i]; 359#ifdef __UNIXOS2__ 360 filename = __XFSRedirRoot(filename); 361#endif 362 if ((fp = fopen(filename, "r")) != NULL) 363 break; 364 } 365 if (fp == NULL) { 366 for (i = 0; default_config_files[i] != NULL; i++) { 367 ErrorF(ConfigErrors[CONFIG_ERR_OPEN], default_config_files[i]); 368 } 369 } 370 } 371 if (fp == NULL) { 372 fsfree(data); 373 return FSBadName; 374 } 375 ret = fread(data, sizeof(char), CONFIG_MAX_FILESIZE, fp); 376 if (ret <= 0) { 377 fsfree(data); 378 (void) fclose(fp); 379 ErrorF(ConfigErrors[CONFIG_ERR_READ], filename); 380 return FSBadName; 381 } 382 len = ftell(fp); 383 len = min(len, CONFIG_MAX_FILESIZE); 384 data[len] = '\0'; /* NULL terminate the data */ 385 386 (void) fclose(fp); 387 388 strip_comments(data); 389 ret = parse_config(data); 390 391 fsfree(data); 392 393 return ret; 394} 395 396struct nameVal { 397 char *name; 398 int val; 399}; 400 401static char * 402config_parse_nameVal ( 403 char *c, 404 int *ret, 405 int *pval, 406 struct nameVal *name_val) 407{ 408 char *start, 409 t; 410 int i, 411 len; 412 413 start = c; 414 skip_val(c); 415 t = *c; 416 *c = '\0'; 417 len = c - start; 418 419 for (i = 0; name_val[i].name; i++) { 420 if (!strncmpnocase(start, name_val[i].name, len)) { 421 *pval = name_val[i].val; 422 *ret = 0; 423 *c = t; 424 return c; 425 } 426 } 427 ErrorF(ConfigErrors[CONFIG_ERR_VALUE], start); 428 *c = t; 429 *ret = -1; 430 return c; 431} 432 433static char * 434config_parse_bool ( 435 char *c, 436 int *ret, 437 Bool *pval) 438{ 439 static struct nameVal bool_val[] = { 440 { "yes", TRUE }, 441 { "on", TRUE }, 442 { "1", TRUE }, 443 { "true", TRUE }, 444 { "no", FALSE }, 445 { "off", FALSE }, 446 { "0", FALSE }, 447 { "false", FALSE }, 448 { (char *) 0, 0 }, 449 }; 450 return config_parse_nameVal (c, ret, pval, bool_val); 451} 452 453static char * 454config_parse_int( 455 char *c, 456 int *ret, 457 int *pval) 458{ 459 char *start, 460 t; 461 462 start = c; 463 while (*c != '\0' && !isspace(*c) && *c != ',') { 464 if (!isdigit(*c)) { /* error */ 465 skip_val(c); 466 t = *c; 467 *c = '\0'; 468 ErrorF(ConfigErrors[CONFIG_ERR_VALUE], start); 469 *ret = -1; 470 *c = t; 471 return c; 472 } 473 c++; 474 } 475 t = *c; 476 *c = '\0'; 477 *ret = 0; 478 *pval = atoi(start); 479 *c = t; 480 return c; 481} 482 483 484/* config option sets */ 485/* these have to know how to do the real work and tweak the proper things */ 486static char * 487config_set_int( 488 ConfigOptionPtr parm, 489 char *val) 490{ 491 int ival, 492 ret; 493 494 val = config_parse_int(val, &ret, &ival); 495 if (ret == -1) 496 return val; 497 498 /* now do individual attribute checks */ 499 if (!strcmp(parm->parm_name, "port") && !portFromCmdline) { 500 ListenPort = ival; 501 } else if (!strcmp(parm->parm_name, "client-limit")) { 502 AccessSetConnectionLimit(ival); 503 } else if (!strcmp(parm->parm_name, "default-point-size")) { 504 SetDefaultPointSize(ival); 505 } 506#ifdef FONTCACHE 507 else if (!strcmp(parm->parm_name, "cache-balance")) { 508 cacheSettings.balance = ival; 509 } else if (!strcmp(parm->parm_name, "cache-hi-mark")) { 510 cacheSettings.himark = ival * 1024; 511 } else if (!strcmp(parm->parm_name, "cache-low-mark")) { 512 cacheSettings.lowmark = ival * 1024; 513 } 514#endif 515 return val; 516} 517 518static char * 519config_set_bool( 520 ConfigOptionPtr parm, 521 char *val) 522{ 523 int 524 ret; 525 Bool bval; 526 527 val = config_parse_bool(val, &ret, &bval); 528 if (ret == -1) 529 return val; 530 531 /* now do individual attribute checks */ 532 if (!strcmp(parm->parm_name, "use-syslog")) { 533 UseSyslog = bval; 534 } else if (!strcmp(parm->parm_name, "clone-self")) { 535 CloneSelf = bval; 536 } 537 return val; 538} 539 540static char * 541config_set_file( 542 ConfigOptionPtr parm, 543 char *val) 544{ 545 char *start = val, 546 t; 547 548 skip_val(val); 549 t = *val; 550 *val = '\0'; 551 if (!strcmp(parm->parm_name, "error-file")) { 552#ifndef __UNIXOS2__ 553 memmove( ErrorFile, start, val - start + 1); 554#else 555 strcpy( ErrorFile, __XFSRedirRoot(start)); 556#endif 557 } 558 *val = t; 559 return val; 560} 561 562static char * 563config_set_catalogue( 564 ConfigOptionPtr parm, 565 char *val) 566{ 567 char *b; 568 569 if (!strcmp(parm->parm_name, "catalogue")) { 570 /* stash it for later */ 571 fsfree((char *) font_catalogue); /* dump any previous one */ 572 b = font_catalogue = (char *) fsalloc(strlen(val) + 1); 573 if (!font_catalogue) 574 FatalError("insufficent memory for font catalogue\n"); 575 while (*val) { /* remove all the gunk */ 576 if (!isspace(*val)) { 577 *b++ = *val; 578 } 579 val++; 580 } 581 *b = '\0'; 582 } 583 return val; 584} 585 586static char * 587config_set_list( 588 ConfigOptionPtr parm, 589 char *val) 590{ 591 char *start = val, 592 t; 593 594 skip_list_val(val); 595 t = *val; 596 *val = '\0'; 597 if (!strcmp(parm->parm_name, "alternate-servers")) { 598 SetAlternateServers(start); 599 } 600 *val = t; 601 return val; 602} 603 604static char * 605config_set_ignored_transports( 606 ConfigOptionPtr parm, 607 char *val) 608{ 609 char *start = val, 610 t; 611 612 skip_list_val(val); 613 t = *val; 614 *val = '\0'; 615 _FontTransNoListen(start); 616 *val = t; 617 return val; 618} 619 620static char * 621config_set_glyph_caching_mode( 622 ConfigOptionPtr parm, 623 char *val) 624{ 625 char *start = val, 626 t; 627 628 skip_list_val(val); 629 t = *val; 630 *val = '\0'; 631 if (!strcmp(parm->parm_name, "deferglyphs")) { 632 ParseGlyphCachingMode(start); 633 } 634 *val = t; 635 return val; 636} 637 638static char * 639config_set_resolutions( 640 ConfigOptionPtr parm, 641 char *val) 642{ 643 char *start = val, 644 t; 645 int err; 646 647 skip_list_val(val); 648 t = *val; 649 *val = '\0'; 650 if (!strcmp(parm->parm_name, "default-resolutions")) { 651 err = SetDefaultResolutions(start); 652 if (err != FSSuccess) { 653 FatalError("bogus resolution list \"%s\"\n", start); 654 } 655 } 656 *val = t; 657 return val; 658} 659 660 661static char * 662config_parse_endian( 663 char *c, 664 int *ret, 665 int *pval) 666{ 667 static struct nameVal endian_val[] = { 668 { "lsb", LSBFirst }, 669 { "little", LSBFirst }, 670 { "lsbfirst", LSBFirst }, 671 { "msb", MSBFirst }, 672 { "big", MSBFirst }, 673 { "msbfirst", MSBFirst }, 674 { (char *) 0, 0 }, 675 }; 676 return config_parse_nameVal (c, ret, pval, endian_val); 677} 678 679/* ARGSUSED */ 680static char * 681config_set_snf_format ( 682 ConfigOptionPtr parm, 683 char *val) 684{ 685 int bit, byte, glyph, scan; 686 int ret; 687 688 val = config_parse_endian (val, &ret, &bit); 689 if (ret == -1) 690 return val; 691 skip_whitespace (val); 692 val = config_parse_endian (val, &ret, &byte); 693 if (ret == -1) 694 return val; 695 skip_whitespace (val); 696 val = config_parse_int (val, &ret, &glyph); 697 if (ret == -1) 698 return val; 699 skip_whitespace (val); 700 val = config_parse_int (val, &ret, &scan); 701 if (ret == -1) 702 return val; 703 SnfSetFormat (bit, byte, glyph, scan); 704 return val; 705} 706