fix several problems with config parser:

a bug where it underflows the string
 a bug where it never frees parser_t struct
make read_config() return 0 if parser is NULL,
 make config_close() accept and ignore NULL parser -
 eliminates many if() blocks
reverse the sense of parser bit flags - negative flags
 are harder to grok.
hexdump: revert the change to use config parser, it is BIGGER
 and also requires additional quirks in parser
*: explicitly use PARSER_NORMAL instead of 0

function                                             old     new   delta
login_main                                          1575    1596     +21
config_close                                          18      29     +11
bbunpack                                             383     391      +8
qgravechar                                           106     109      +3
rtnl_tab_initialize                                  121     117      -4
expand                                              1697    1693      -4
man_main                                             717     712      -5
nameif_main                                          674     668      -6
hexdump_main                                         597     591      -6
read_config                                          217     209      -8
dnsd_main                                           1478    1470      -8
sysctl_main                                          203     189     -14
config_open2                                          44      25     -19
make_device                                         1177    1141     -36
config_read                                          597     549     -48
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/11 up/down: 43/-158)         Total: -115 bytes
This commit is contained in:
Denis Vlasenko 2008-07-26 23:08:31 +00:00
parent 8895c2073e
commit 084266ed52
18 changed files with 160 additions and 142 deletions

View File

@ -998,15 +998,20 @@ int bb_parse_mode(const char* s, mode_t* theMode) FAST_FUNC;
* Config file parser * Config file parser
*/ */
enum { enum {
PARSE_VANILLA = 0x00000000, // trim line, collapse delimiters, warn and continue if less than mintokens PARSE_COLLAPSE = 0x00010000, // treat consecutive delimiters as one
PARSE_DONT_REDUCE = 0x00010000, // do not treat consecutive delimiters as one PARSE_TRIM = 0x00020000, // trim leading and trailing delimiters
PARSE_DONT_TRIM = 0x00020000, // do not trim line of leading and trailing delimiters // TODO: COLLAPSE and TRIM seem to always go in pair
PARSE_LAST_IS_GREEDY = 0x00040000, // last token takes whole remainder of the line PARSE_GREEDY = 0x00040000, // last token takes entire remainder of the line
// PARSE_DONT_NULL = 0x00080000, // do not set tokens[] to NULL PARSE_MIN_DIE = 0x00100000, // die if < min tokens found
PARSE_MIN_DIE = 0x00100000, // die if less tokens found
// keep a copy of current line // keep a copy of current line
PARSE_KEEP_COPY = 0x00200000 * ENABLE_DEBUG_CROND_OPTION, PARSE_KEEP_COPY = 0x00200000 * ENABLE_DEBUG_CROND_OPTION,
PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens // PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens
// NORMAL is:
// * remove leading and trailing delimiters and collapse
// multiple delimiters into one
// * warn and continue if less than mintokens delimiters found
// * grab everything into last token
PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY,
}; };
typedef struct parser_t { typedef struct parser_t {
FILE *fp; FILE *fp;

View File

@ -701,13 +701,13 @@ static void parse_inittab(void)
new_init_action(ASKFIRST, bb_default_login_shell, VC_4); new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
/* sysinit */ /* sysinit */
new_init_action(SYSINIT, INIT_SCRIPT, ""); new_init_action(SYSINIT, INIT_SCRIPT, "");
return; return;
} }
/* optional_tty:ignored_runlevel:action:command /* optional_tty:ignored_runlevel:action:command
* Delims are not to be collapsed and need exactly 4 tokens * Delims are not to be collapsed and need exactly 4 tokens
*/ */
while (config_read(parser, token, 4, 0, "#:", PARSE_DONT_TRIM|PARSE_DONT_REDUCE|PARSE_LAST_IS_GREEDY)) { while (config_read(parser, token, 4, 0, "#:",
PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
int action; int action;
char *tty = token[0]; char *tty = token[0];

View File

@ -14,8 +14,9 @@ int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int parse_main(int argc UNUSED_PARAM, char **argv) int parse_main(int argc UNUSED_PARAM, char **argv)
{ {
const char *delims = "# \t"; const char *delims = "# \t";
unsigned flags = 0; unsigned flags = PARSE_NORMAL;
int mintokens = 0, ntokens = 128; int mintokens = 0, ntokens = 128;
opt_complementary = "-1:n+:m+:f+"; opt_complementary = "-1:n+:m+:f+";
getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags);
//argc -= optind; //argc -= optind;
@ -61,13 +62,15 @@ Typical usage:
parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path))
{ {
parser_t *parser = xzalloc(sizeof(parser_t)); FILE* fp;
/* empty file configures nothing */ parser_t *parser;
parser->fp = fopen_func(filename);
if (parser->fp) fp = fopen_func(filename);
return parser; if (!fp)
free(parser); return NULL;
return NULL; parser = xzalloc(sizeof(*parser));
parser->fp = fp;
return parser;
} }
parser_t* FAST_FUNC config_open(const char *filename) parser_t* FAST_FUNC config_open(const char *filename)
@ -87,41 +90,53 @@ static void config_free_data(parser_t *const parser)
void FAST_FUNC config_close(parser_t *parser) void FAST_FUNC config_close(parser_t *parser)
{ {
config_free_data(parser); if (parser) {
fclose(parser->fp); config_free_data(parser);
fclose(parser->fp);
free(parser);
}
} }
/* /*
1. Read a line from config file. If nothing to read then bail out returning 0. 0. If parser is NULL return 0.
Handle continuation character. Advance lineno for each physical line. Cut comments. 1. Read a line from config file. If nothing to read then return 0.
2. if PARSE_DONT_TRIM is not set (default) skip leading and cut trailing delimiters, if any. Handle continuation character. Advance lineno for each physical line.
Discard everything past comment characher.
2. if PARSE_TRIM is set (default), remove leading and trailing delimiters.
3. If resulting line is empty goto 1. 3. If resulting line is empty goto 1.
4. Look for first delimiter. If PARSE_DONT_REDUCE or PARSE_DONT_TRIM is set then pin empty token. 4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then
5. Else (default) if number of seen tokens is equal to max number of tokens (token is the last one) remember the token as empty.
and PARSE_LAST_IS_GREEDY is set then pin the remainder of the line as the last token. 5. Else (default) if number of seen tokens is equal to max number of tokens
Else (token is not last or PARSE_LAST_IS_GREEDY is not set) just replace first delimiter with '\0' (token is the last one) and PARSE_GREEDY is set then the remainder
thus delimiting token and pin it. of the line is the last token.
6. Advance line pointer past the end of token. If number of seen tokens is less than required number Else (token is not last or PARSE_GREEDY is not set) just replace
of tokens then goto 4. first delimiter with '\0' thus delimiting the token.
7. Control the number of seen tokens is not less the min number of tokens. Die if condition is not met. 6. Advance line pointer past the end of token. If number of seen tokens
is less than required number of tokens then goto 4.
7. Check the number of seen tokens is not less the min number of tokens.
Complain or die otherwise depending on PARSE_MIN_DIE.
8. Return the number of seen tokens. 8. Return the number of seen tokens.
mintokens > 0 make config_read() exit with error message if less than mintokens mintokens > 0 make config_read() print error message if less than mintokens
(but more than 0) are found. Empty lines are always skipped (not warned about). (but more than 0) are found. Empty lines are always skipped (not warned about).
*/ */
#undef config_read #undef config_read
int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims)
{ {
char *line, *q; char *line, *q;
char comment = *delims++; char comment;
int ii; int ii;
int ntokens = flags & 0xFF; int ntokens;
int mintokens = (flags & 0xFF00) >> 8; int mintokens;
comment = *delims++;
ntokens = flags & 0xFF;
mintokens = (flags & 0xFF00) >> 8;
again: again:
// N.B. this could only be used in read-in-one-go version, or when tokens use xstrdup(). TODO memset(tokens, 0, sizeof(tokens[0]) * ntokens);
//if (!parser->lineno || !(flags & PARSE_DONT_NULL)) if (!parser)
memset(tokens, 0, sizeof(tokens[0]) * ntokens); return 0;
config_free_data(parser); config_free_data(parser);
while (1) { while (1) {
@ -142,20 +157,20 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
line[--ii] = '\0'; line[--ii] = '\0';
//TODO: add xmalloc_fgetline-like iface but with appending to existing str //TODO: add xmalloc_fgetline-like iface but with appending to existing str
q = xmalloc_fgetline(parser->fp); q = xmalloc_fgetline(parser->fp);
if (q) { if (!q)
parser->lineno++; break;
line = xasprintf("%s%s", line, q); parser->lineno++;
free(q); line = xasprintf("%s%s", line, q);
} free(q);
} }
// comments mean EOLs // discard comments
if (comment) { if (comment) {
q = strchrnul(line, comment); q = strchrnul(line, comment);
*q = '\0'; *q = '\0';
ii = q - line; ii = q - line;
} }
// skip leading and trailing delimiters // skip leading and trailing delimiters
if (!(flags & PARSE_DONT_TRIM)) { if (flags & PARSE_TRIM) {
// skip leading // skip leading
int n = strspn(line, delims); int n = strspn(line, delims);
if (n) { if (n) {
@ -177,7 +192,6 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
// skip empty line // skip empty line
free(line); free(line);
} }
// non-empty line found, parse and return the number of tokens // non-empty line found, parse and return the number of tokens
// store line // store line
@ -190,14 +204,15 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
ntokens--; // now it's max allowed token no ntokens--; // now it's max allowed token no
// N.B. non-empty remainder is also a token, // N.B. non-empty remainder is also a token,
// so if ntokens <= 1, we just return the whole line // so if ntokens <= 1, we just return the whole line
// N.B. if PARSE_LAST_IS_GREEDY is set the remainder of the line is stuck to the last token // N.B. if PARSE_GREEDY is set the remainder of the line is stuck to the last token
for (ii = 0; *line && ii <= ntokens; ) { ii = 0;
while (*line && ii <= ntokens) {
//bb_info_msg("L[%s]", line); //bb_info_msg("L[%s]", line);
// get next token // get next token
// at the last token and need greedy token -> // at last token and need greedy token ->
if ((flags & PARSE_LAST_IS_GREEDY) && (ii == ntokens)) { if ((flags & PARSE_GREEDY) && (ii == ntokens)) {
// skip possible delimiters // skip possible delimiters
if (!(flags & PARSE_DONT_REDUCE)) if (flags & PARSE_COLLAPSE)
line += strspn(line, delims); line += strspn(line, delims);
// don't cut the line // don't cut the line
q = line + strlen(line); q = line + strlen(line);
@ -208,10 +223,11 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
*q++ = '\0'; *q++ = '\0';
} }
// pin token // pin token
if ((flags & (PARSE_DONT_REDUCE|PARSE_DONT_TRIM)) || *line) { if (!(flags & (PARSE_COLLAPSE | PARSE_TRIM)) || *line) {
//bb_info_msg("N[%d] T[%s]", ii, line); //bb_info_msg("N[%d] T[%s]", ii, line);
tokens[ii++] = line; tokens[ii++] = line;
// process escapes in token // process escapes in token
#if 0 // unused so far
if (flags & PARSE_ESCAPE) { if (flags & PARSE_ESCAPE) {
char *s = line; char *s = line;
while (*s) { while (*s) {
@ -224,6 +240,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
} }
*line = '\0'; *line = '\0';
} }
#endif
} }
line = q; line = q;
//bb_info_msg("A[%s]", line); //bb_info_msg("A[%s]", line);
@ -234,6 +251,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
parser->lineno, ii, mintokens); parser->lineno, ii, mintokens);
if (flags & PARSE_MIN_DIE) if (flags & PARSE_MIN_DIE)
xfunc_die(); xfunc_die();
ntokens++;
goto again; goto again;
} }

View File

@ -139,20 +139,17 @@ static ALWAYS_INLINE void die_if_nologin(void) {}
#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
static int check_securetty(void) static int check_securetty(void)
{ {
char *buf; char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */
int ret = 1;
parser_t *parser = config_open2("/etc/securetty", fopen_for_read); parser_t *parser = config_open2("/etc/securetty", fopen_for_read);
/* N.B. A missing securetty file is not an error. */ while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) {
if (parser) { if (strcmp(buf, short_tty) == 0)
while (config_read(parser, &buf, 1, 1, "# \t", 0)) { break;
if (strcmp(buf, short_tty) == 0) buf = NULL;
break;
}
config_close(parser);
// buf != NULL here iff config file was empty (OK) or buf equals short_tty (OK)
ret = buf != NULL;
} }
return ret; config_close(parser);
/* buf != NULL here if config file was not found, empty
* or line was found which equals short_tty */
return buf != NULL;
} }
#else #else
static ALWAYS_INLINE int check_securetty(void) { return 1; } static ALWAYS_INLINE int check_securetty(void) { return 1; }

View File

@ -469,11 +469,15 @@ static void SynchronizeFile(const char *fileName)
file->cf_User = xstrdup(fileName); file->cf_User = xstrdup(fileName);
pline = &file->cf_LineBase; pline = &file->cf_LineBase;
while (--maxLines while (1) {
&& (n = config_read(parser, tokens, 6, 1, "# \t", PARSE_LAST_IS_GREEDY|PARSE_KEEP_COPY))
) {
CronLine *line; CronLine *line;
if (!--maxLines)
break;
n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY);
if (!n)
break;
if (DebugOpt) if (DebugOpt)
crondlog(LVL5 "user:%s entry:%s", fileName, parser->data); crondlog(LVL5 "user:%s entry:%s", fileName, parser->data);
@ -488,7 +492,7 @@ static void SynchronizeFile(const char *fileName)
/* check if a minimum of tokens is specified */ /* check if a minimum of tokens is specified */
if (n < 6) if (n < 6)
continue; continue;
*pline = line = xzalloc(sizeof(CronLine)); *pline = line = xzalloc(sizeof(*line));
/* parse date ranges */ /* parse date ranges */
ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]); ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]);
ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]); ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]);

View File

@ -288,10 +288,10 @@ static void init(const char *cfg_filename)
"DEBUG\0" "DEBUG\0"
#endif #endif
; ;
char *token[2]; char *token[2];
parser_t *parser = config_open2(cfg_filename, xfopen_stdin); parser_t *parser = config_open2(cfg_filename, xfopen_stdin);
while (config_read(parser, token, 2, 2, "#=", PARSE_MIN_DIE)) { while (config_read(parser, token, 2, 2, "#=",
(PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
unsigned val = xatoi_u(token[1]); unsigned val = xatoi_u(token[1]);
int i = index_in_strings(param_names, token[0]); int i = index_in_strings(param_names, token[0]);
if (i < 0) if (i < 0)

View File

@ -82,6 +82,7 @@ int man_main(int argc UNUSED_PARAM, char **argv)
char *cur_path, *cur_sect; char *cur_path, *cur_sect;
int count_mp, cur_mp; int count_mp, cur_mp;
int opt, not_found; int opt, not_found;
char *token[2];
opt_complementary = "-1"; /* at least one argument */ opt_complementary = "-1"; /* at least one argument */
opt = getopt32(argv, "+aw"); opt = getopt32(argv, "+aw");

View File

@ -491,7 +491,7 @@ static int already_loaded(const char *name)
int ret = 0; int ret = 0;
char *s; char *s;
parser_t *parser = config_open2("/proc/modules", xfopen_for_read); parser_t *parser = config_open2("/proc/modules", xfopen_for_read);
while (config_read(parser, &s, 1, 1, "# \t", 0)) { while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
if (strcmp(s, name) == 0) { if (strcmp(s, name) == 0) {
ret = 1; ret = 1;
break; break;

View File

@ -106,43 +106,41 @@ static void undot(uint8_t * rip)
*/ */
static void dnsentryinit(void) static void dnsentryinit(void)
{ {
char *token[2];
parser_t *parser; parser_t *parser;
struct dns_entry *m, *prev; struct dns_entry *m, *prev;
prev = dnsentry = NULL; prev = dnsentry = NULL;
parser = config_open(fileconf); parser = config_open(fileconf);
if (parser) { while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
char *token[2]; unsigned a, b, c, d;
while (config_read(parser, token, 2, 2, "# \t", 0)) { /*
unsigned int a,b,c,d; * Assumes all host names are lower case only
/* * Hostnames with more than one label are not handled correctly.
* Assumes all host names are lower case only * Presently the dot is copied into name without
* Hostnames with more than one label are not handled correctly. * converting to a length/string substring for that label.
* Presently the dot is copied into name without */
* converting to a length/string substring for that label. // if (!token[1] || sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4)
*/ if (sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4)
// if (!token[1] || sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) continue;
if (sscanf(token[1], ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4)
continue;
m = xzalloc(sizeof(*m)); m = xzalloc(sizeof(*m));
/*m->next = NULL;*/ /*m->next = NULL;*/
sprintf(m->ip, ".%u.%u.%u.%u"+1, a, b, c, d); sprintf(m->ip, ".%u.%u.%u.%u"+1, a, b, c, d);
sprintf(m->rip, ".%u.%u.%u.%u", d, c, b, a); sprintf(m->rip, ".%u.%u.%u.%u", d, c, b, a);
undot((uint8_t*)m->rip); undot((uint8_t*)m->rip);
convname(m->name, (uint8_t*)token[0]); convname(m->name, (uint8_t*)token[0]);
if (OPT_verbose) if (OPT_verbose)
fprintf(stderr, "\tname:%s, ip:%s\n", &(m->name[1]), m->ip); fprintf(stderr, "\tname:%s, ip:%s\n", &(m->name[1]), m->ip);
if (prev == NULL) if (prev == NULL)
dnsentry = m; dnsentry = m;
else else
prev->next = m; prev->next = m;
prev = m; prev = m;
}
config_close(parser);
} }
config_close(parser);
} }
/* /*

View File

@ -20,7 +20,7 @@ static void do_sethostname(char *s, int isfile)
return; return;
if (isfile) { if (isfile) {
parser_t *parser = config_open2(s, xfopen_for_read); parser_t *parser = config_open2(s, xfopen_for_read);
while (config_read(parser, &s, 1, 1, "# \t", 0)) { while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
do_sethostname(s, 0); do_sethostname(s, 0);
} }
if (ENABLE_FEATURE_CLEAN_UP) if (ENABLE_FEATURE_CLEAN_UP)

View File

@ -20,9 +20,7 @@ static void rtnl_tab_initialize(const char *file, const char **tab, int size)
{ {
char *token[2]; char *token[2];
parser_t *parser = config_open2(file, fopen_for_read); parser_t *parser = config_open2(file, fopen_for_read);
if (!parser) while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
return;
while (config_read(parser, token, 2, 2, "# \t", 0)) {
int id = bb_strtou(token[0], NULL, 0); int id = bb_strtou(token[0], NULL, 0);
if (id < 0 || id > size) { if (id < 0 || id > size) {
bb_error_msg("database %s is corrupted at line %d", bb_error_msg("database %s is corrupted at line %d",

View File

@ -160,13 +160,11 @@ int nameif_main(int argc, char **argv)
prepend_new_eth_table(&clist, ifname, *argv++); prepend_new_eth_table(&clist, ifname, *argv++);
} }
} else { } else {
char *tokens[2];
struct parser_t *parser = config_open(fname); struct parser_t *parser = config_open(fname);
if (parser) { while (config_read(parser, tokens, 2, 2, "# \t", PARSE_NORMAL))
char *tokens[2]; prepend_new_eth_table(&clist, tokens[0], tokens[1]);
while (config_read(parser, tokens, 2, 2, "# \t", 0)) config_close(parser);
prepend_new_eth_table(&clist, tokens[0], tokens[1]);
config_close(parser);
}
} }
ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0); ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);

View File

@ -318,10 +318,7 @@ void read_config(const char *file)
keywords[i].handler(keywords[i].def, keywords[i].var); keywords[i].handler(keywords[i].def, keywords[i].var);
parser = config_open(file); parser = config_open(file);
if (!parser) while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
return;
while (config_read(parser, token, 2, 2, "# \t", PARSE_LAST_IS_GREEDY)) {
for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) { for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
if (!strcasecmp(token[0], k->keyword)) { if (!strcasecmp(token[0], k->keyword)) {
if (!k->handler(token[1], k->var)) { if (!k->handler(token[1], k->var)) {

View File

@ -95,10 +95,7 @@ static int sysctl_preload_file_and_exit(const char *filename)
parser_t *parser; parser_t *parser;
parser = config_open(filename); parser = config_open(filename);
if (!parser) while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { // TODO: ';' is comment char too
return 1;
while (config_read(parser, token, 2, 2, "# \t=", PARSE_LAST_IS_GREEDY)) { // TODO: ';' is comment char too
// if (!token[1]) { // if (!token[1]) {
// bb_error_msg(WARN_BAD_LINE, filename, parser->lineno); // bb_error_msg(WARN_BAD_LINE, filename, parser->lineno);
// } else { // } else {

View File

@ -54,10 +54,7 @@ static void read_config(char **pc, int npc, char **fc, int nfc)
pc[0] = fc[0] = NULL; pc[0] = fc[0] = NULL;
parser = config_open("/etc/sestatus.conf"); parser = config_open("/etc/sestatus.conf");
if (!parser) while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) {
return;
while (config_read(parser, &buf, 1, 1, "# \t", PARSE_LAST_IS_GREEDY)) {
if (strcmp(buf, "[process]") == 0) { if (strcmp(buf, "[process]") == 0) {
section = 1; section = 1;
} else if (strcmp(buf, "[files]") == 0) { } else if (strcmp(buf, "[files]") == 0) {

View File

@ -5,20 +5,24 @@
. testing.sh . testing.sh
NO_REDUCE=65536 COLLAPSE=$(( 0x00010000))
NO_TRIM=131072 TRIM=$(( 0x00020000))
GREEDY=262144 GREEDY=$(( 0x00040000))
MIN_DIE=$(( 0x00100000))
KEEP_COPY=$((0x00200000))
ESCAPE=$(( 0x00400000))
NORMAL=$(( COLLAPSE | TRIM | GREEDY))
# testing "description" "command" "result" "infile" "stdin" # testing "description" "command" "result" "infile" "stdin"
testing "mdev.conf" \ testing "parse mdev.conf" \
"parse -n 4 -m 3 -f $GREEDY -" \ "parse -n 4 -m 3 -f $((NORMAL)) -" \
"[sda][0:0][644][@echo @echo TEST]\n" \ "[sda][0:0][644][@echo @echo TEST]\n" \
"-" \ "-" \
" sda 0:0 644 @echo @echo TEST # echo trap\n" " sda 0:0 644 @echo @echo TEST # echo trap\n"
testing "notrim" \ testing "parse notrim" \
"parse -n 4 -m 3 -f $(($GREEDY+$NO_TRIM)) -" \ "parse -n 4 -m 3 -f $((NORMAL - TRIM - COLLAPSE)) -" \
"[][sda][0:0][644 @echo @echo TEST ]\n" \ "[][sda][0:0][644 @echo @echo TEST ]\n" \
"-" \ "-" \
" sda 0:0 644 @echo @echo TEST \n" " sda 0:0 644 @echo @echo TEST \n"
@ -49,12 +53,12 @@ cat >$FILE.res <<EOF
[/dev/cdrom][/cdrom][iso9660][ro,user,noauto,nohide][0][0] [/dev/cdrom][/cdrom][iso9660][ro,user,noauto,nohide][0][0]
[/dev/hdb5][/redhat][ext2][rw,root,noauto,nohide][0][0] [/dev/hdb5][/redhat][ext2][rw,root,noauto,nohide][0][0]
[/dev/hdb6][/win2home][ntfs][rw,root,noauto,nohide][0][0] [/dev/hdb6][/win2home][ntfs][rw,root,noauto,nohide][0][0]
[/dev/hdb7][/win2skul][ntfs][rw,root,noauto,nohide][none][0] [/dev/hdb7][/win2skul][ntfs][rw,root,noauto,nohide][none][0 0]
[none][/dev/pts][devpts][gid=5,mode=620][0][0] [none][/dev/pts][devpts][gid=5,mode=620][0][0]
[none][/proc][proc][defaults][0][0] [none][/proc][proc][defaults][0][0]
EOF EOF
testing "polluted fstab" \ testing "parse polluted fstab" \
"parse -n 6 -m 6 $FILE" \ "parse -n 6 -m 6 $FILE" \
"`cat $FILE.res`\n" \ "`cat $FILE.res`\n" \
"" \ "" \
@ -74,8 +78,8 @@ cat >$FILE.res <<EOF
[][][shutdown][/sbin/swapoff -a] [][][shutdown][/sbin/swapoff -a]
EOF EOF
testing "inittab from examples" \ testing "parse inittab from examples" \
"parse -n 4 -m 4 -f $(($GREEDY+$NO_TRIM)) -d'#:' $FILE" \ "parse -n 4 -m 4 -f $((NORMAL - TRIM - COLLAPSE)) -d'#:' $FILE" \
"`cat $FILE.res`\n" \ "`cat $FILE.res`\n" \
"" \ "" \
"" ""
@ -94,7 +98,7 @@ cat >$FILE.res <<EOF
[option][lease][864000] [option][lease][864000]
EOF EOF
testing "udhcpd.conf from examples" \ testing "parse udhcpd.conf from examples" \
"parse -n 127 $FILE" \ "parse -n 127 $FILE" \
"`cat $FILE.res`\n" \ "`cat $FILE.res`\n" \
"" \ "" \

View File

@ -16,11 +16,19 @@
static void bb_dump_addfile(dumper_t *dumper, char *name) static void bb_dump_addfile(dumper_t *dumper, char *name)
{ {
parser_t *parser = config_open2(name, xfopen_for_read); char *p;
while (config_read(parser, &name, 1, 1, "# \t", 0)) { FILE *fp;
bb_dump_add(dumper, name); char *buf;
fp = xfopen_for_read(name);
while ((buf = xmalloc_fgetline(fp)) != NULL) {
p = skip_whitespace(buf);
if (*p && (*p != '#')) {
bb_dump_add(dumper, p);
}
free(buf);
} }
config_close(parser); fclose(fp);
} }
static const char *const add_strings[] = { static const char *const add_strings[] = {

View File

@ -107,10 +107,7 @@ static void make_device(char *path, int delete)
parser = config_open2("/etc/mdev.conf", fopen_for_read); parser = config_open2("/etc/mdev.conf", fopen_for_read);
/* If we have config file, look up user settings */ /* If we have config file, look up user settings */
if (!parser) while (config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) {
goto end_parse;
while (config_read(parser, tokens, 4, 3, "# \t", PARSE_LAST_IS_GREEDY)) {
regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP]; regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP];
char *val; char *val;
@ -244,7 +241,6 @@ static void make_device(char *path, int delete)
} /* end of "while line is read from /etc/mdev.conf" */ } /* end of "while line is read from /etc/mdev.conf" */
config_close(parser); config_close(parser);
end_parse:
#endif /* ENABLE_FEATURE_MDEV_CONF */ #endif /* ENABLE_FEATURE_MDEV_CONF */
if (!delete && sscanf(dev_maj_min, "%u:%u", &major, &minor) == 2) { if (!delete && sscanf(dev_maj_min, "%u:%u", &major, &minor) == 2) {