Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120825983
libconfig.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
18 KB
Referenced Files
None
Subscribers
None
libconfig.c
View Options
/* libconfig.c -- imapd.conf handling
*
* Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: libconfig.c,v 1.26 2010/04/19 19:54:26 murch Exp $
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<ctype.h>
#include
<syslog.h>
#include
<sys/types.h>
#include
<netinet/in.h>
#include
<sys/stat.h>
#include
"assert.h"
#include
"hash.h"
#include
"libconfig.h"
#include
"imapopts.h"
#include
"xmalloc.h"
#include
"xstrlcat.h"
#include
"xstrlcpy.h"
#include
"util.h"
#define CONFIGHASHSIZE 30
/* relatively small,
* because it is for overflow only */
#define INCLUDEHASHSIZE 5
/* relatively small,
* but how many includes are reasonable? */
static
struct
hash_table
confighash
,
includehash
;
/* cached configuration variables accessible to the external world */
const
char
*
config_filename
=
NULL
;
/* filename of configuration file */
const
char
*
config_dir
=
NULL
;
/* ie /var/imap */
const
char
*
config_defpartition
=
NULL
;
/* /var/spool/imap */
const
char
*
config_servername
=
NULL
;
/* gethostname() */
enum
enum_value
config_serverinfo
;
/* on */
const
char
*
config_mupdate_server
=
NULL
;
/* NULL */
const
char
*
config_defdomain
=
NULL
;
/* NULL */
const
char
*
config_ident
=
NULL
;
/* the service name */
int
config_hashimapspool
;
/* f */
enum
enum_value
config_virtdomains
;
/* f */
enum
enum_value
config_mupdate_config
;
/* IMAP_ENUM_MUPDATE_CONFIG_STANDARD */
int
config_auditlog
;
unsigned
config_maxword
;
unsigned
config_maxquoted
;
int
config_qosmarking
;
/* declared in each binary that uses libconfig */
extern
const
int
config_need_data
;
extern
void
fatal
(
const
char
*
fatal_message
,
int
fatal_code
)
__attribute__
((
noreturn
));
/* prototype to allow for sane function ordering */
void
config_read_file
(
const
char
*
filename
);
const
char
*
config_getstring
(
enum
imapopt
opt
)
{
assert
(
opt
>
IMAPOPT_ZERO
&&
opt
<
IMAPOPT_LAST
);
assert
((
imapopts
[
opt
].
t
==
OPT_STRING
)
||
(
imapopts
[
opt
].
t
==
OPT_STRINGLIST
));
return
imapopts
[
opt
].
val
.
s
;
}
int
config_getint
(
enum
imapopt
opt
)
{
assert
(
opt
>
IMAPOPT_ZERO
&&
opt
<
IMAPOPT_LAST
);
assert
(
imapopts
[
opt
].
t
==
OPT_INT
);
#if (SIZEOF_LONG != 4)
if
((
imapopts
[
opt
].
val
.
i
>
0x7fffffff
)
||
(
imapopts
[
opt
].
val
.
i
<
-0x7fffffff
))
{
syslog
(
LOG_ERR
,
"config_getint: %s: %ld too large for type"
,
imapopts
[
opt
].
optname
,
imapopts
[
opt
].
val
.
i
);
}
#endif
return
imapopts
[
opt
].
val
.
i
;
}
int
config_getswitch
(
enum
imapopt
opt
)
{
assert
(
opt
>
IMAPOPT_ZERO
&&
opt
<
IMAPOPT_LAST
);
assert
(
imapopts
[
opt
].
t
==
OPT_SWITCH
);
#if (SIZEOF_LONG != 4)
if
((
imapopts
[
opt
].
val
.
b
>
0x7fffffff
)
||
(
imapopts
[
opt
].
val
.
b
<
-0x7fffffff
))
{
syslog
(
LOG_ERR
,
"config_getswitch: %s: %ld too large for type"
,
imapopts
[
opt
].
optname
,
imapopts
[
opt
].
val
.
b
);
}
#endif
return
imapopts
[
opt
].
val
.
b
;
}
enum
enum_value
config_getenum
(
enum
imapopt
opt
)
{
assert
(
opt
>
IMAPOPT_ZERO
&&
opt
<
IMAPOPT_LAST
);
assert
(
imapopts
[
opt
].
t
==
OPT_ENUM
);
return
imapopts
[
opt
].
val
.
e
;
}
unsigned
long
config_getbitfield
(
enum
imapopt
opt
)
{
assert
(
opt
>
IMAPOPT_ZERO
&&
opt
<
IMAPOPT_LAST
);
assert
(
imapopts
[
opt
].
t
==
OPT_BITFIELD
);
return
imapopts
[
opt
].
val
.
x
;
}
const
char
*
config_getoverflowstring
(
const
char
*
key
,
const
char
*
def
)
{
char
buf
[
256
];
char
*
ret
=
NULL
;
if
(
!
config_filename
)
return
0
;
/* First lookup <ident>_key, to see if we have a service-specific
* override */
if
(
config_ident
)
{
if
(
snprintf
(
buf
,
sizeof
(
buf
),
"%s_%s"
,
config_ident
,
key
)
==
-1
)
fatal
(
"key too long in config_getoverflowstring"
,
EC_TEMPFAIL
);
ret
=
hash_lookup
(
buf
,
&
confighash
);
}
/* No service-specific override, check the actual key */
if
(
!
ret
)
ret
=
hash_lookup
(
key
,
&
confighash
);
/* Return what we got or the default */
return
ret
?
ret
:
def
;
}
void
config_foreachoverflowstring
(
void
(
*
func
)(
const
char
*
,
const
char
*
,
void
*
),
void
*
rock
)
{
if
(
!
config_filename
)
return
;
hash_enumerate
(
&
confighash
,
(
void
(
*
)(
char
*
,
void
*
,
void
*
))
func
,
rock
);
}
const
char
*
config_partitiondir
(
const
char
*
partition
)
{
char
buf
[
80
];
if
(
strlcpy
(
buf
,
"partition-"
,
sizeof
(
buf
))
>=
sizeof
(
buf
))
return
0
;
if
(
strlcat
(
buf
,
partition
,
sizeof
(
buf
))
>=
sizeof
(
buf
))
return
0
;
return
config_getoverflowstring
(
buf
,
NULL
);
}
const
char
*
config_metapartitiondir
(
const
char
*
partition
)
{
char
buf
[
80
];
if
(
strlcpy
(
buf
,
"metapartition-"
,
sizeof
(
buf
))
>=
sizeof
(
buf
))
return
0
;
if
(
strlcat
(
buf
,
partition
,
sizeof
(
buf
))
>=
sizeof
(
buf
))
return
0
;
return
config_getoverflowstring
(
buf
,
NULL
);
}
static
void
config_ispartition
(
const
char
*
key
,
const
char
*
val
__attribute__
((
unused
)),
void
*
rock
)
{
int
*
found
=
(
int
*
)
rock
;
if
(
!
strncmp
(
"partition-"
,
key
,
10
))
*
found
=
1
;
}
static
const
unsigned
char
qos
[]
=
{
/* cs0..cs7 */
0x00
,
0x20
,
0x40
,
0x60
,
0x80
,
0xa0
,
0xc0
,
0xe0
,
/* af11..af13 */
0x28
,
0x30
,
0x38
,
/* af21..af23 */
0x48
,
0x50
,
0x58
,
/* af31..af33 */
0x68
,
0x70
,
0x78
,
/* af41..af43 */
0x88
,
0x90
,
0x98
,
/* ef */
0xb8
};
void
config_read
(
const
char
*
alt_config
)
{
enum
imapopt
opt
=
IMAPOPT_ZERO
;
char
buf
[
4096
];
char
*
p
;
int
ival
;
/* xxx this is leaked, this may be able to be better in 2.2 (cyrus_done) */
if
(
alt_config
)
config_filename
=
xstrdup
(
alt_config
);
else
config_filename
=
xstrdup
(
CONFIG_FILENAME
);
if
(
!
construct_hash_table
(
&
confighash
,
CONFIGHASHSIZE
,
1
))
{
fatal
(
"could not construct configuration hash table"
,
EC_CONFIG
);
}
if
(
!
construct_hash_table
(
&
includehash
,
INCLUDEHASHSIZE
,
1
))
{
fatal
(
"could not construct include file hash table"
,
EC_CONFIG
);
}
config_read_file
(
config_filename
);
free_hash_table
(
&
includehash
,
NULL
);
/* Check configdirectory config option */
if
(
!
config_dir
)
{
fatal
(
"configdirectory option not specified in configuration file"
,
EC_CONFIG
);
}
/* Scan options to see if we need to replace {configdirectory} */
/* xxx need to scan overflow options as well! */
for
(
opt
=
IMAPOPT_ZERO
;
opt
<
IMAPOPT_LAST
;
opt
++
)
{
if
(
!
imapopts
[
opt
].
val
.
s
||
imapopts
[
opt
].
t
!=
OPT_STRING
||
opt
==
IMAPOPT_CONFIGDIRECTORY
)
{
/* Skip options that have a NULL value, aren't strings, or
* are the configdirectory option */
continue
;
}
/* We use some magic numbers here,
* 17 is the length of "{configdirectory}",
* 16 is one less than that length, so that the replacement string
* that is malloced has room for the '\0' */
if
(
!
strncasecmp
(
imapopts
[
opt
].
val
.
s
,
"{configdirectory}"
,
17
))
{
const
char
*
str
=
imapopts
[
opt
].
val
.
s
;
char
*
newstring
=
xmalloc
(
strlen
(
config_dir
)
+
strlen
(
str
)
-
16
);
char
*
freeme
=
NULL
;
/* we need to replace this string, will we need to free
* the current value? -- only if we've actually seen it in
* the config file. */
if
(
imapopts
[
opt
].
seen
)
freeme
=
(
char
*
)
str
;
/* Build replacement string from configdirectory option */
strcpy
(
newstring
,
config_dir
);
strcat
(
newstring
,
str
+
17
);
imapopts
[
opt
].
val
.
s
=
newstring
;
if
(
freeme
)
free
(
freeme
);
}
}
/* Look up default partition */
config_defpartition
=
config_getstring
(
IMAPOPT_DEFAULTPARTITION
);
for
(
p
=
(
char
*
)
config_defpartition
;
p
&&
*
p
;
p
++
)
{
if
(
!
Uisalnum
(
*
p
))
fatal
(
"defaultpartition option contains non-alphanumeric character"
,
EC_CONFIG
);
if
(
Uisupper
(
*
p
))
*
p
=
tolower
((
unsigned
char
)
*
p
);
}
if
(
config_need_data
&
CONFIG_NEED_PARTITION_DATA
)
{
int
found
=
0
;
if
(
config_defpartition
)
{
/* see if defaultpartition is specified properly */
if
(
config_partitiondir
(
config_defpartition
))
found
=
1
;
}
else
{
/* see if we have ANY partition-<name> options */
config_foreachoverflowstring
(
config_ispartition
,
&
found
);
}
if
(
!
found
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"partition-%s option not specified in configuration file"
,
config_defpartition
?
config_defpartition
:
"<name>"
);
fatal
(
buf
,
EC_CONFIG
);
}
}
/* look up mailbox hashing */
config_hashimapspool
=
config_getswitch
(
IMAPOPT_HASHIMAPSPOOL
);
/* are we supporting virtual domains? */
config_virtdomains
=
config_getenum
(
IMAPOPT_VIRTDOMAINS
);
config_defdomain
=
config_getstring
(
IMAPOPT_DEFAULTDOMAIN
);
/* are we auditlogging */
config_auditlog
=
config_getswitch
(
IMAPOPT_AUDITLOG
);
/* look up the hostname and info we should present to the user */
config_servername
=
config_getstring
(
IMAPOPT_SERVERNAME
);
if
(
!
config_servername
)
{
config_servername
=
xmalloc
(
sizeof
(
char
)
*
256
);
gethostname
((
char
*
)
config_servername
,
256
);
}
config_serverinfo
=
config_getenum
(
IMAPOPT_SERVERINFO
);
config_mupdate_server
=
config_getstring
(
IMAPOPT_MUPDATE_SERVER
);
if
(
config_mupdate_server
)
{
config_mupdate_config
=
config_getenum
(
IMAPOPT_MUPDATE_CONFIG
);
}
/* set some limits */
config_maxquoted
=
config_getint
(
IMAPOPT_MAXQUOTED
);
config_maxword
=
config_getint
(
IMAPOPT_MAXWORD
);
ival
=
config_getenum
(
IMAPOPT_QOSMARKING
);
config_qosmarking
=
qos
[
ival
];
}
#define GROWSIZE 4096
void
config_read_file
(
const
char
*
filename
)
{
FILE
*
infile
;
enum
imapopt
opt
=
IMAPOPT_ZERO
;
int
lineno
=
0
;
char
*
buf
,
errbuf
[
1024
];
unsigned
bufsize
,
len
;
char
*
p
,
*
q
,
*
key
,
*
fullkey
,
*
srvkey
,
*
val
,
*
newval
;
int
service_specific
;
int
idlen
=
(
config_ident
?
strlen
(
config_ident
)
:
0
);
bufsize
=
GROWSIZE
;
buf
=
xmalloc
(
bufsize
);
/* read in config file */
infile
=
fopen
(
filename
,
"r"
);
if
(
!
infile
)
{
strlcpy
(
buf
,
CYRUS_PATH
,
bufsize
);
strlcat
(
buf
,
filename
,
bufsize
);
infile
=
fopen
(
buf
,
"r"
);
}
if
(
!
infile
)
{
snprintf
(
buf
,
bufsize
,
"can't open configuration file %s: %s"
,
filename
,
error_message
(
errno
));
fatal
(
buf
,
EC_CONFIG
);
}
/* check to see if we've already read this file */
if
(
hash_lookup
(
filename
,
&
includehash
))
{
snprintf
(
buf
,
bufsize
,
"configuration file %s included twice"
,
filename
);
fatal
(
buf
,
EC_CONFIG
);
}
else
{
hash_insert
(
filename
,
(
void
*
)
0xDEADBEEF
,
&
includehash
);
}
len
=
0
;
while
(
fgets
(
buf
+
len
,
bufsize
-
len
,
infile
))
{
if
(
buf
[
len
])
{
len
=
strlen
(
buf
);
if
(
buf
[
len
-1
]
==
'\n'
)
{
/* end of line */
buf
[
--
len
]
=
'\0'
;
if
(
len
&&
buf
[
len
-1
]
==
'\\'
)
{
/* line continuation */
len
--
;
lineno
++
;
continue
;
}
}
else
if
(
!
feof
(
infile
)
&&
len
==
bufsize
-1
)
{
/* line is longer than the buffer */
bufsize
+=
GROWSIZE
;
buf
=
xrealloc
(
buf
,
bufsize
);
continue
;
}
}
len
=
0
;
lineno
++
;
service_specific
=
0
;
/* remove leading whitespace */
for
(
p
=
buf
;
*
p
&&
Uisspace
(
*
p
);
p
++
);
/* skip comments */
if
(
!*
p
||
*
p
==
'#'
)
continue
;
fullkey
=
key
=
p
;
if
(
*
p
==
'@'
)
p
++
;
/* allow @ as the first char (for directives) */
while
(
*
p
&&
(
Uisalnum
(
*
p
)
||
*
p
==
'-'
||
*
p
==
'_'
))
{
if
(
Uisupper
(
*
p
))
*
p
=
tolower
((
unsigned
char
)
*
p
);
p
++
;
}
if
(
*
p
!=
':'
)
{
snprintf
(
errbuf
,
sizeof
(
errbuf
),
"invalid option name on line %d of configuration file %s"
,
lineno
,
filename
);
fatal
(
errbuf
,
EC_CONFIG
);
}
*
p
++
=
'\0'
;
/* remove leading whitespace */
while
(
*
p
&&
Uisspace
(
*
p
))
p
++
;
/* remove trailing whitespace */
for
(
q
=
p
+
strlen
(
p
)
-
1
;
q
>
p
&&
Uisspace
(
*
q
);
q
--
)
{
*
q
=
'\0'
;
}
if
(
!*
p
)
{
snprintf
(
errbuf
,
sizeof
(
errbuf
),
"empty option value on line %d of configuration file"
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
srvkey
=
NULL
;
/* Look for directives */
if
(
key
[
0
]
==
'@'
)
{
if
(
!
strcasecmp
(
key
,
"@include"
))
{
config_read_file
(
p
);
continue
;
}
else
{
snprintf
(
errbuf
,
sizeof
(
errbuf
),
"invalid directive on line %d of configuration file %s"
,
lineno
,
filename
);
fatal
(
errbuf
,
EC_CONFIG
);
}
}
/* Find if there is a <service>_ prefix */
if
(
config_ident
&&
!
strncasecmp
(
key
,
config_ident
,
idlen
)
&&
key
[
idlen
]
==
'_'
)
{
/* skip service_ prefix */
srvkey
=
key
+
idlen
+
1
;
}
/* look for a service_ prefix match in imapopts */
if
(
srvkey
)
{
for
(
opt
=
IMAPOPT_ZERO
;
opt
<
IMAPOPT_LAST
;
opt
++
)
{
if
(
!
strcasecmp
(
imapopts
[
opt
].
optname
,
srvkey
))
{
key
=
srvkey
;
service_specific
=
1
;
break
;
}
}
}
/* Did not find a service_ specific match, try looking for an
* exact match */
if
(
!
service_specific
)
{
for
(
opt
=
IMAPOPT_ZERO
;
opt
<
IMAPOPT_LAST
;
opt
++
)
{
if
(
!
strcasecmp
(
imapopts
[
opt
].
optname
,
key
))
{
break
;
}
}
}
/* If both of those loops failed, it goes verbatim into the
* overflow hash table. */
if
(
opt
<
IMAPOPT_LAST
)
{
/* Okay, we know about this configure option.
* So first check that we have either
* 1. not seen it
* 2. seen its generic form, but this is a service specific form
*
* If we have already seen a service-specific form, and this is
* a generic form, just skip it and don't moan.
*/
if
((
imapopts
[
opt
].
seen
==
1
&&
!
service_specific
)
||
(
imapopts
[
opt
].
seen
==
2
&&
service_specific
))
{
sprintf
(
errbuf
,
"option '%s' was specified twice in config file (second occurance on line %d)"
,
fullkey
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
else
if
(
imapopts
[
opt
].
seen
==
2
&&
!
service_specific
)
{
continue
;
}
/* If we've seen it already, we're replacing it, so we need
* to free the current string if there is one */
if
(
imapopts
[
opt
].
seen
&&
imapopts
[
opt
].
t
==
OPT_STRING
)
free
((
char
*
)
imapopts
[
opt
].
val
.
s
);
if
(
service_specific
)
imapopts
[
opt
].
seen
=
2
;
else
imapopts
[
opt
].
seen
=
1
;
/* this is a known option */
switch
(
imapopts
[
opt
].
t
)
{
case
OPT_STRING
:
{
imapopts
[
opt
].
val
.
s
=
xstrdup
(
p
);
if
(
opt
==
IMAPOPT_CONFIGDIRECTORY
)
config_dir
=
imapopts
[
opt
].
val
.
s
;
break
;
}
case
OPT_INT
:
{
long
val
;
char
*
ptr
;
val
=
strtol
(
p
,
&
ptr
,
0
);
if
(
!
ptr
||
*
ptr
!=
'\0'
)
{
/* error during conversion */
sprintf
(
errbuf
,
"non-integer value for %s in line %d"
,
imapopts
[
opt
].
optname
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
imapopts
[
opt
].
val
.
i
=
val
;
break
;
}
case
OPT_SWITCH
:
{
if
(
*
p
==
'0'
||
*
p
==
'n'
||
(
*
p
==
'o'
&&
p
[
1
]
==
'f'
)
||
*
p
==
'f'
)
{
imapopts
[
opt
].
val
.
b
=
0
;
}
else
if
(
*
p
==
'1'
||
*
p
==
'y'
||
(
*
p
==
'o'
&&
p
[
1
]
==
'n'
)
||
*
p
==
't'
)
{
imapopts
[
opt
].
val
.
b
=
1
;
}
else
{
/* error during conversion */
sprintf
(
errbuf
,
"non-switch value for %s in line %d"
,
imapopts
[
opt
].
optname
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
break
;
}
case
OPT_ENUM
:
case
OPT_STRINGLIST
:
case
OPT_BITFIELD
:
{
const
struct
enum_option_s
*
e
;
/* zero the value */
memset
(
&
imapopts
[
opt
].
val
,
0
,
sizeof
(
imapopts
[
opt
].
val
));
/* q is already at EOS so we'll process entire the string
as one value unless told otherwise */
if
(
imapopts
[
opt
].
t
==
OPT_ENUM
)
{
/* normalize on/off values */
if
(
!
strcmp
(
p
,
"1"
)
||
!
strcmp
(
p
,
"yes"
)
||
!
strcmp
(
p
,
"t"
)
||
!
strcmp
(
p
,
"true"
))
{
p
=
"on"
;
}
else
if
(
!
strcmp
(
p
,
"0"
)
||
!
strcmp
(
p
,
"no"
)
||
!
strcmp
(
p
,
"f"
)
||
!
strcmp
(
p
,
"false"
))
{
p
=
"off"
;
}
}
else
if
(
imapopts
[
opt
].
t
==
OPT_BITFIELD
)
{
/* split the string into separate values */
q
=
p
;
}
while
(
*
p
)
{
/* find the end of the first value */
for
(;
*
q
&&
!
Uisspace
(
*
q
);
q
++
);
if
(
*
q
)
*
q
++
=
'\0'
;
/* see if its a legal value */
for
(
e
=
imapopts
[
opt
].
enum_options
;
e
->
name
&&
strcmp
(
e
->
name
,
p
);
e
++
);
if
(
!
e
->
name
)
{
/* error during conversion */
sprintf
(
errbuf
,
"invalid value '%s' for %s in line %d"
,
p
,
imapopts
[
opt
].
optname
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
else
if
(
imapopts
[
opt
].
t
==
OPT_STRINGLIST
)
imapopts
[
opt
].
val
.
s
=
e
->
name
;
else
if
(
imapopts
[
opt
].
t
==
OPT_ENUM
)
imapopts
[
opt
].
val
.
e
=
e
->
val
;
else
imapopts
[
opt
].
val
.
x
|=
e
->
val
;
/* find the start of the next value */
for
(
p
=
q
;
*
p
&&
Uisspace
(
*
p
);
p
++
);
q
=
p
;
}
break
;
}
case
OPT_NOTOPT
:
default
:
abort
();
}
}
else
{
/* check to make sure it's valid for overflow */
/* that is, partition names and anything that might be
* used by SASL */
/*
xxx this would be nice if it wasn't for other services who might be
sharing this config file and whose names we cannot predict
if(strncasecmp(key,"sasl_",5)
&& strncasecmp(key,"partition-",10)) {
sprintf(errbuf,
"option '%s' is unknown on line %d of config file",
fullkey, lineno);
fatal(errbuf, EC_CONFIG);
}
*/
/* Put it in the overflow hash table */
newval
=
xstrdup
(
p
);
val
=
hash_insert
(
key
,
newval
,
&
confighash
);
if
(
val
!=
newval
)
{
snprintf
(
errbuf
,
sizeof
(
errbuf
),
"option '%s' was specified twice in config file (second occurance on line %d)"
,
fullkey
,
lineno
);
fatal
(
errbuf
,
EC_CONFIG
);
}
}
}
fclose
(
infile
);
free
(
buf
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 10:47 AM (5 d, 1 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18840411
Default Alt Text
libconfig.c (18 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline