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