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 "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 "difs.h" 62#include <X11/fonts/libxfont2.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 109/* max size in bytes of config file */ 110#define CONFIG_MAX_FILESIZE 32767 111 112#define CONFIG_ERR_MEMORY \ 113 "CONFIG: insufficient memory to load configuration file \"%s\"\n" 114#define CONFIG_ERR_OPEN "CONFIG: can't open configuration file \"%s\"\n" 115#define CONFIG_ERR_READ "CONFIG: error reading configuration file \"%s\"\n" 116#define CONFIG_ERR_VALUE "CONFIG: bad value \"%s\" for parameter \"%s\"\n" 117#define CONFIG_ERR_UNKNOWN "CONFIG: unknown parameter \"%s\"\n" 118#define CONFIG_ERR_NOEQUALS "CONFIG: missing '=' after parameter \"%s\"\n" 119#define CONFIG_ERR_RANGE "CONFIG: value out of range for parameter \"%s\"\n" 120#define CONFIG_ERR_SYNTAX "CONFIG: syntax error near parameter \"%s\"\n" 121#define CONFIG_ERR_NOVALUE "CONFIG: missing value for parameter \"%s\"\n" 122#define CONFIG_ERR_EXTRAVALUE "CONFIG: extra value for parameter \"%s\"\n" 123 124#define iseol(c) ((c) == '\n' || (c) == '\r' || (c) == '\f') 125#define skip_whitespace(c) while(isspace(*(c)) || *(c) == ',') (c)++; 126#define skip_val(c) while(!isspace(*(c)) && *(c) != ',' && *(c) != '\0')\ 127 (c) ++; 128#define skip_list_val(c) while(!isspace(*(c)) && *(c) != '\0')\ 129 (c) ++; 130#define blank_comment(c) while (!iseol(*(c)) && *(c) != '\0') \ 131 *(c)++= ' '; 132 133static char * 134next_assign(char *c) 135{ 136 int nesting = 0; 137 138 while (*c != '\0') { 139 if (*c == '(') 140 nesting++; 141 else if (*c == ')') 142 nesting--; 143 else if (*c == '=' && nesting == 0) 144 return c; 145 c++; 146 } 147 return (char *) 0; 148} 149 150static void 151strip_comments(char *data) 152{ 153 char *c; 154 155 c = data; 156 while ((c = strchr(c, '#')) != NULL) { 157 if (c == data || *(c - 1) != '\\') { 158 blank_comment(c); 159 } else { 160 c++; 161 } 162 } 163} 164 165static ConfigOptionPtr 166match_param_name(char *name) 167{ 168 int pos, 169 rc, 170 low, 171 high; 172 173 low = 0; 174 high = sizeof(config_options) / sizeof(ConfigOptionRec) - 2; 175 pos = high >> 1; 176 177 while (low <= high) { 178 rc = strcmp(name, config_options[pos].parm_name); 179 if (rc == 0) { 180 return &config_options[pos]; 181 } else if (rc < 0) { 182 high = pos - 1; 183 } else { 184 low = pos + 1; 185 } 186 pos = ((high + low) >> 1); 187 } 188 return NULL; 189} 190 191static int 192parse_config(char *data) 193{ 194 char *c, 195 *val = NULL, 196 *next_eq, 197 *consumed, 198 *p; 199 char param_name[64]; 200 Bool equals_missing; 201 ConfigOptionPtr param; 202 203 c = data; 204 skip_whitespace(c); 205 206 while (*c != '\0') { 207 equals_missing = FALSE; 208 209 /* get parm name in lower case */ 210 p = c; 211 while (isalnum(*c) || *c == '-') { 212 if (isupper(*c)) 213 *c = tolower(*c); 214 c++; 215 } 216 memcpy(param_name, p, min(sizeof(param_name), (int) (c - p))); 217 param_name[(int) (c - p)] = '\0'; 218 219 /* check for junk */ 220 if (!isspace(*c) && *c != '=') { 221 ErrorF(CONFIG_ERR_SYNTAX, param_name); 222 /* eat garbage */ 223 while (!isspace(*c) && *c != '=' && *c != '\0') 224 c++; 225 } 226 skip_whitespace(c); 227 if (*c != '=') { 228 ErrorF(CONFIG_ERR_NOEQUALS, param_name); 229 equals_missing = TRUE; 230 } else { 231 c++; 232 } 233 234 skip_whitespace(c); 235 236 /* find next assignment to guess where the value ends */ 237 if ((next_eq = next_assign(c)) != NULL) { 238 /* back up over whitespace */ 239 for (val = next_eq - 1; val >= c && 240 (isspace(*val) || *val == ','); 241 val--); 242 243 /* back over parm name */ 244 for (; val >= c && (isalnum(*val) || *val == '-'); val--); 245 246 if (val <= c) { 247 /* no value, ignore */ 248 ErrorF(CONFIG_ERR_NOVALUE, param_name); 249 continue; 250 } 251 *val = '\0'; 252 } else if (*c == '\0') { 253 /* no value, ignore */ 254 ErrorF(CONFIG_ERR_NOVALUE, param_name); 255 continue; 256 } 257 /* match parm name */ 258 if (equals_missing) { 259 equals_missing = FALSE; 260 } else if ((param = match_param_name(param_name)) == NULL) { 261 ErrorF(CONFIG_ERR_UNKNOWN, param_name); 262 } else { 263 consumed = (param->set_func) (param, c); 264 265 skip_whitespace(consumed); 266 if (*consumed != '\0') { 267 ErrorF(CONFIG_ERR_EXTRAVALUE, 268 param_name); 269 } 270 } 271 272 if (next_eq != NULL) 273 c = val + 1; 274 else /* last setting */ 275 break; 276 } 277 return FSSuccess; 278} 279 280/* 281 * handles anything that should be set once the file is parsed 282 */ 283void 284SetConfigValues(void) 285{ 286 int err, 287 num; 288 289 if (font_catalogue == NULL) { 290 FatalError("font catalogue is missing/empty\n"); 291 } 292 293 err = SetFontCatalogue(font_catalogue, &num); 294 if (err != FSSuccess) { 295 FatalError("element #%d (starting at 0) of font path is bad or has a bad font:\n\"%s\"\n", 296 num, font_catalogue); 297 } 298 InitErrors(); 299 FSfree((char *) font_catalogue); 300 font_catalogue = NULL; 301} 302 303 304/* If argument is NULL, uses first file found from default_config_files */ 305int 306ReadConfigFile(const char *filename) 307{ 308 FILE *fp = NULL; 309 int ret; 310 int len; 311 int i; 312 char *data; 313 314 data = (char *) FSalloc(CONFIG_MAX_FILESIZE); 315 if (!data) { 316 ErrorF(CONFIG_ERR_MEMORY, filename); 317 return FSBadAlloc; 318 } 319 if (filename != NULL) { 320 fp = fopen(filename, "r"); 321 if (fp == NULL) { 322 ErrorF(CONFIG_ERR_OPEN, filename); 323 } 324 } else { 325 for (i = 0; default_config_files[i] != NULL; i++) { 326 filename = default_config_files[i]; 327 if ((fp = fopen(filename, "r")) != NULL) { 328 if (configfilename == NULL) { 329 configfilename = strdup(filename); /* save for clones */ 330 } 331 break; 332 } 333 } 334 if (fp == NULL) { 335 for (i = 0; default_config_files[i] != NULL; i++) { 336 ErrorF(CONFIG_ERR_OPEN, default_config_files[i]); 337 } 338 } 339 } 340 if (fp == NULL) { 341 FSfree(data); 342 return FSBadName; 343 } 344 ret = fread(data, sizeof(char), CONFIG_MAX_FILESIZE, fp); 345 if (ret <= 0) { 346 FSfree(data); 347 (void) fclose(fp); 348 ErrorF(CONFIG_ERR_READ, filename); 349 return FSBadName; 350 } 351 len = ftell(fp); 352 len = min(len, CONFIG_MAX_FILESIZE); 353 data[len] = '\0'; /* NULL terminate the data */ 354 355 (void) fclose(fp); 356 357 strip_comments(data); 358 ret = parse_config(data); 359 360 FSfree(data); 361 362 return ret; 363} 364 365struct nameVal { 366 const char *name; 367 int val; 368}; 369 370static char * 371config_parse_nameVal ( 372 ConfigOptionPtr parm, 373 char *c, 374 int *ret, 375 int *pval, 376 struct nameVal *name_val) 377{ 378 char *start, 379 t; 380 int i, 381 len; 382 383 start = c; 384 skip_val(c); 385 t = *c; 386 *c = '\0'; 387 len = c - start; 388 389 for (i = 0; name_val[i].name; i++) { 390 if (!strncmpnocase(start, name_val[i].name, len)) { 391 *pval = name_val[i].val; 392 *ret = 0; 393 *c = t; 394 return c; 395 } 396 } 397 ErrorF(CONFIG_ERR_VALUE, start, parm->parm_name); 398 *c = t; 399 *ret = -1; 400 return c; 401} 402 403static char * 404config_parse_bool ( 405 ConfigOptionPtr parm, 406 char *c, 407 int *ret, 408 Bool *pval) 409{ 410 static struct nameVal bool_val[] = { 411 { "yes", TRUE }, 412 { "on", TRUE }, 413 { "1", TRUE }, 414 { "true", TRUE }, 415 { "no", FALSE }, 416 { "off", FALSE }, 417 { "0", FALSE }, 418 { "false", FALSE }, 419 { (char *) 0, 0 }, 420 }; 421 return config_parse_nameVal (parm, c, ret, pval, bool_val); 422} 423 424static char * 425config_parse_int( 426 ConfigOptionPtr parm, 427 char *c, 428 int *ret, 429 int *pval) 430{ 431 char *start, 432 t; 433 434 start = c; 435 while (*c != '\0' && !isspace(*c) && *c != ',') { 436 if (!isdigit(*c)) { /* error */ 437 skip_val(c); 438 t = *c; 439 *c = '\0'; 440 ErrorF(CONFIG_ERR_VALUE, start, parm->parm_name); 441 *ret = -1; 442 *c = t; 443 return c; 444 } 445 c++; 446 } 447 t = *c; 448 *c = '\0'; 449 *ret = 0; 450 *pval = atoi(start); 451 *c = t; 452 return c; 453} 454 455 456/* config option sets */ 457/* these have to know how to do the real work and tweak the proper things */ 458static char * 459config_set_int( 460 ConfigOptionPtr parm, 461 char *val) 462{ 463 int ival, 464 ret; 465 466 val = config_parse_int(parm, val, &ret, &ival); 467 if (ret == -1) 468 return val; 469 470 /* now do individual attribute checks */ 471 if (!strcmp(parm->parm_name, "port") && !portFromCmdline) { 472 ListenPort = ival; 473 } else if (!strcmp(parm->parm_name, "client-limit")) { 474 AccessSetConnectionLimit(ival); 475 } else if (!strcmp(parm->parm_name, "default-point-size")) { 476 SetDefaultPointSize(ival); 477 } 478 return val; 479} 480 481static char * 482config_set_bool( 483 ConfigOptionPtr parm, 484 char *val) 485{ 486 int 487 ret; 488 Bool bval; 489 490 val = config_parse_bool(parm, val, &ret, &bval); 491 if (ret == -1) 492 return val; 493 494 /* now do individual attribute checks */ 495 if (!strcmp(parm->parm_name, "use-syslog")) { 496 UseSyslog = bval; 497 } else if (!strcmp(parm->parm_name, "clone-self")) { 498 CloneSelf = bval; 499 } 500 return val; 501} 502 503static char * 504config_set_file( 505 ConfigOptionPtr parm, 506 char *val) 507{ 508 char *start = val, 509 t; 510 511 skip_val(val); 512 t = *val; 513 *val = '\0'; 514 if (!strcmp(parm->parm_name, "error-file")) { 515 memmove( ErrorFile, start, val - start + 1); 516 } 517 *val = t; 518 return val; 519} 520 521static char * 522config_set_catalogue( 523 ConfigOptionPtr parm, 524 char *val) 525{ 526 char *b; 527 528 if (!strcmp(parm->parm_name, "catalogue")) { 529 /* stash it for later */ 530 FSfree((char *) font_catalogue); /* dump any previous one */ 531 b = font_catalogue = (char *) FSalloc(strlen(val) + 1); 532 if (!font_catalogue) 533 FatalError("insufficient memory for font catalogue\n"); 534 while (*val) { /* remove all the gunk */ 535 if (!isspace(*val)) { 536 *b++ = *val; 537 } 538 val++; 539 } 540 *b = '\0'; 541 } 542 return val; 543} 544 545static char * 546config_set_list( 547 ConfigOptionPtr parm, 548 char *val) 549{ 550 char *start = val, 551 t; 552 553 skip_list_val(val); 554 t = *val; 555 *val = '\0'; 556 if (!strcmp(parm->parm_name, "alternate-servers")) { 557 SetAlternateServers(start); 558 } 559 *val = t; 560 return val; 561} 562 563static char * 564config_set_ignored_transports( 565 ConfigOptionPtr parm, 566 char *val) 567{ 568 char *start = val, 569 t; 570 571 skip_list_val(val); 572 t = *val; 573 *val = '\0'; 574 _FontTransNoListen(start); 575 *val = t; 576 return val; 577} 578 579static char * 580config_set_glyph_caching_mode( 581 ConfigOptionPtr parm, 582 char *val) 583{ 584 char *start = val, 585 t; 586 587 skip_list_val(val); 588 t = *val; 589 *val = '\0'; 590 if (!strcmp(parm->parm_name, "deferglyphs")) { 591 xfont2_parse_glyph_caching_mode(start); 592 } 593 *val = t; 594 return val; 595} 596 597static char * 598config_set_resolutions( 599 ConfigOptionPtr parm, 600 char *val) 601{ 602 char *start = val, 603 t; 604 int err; 605 606 skip_list_val(val); 607 t = *val; 608 *val = '\0'; 609 if (!strcmp(parm->parm_name, "default-resolutions")) { 610 err = SetDefaultResolutions(start); 611 if (err != FSSuccess) { 612 FatalError("bogus resolution list \"%s\"\n", start); 613 } 614 } 615 *val = t; 616 return val; 617} 618 619 620static char * 621config_parse_endian( 622 ConfigOptionPtr parm, 623 char *c, 624 int *ret, 625 int *pval) 626{ 627 static struct nameVal endian_val[] = { 628 { "lsb", LSBFirst }, 629 { "little", LSBFirst }, 630 { "lsbfirst", LSBFirst }, 631 { "msb", MSBFirst }, 632 { "big", MSBFirst }, 633 { "msbfirst", MSBFirst }, 634 { (char *) 0, 0 }, 635 }; 636 return config_parse_nameVal (parm, c, ret, pval, endian_val); 637} 638 639/* ARGSUSED */ 640static char * 641config_set_snf_format ( 642 ConfigOptionPtr parm, 643 char *val) 644{ 645 int bit, byte, glyph, scan; 646 int ret; 647 648 val = config_parse_endian (parm, val, &ret, &bit); 649 if (ret == -1) 650 return val; 651 skip_whitespace (val); 652 val = config_parse_endian (parm, val, &ret, &byte); 653 if (ret == -1) 654 return val; 655 skip_whitespace (val); 656 val = config_parse_int (parm, val, &ret, &glyph); 657 if (ret == -1) 658 return val; 659 skip_whitespace (val); 660 val = config_parse_int (parm, val, &ret, &scan); 661 if (ret == -1) 662 return val; 663#ifdef XFONT_SNFFORMAT 664 SnfSetFormat (bit, byte, glyph, scan); 665#endif 666 return val; 667} 668