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