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