diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makemodule.am | 3 | ||||
| -rw-r--r-- | lib/cron/rdcron.c | 6 | ||||
| -rw-r--r-- | lib/include/libcfg.h | 29 | ||||
| -rw-r--r-- | lib/libcfg/rdcfg.c | 32 | ||||
| -rw-r--r-- | lib/libcfg/rdline.c | 227 | ||||
| -rw-r--r-- | lib/libcfg/splitkv.c | 48 | ||||
| -rw-r--r-- | lib/util/rdsvc.c | 13 | 
7 files changed, 158 insertions, 200 deletions
| diff --git a/lib/Makemodule.am b/lib/Makemodule.am index fb6ca92..51bce72 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -8,8 +8,7 @@ libinit_a_SOURCES += lib/util/print_version.c lib/util/argv_exec.c $(HEADRS)  libinit_a_CPPFLAGS = $(AM_CPPFLAGS)  libinit_a_CFLAGS = $(AM_CFLAGS) -libcfg_a_SOURCES = lib/libcfg/rdline.c lib/libcfg/unescape.c -libcfg_a_SOURCES += lib/libcfg/splitkv.c lib/libcfg/rdcfg.c +libcfg_a_SOURCES = lib/libcfg/rdline.c lib/libcfg/unescape.c lib/libcfg/rdcfg.c  libcfg_a_SOURCES += lib/libcfg/pack_argv.c lib/include/libcfg.h  libcfg_a_CPPFLAGS = $(AM_CPPFLAGS)  libcfg_a_CFLAGS = $(AM_CFLAGS) diff --git a/lib/cron/rdcron.c b/lib/cron/rdcron.c index 1c11cbb..520f969 100644 --- a/lib/cron/rdcron.c +++ b/lib/cron/rdcron.c @@ -486,7 +486,8 @@ crontab_t *rdcron(int dirfd, const char *filename)  	cron = calloc(1, sizeof(*cron));  	if (cron == NULL) {  		fputs("out of memory\n", stderr); -		goto out; +		close(fd); +		return NULL;  	}  	cron->minute = 0xFFFFFFFFFFFFFFFFUL; @@ -501,7 +502,6 @@ crontab_t *rdcron(int dirfd, const char *filename)  		delcron(cron);  		cron = NULL;  	} -out: -	close(fd); +	rdline_cleanup(&rd);  	return cron;  } diff --git a/lib/include/libcfg.h b/lib/include/libcfg.h index 8096f1b..95f91a8 100644 --- a/lib/include/libcfg.h +++ b/lib/include/libcfg.h @@ -20,23 +20,16 @@  #include <stdbool.h>  #include <stddef.h> +#include <stdio.h>  typedef struct { -	int fd;			/* input file descriptor */ -	const char *argstr;	/* if not NULL, read from this instead */ -  	const char *filename;	/* input file name */  	size_t lineno;		/* current line number */ - -	size_t i;		/* buffer offset */ -	char buffer[256];	/* current line, null-terminated */ +	FILE *fp; +	char *line;  	int argc;  	const char *const *argv; - -	bool string;		/* inside a string? */ -	bool escape;		/* reading an escape sequence? */ -	bool comment;		/* inside a comment */  } rdline_t;  typedef struct { @@ -63,6 +56,8 @@ typedef struct {  void rdline_init(rdline_t *t, int fd, const char *filename,  		 int argc, const char *const *argv); +void rdline_cleanup(rdline_t *t); +  /*  	Read from file until end-of-file or a line feed is encountered. @@ -84,9 +79,8 @@ void rdline_init(rdline_t *t, int fd, const char *filename,  	   outside the bounds set by argc, processing fails. On success,  	   the argv value is inserted and processed as described above.  	 - A '%' character can be escaped by writing '%%' or, if inside -	   a double quite string, by writing \%. -	 - An attempt to use such an indexed argument inside an argument -	   expansion, results in failure. +	   a double quoted string, by writing \%. +	 - Arguments are pasted as is. Substitution is not recursive.  	 - If the resulting line is empty, processing is restarted.  */  int rdline(rdline_t *t); @@ -111,15 +105,6 @@ int unescape(char *src);  int pack_argv(char *str);  /* -	Split the current input line into a space seperted keyword -	(alphabetical characters only) and a value (the rest of the line). - -	If errors are encounted, prints a diagnostic message to stderr and -	returns -1. On success, zero is returned. - */ -int splitkv(rdline_t *rd, char **k, char **v); - -/*  	Parse a configuration file containing '<keyword> [arguments...]' lines.  	The cfgobj and flags are passed to the callback in the params array. diff --git a/lib/libcfg/rdcfg.c b/lib/libcfg/rdcfg.c index 71a994f..ccbcf7b 100644 --- a/lib/libcfg/rdcfg.c +++ b/lib/libcfg/rdcfg.c @@ -19,6 +19,7 @@  #include <string.h>  #include <stdio.h> +#include <ctype.h>  static const cfg_param_t *find_param(rdline_t *rd, const char *name,  				     const cfg_param_t *params, size_t count) @@ -35,6 +36,33 @@ static const cfg_param_t *find_param(rdline_t *rd, const char *name,  	return NULL;  } +static int splitkv(rdline_t *rd, char **k, char **v) +{ +	char *key = rd->line, *value = rd->line; + +	while (*value != ' ' && *value != '\0') { +		if (!isalpha(*value)) { +			fprintf(stderr, +				"%s: %zu: unexpected '%c' in keyword\n", +				rd->filename, rd->lineno, *value); +			return -1; +		} +		++value; +	} + +	if (*value != ' ') { +		fprintf(stderr, "%s: %zu: expected argument after '%s'\n", +			rd->filename, rd->lineno, key); +		return -1; +	} + +	*(value++) = '\0'; + +	*k = key; +	*v = value; +	return 0; +} +  int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count,  	  int flags)  { @@ -61,9 +89,9 @@ int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count,  			}  			while ((ret = rdline(rd)) == 0) { -				if (strcmp(rd->buffer, "}") == 0) +				if (strcmp(rd->line, "}") == 0)  					break; -				if (p->handle(cfgobj, rd->buffer, rd, flags)) +				if (p->handle(cfgobj, rd->line, rd, flags))  					return -1;  			} diff --git a/lib/libcfg/rdline.c b/lib/libcfg/rdline.c index ffbfd89..16ca5cf 100644 --- a/lib/libcfg/rdline.c +++ b/lib/libcfg/rdline.c @@ -24,151 +24,144 @@  #include "libcfg.h" -static int rdline_getc(rdline_t *t) +void rdline_init(rdline_t *t, int fd, const char *filename, +		 int argc, const char *const *argv)  { -	int ret; -	char c; +	memset(t, 0, sizeof(*t)); +	t->fp = fdopen(fd, "r"); +	t->filename = filename; +	t->argc = argc; +	t->argv = argv; +} -	if (t->argstr != NULL) { -		c = *(t->argstr++); -		if (c != '\0') -			goto out; +void rdline_cleanup(rdline_t *t) +{ +	free(t->line); +	fclose(t->fp); +} -		t->argstr = NULL; -	} +static int read_raw_line(rdline_t *t) +{ +	size_t len = 0; -	do { -		ret = read(t->fd, &c, 1); -	} while (ret < 0 && errno == EINTR); +	free(t->line); +	t->line = NULL; -	if (ret < 0) -		return -1; +	errno = 0; -	if (ret == 0) { -		if (t->i == 0) { -			errno = 0; +	if (getline(&t->line, &len, t->fp) < 0) { +		if (errno) { +			fprintf(stderr, "%s: %zu: %s\n", t->filename, +				t->lineno, strerror(errno));  			return -1;  		} -		c = '\0'; +		return 1;  	} -out: -	return (c == '\n') ? '\0' : c; + +	t->lineno += 1; +	return 0;  } -static int rdline_append(rdline_t *t, int c) +static int normalize_line(rdline_t *t)  { -	if (t->comment) { -		if (c != '\0') -			return 0; -	} else if (t->string) { -		if (t->escape) { -			t->escape = false; -		} else { -			if (c == '\\') -				t->escape = true; -			if (c == '"') -				t->string = false; -		} -	} else { -		if (isspace(c)) +	char *dst = t->line, *src = t->line; +	bool string = false; +	const char *errstr; +	int c, ret = 0; + +	while (isspace(*src)) +		++src; + +	while (*src != '\0' && (string || *src != '#')) { +		c = *(src++); + +		if (c == '"') { +			string = !string; +		} else if (!string && isspace(c)) {  			c = ' '; -		if (c == ' ' && (t->i == 0 || t->buffer[t->i - 1] == ' ')) -			return 0; -		if (c == '#') { -			t->comment = true; -			return 0; +			if (dst > t->line && dst[-1] == ' ') +				continue; +		} else if (c == '%') { +			*(dst++) = c; +			c = *(src++); +			if (c != '%' && !isdigit(c)) { +				errstr = "expected digit after '%%'"; +				goto fail; +			} +			if (isdigit(c) && (c - '0') >= t->argc) { +				errstr = "argument out of range"; +				goto fail; +			} +			ret += strlen(t->argv[c - '0']); +		} else if (string && c == '\\' && *src != '\0') { +			*(dst++) = c; +			c = *(src++);  		} -		if (c == '"') -			t->string = true; -	} -	if (c == '\0') { -		while (t->i > 0 && t->buffer[t->i - 1] == ' ') -			t->i -= 1; +		*(dst++) = c;  	} -	if (t->i == sizeof(t->buffer)) -		return -1; +	if (string) { +		errstr = "missing \""; +		goto fail; +	} -	t->buffer[t->i++] = c; -	return 0; +	while (dst > t->line && dst[-1] == ' ') +		--dst; +	*dst = '\0'; +	return ret; +fail: +	fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr); +	return -1;  } -void rdline_init(rdline_t *t, int fd, const char *filename, -		 int argc, const char *const *argv) +static void substitute(rdline_t *t, char *dst, char *src)  { -	memset(t, 0, sizeof(*t)); -	t->fd = fd; -	t->filename = filename; -	t->argc = argc; -	t->argv = argv; +	bool string = false; + +	while (*src != '\0') { +		if (src[0] == '%' && isdigit(src[1])) { +			strcpy(dst, t->argv[src[1] - '0']); +			src += 2; +			while (*dst != '\0') +				++dst; +		} else { +			if (*src == '"') +				string = !string; +			if (string && *src == '\\') +				*(dst++) = *(src++); +			*(dst++) = *(src++); +		} +	}  }  int rdline(rdline_t *t)  { -	const char *errstr; -	int c; -retry: -	t->i = 0; -	t->argstr = NULL; -	t->string = t->escape = t->comment = false; -	t->lineno += 1; +	char *buffer = NULL; +	int ret;  	do { -		errno = 0; -		c = rdline_getc(t); -		if (c < 0) { -			if (errno == 0) -				return 1; -			errstr = strerror(errno); -			goto fail; -		} -		if (c == 0 && t->string) { -			errstr = "missing \""; -			goto fail; -		} - -		if (c == '%') { -			c = rdline_getc(t); -			if (c == 0) { -				errstr = "unexpected end of line after '%%'"; -				goto fail; -			} -			if (c < 0) { -				errstr = strerror(errno); -				goto fail; -			} - -			if (c != '%') { -				if (!isdigit(c)) { -					errstr = "exptected digit after '%%'"; -					goto fail; -				} -				if ((c - '0') >= t->argc) { -					errstr = "argument out of range"; -					goto fail; -				} -				if (t->argstr != NULL) { -					errstr = "recursive argument " -						 "expansion"; -					goto fail; -				} -				t->argstr = t->argv[c - '0']; -				continue; -			} -		} +		if ((ret = read_raw_line(t))) +			goto out; +		if ((ret = normalize_line(t)) < 0) +			goto out; +	} while (t->line[0] == '\0'); -		if (rdline_append(t, c)) { -			errstr = "line too long"; -			goto fail; -		} -	} while (c != '\0'); +	if (ret == 0) +		return 0; -	if (t->buffer[0] == '\0') -		goto retry; +	buffer = calloc(1, strlen(t->line) + ret + 1); +	if (buffer == NULL) { +		fprintf(stderr, "%s: %zu: out of memory\n", +			t->filename, t->lineno); +		ret = -1; +		goto out; +	} -	return 0; -fail: -	fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr); -	return -1; +	substitute(t, buffer, t->line); +	ret = 0; +out: +	free(t->line); +	t->line = buffer; +	return ret;  } diff --git a/lib/libcfg/splitkv.c b/lib/libcfg/splitkv.c deleted file mode 100644 index 49f8ebe..0000000 --- a/lib/libcfg/splitkv.c +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <https://www.gnu.org/licenses/>. - */ -#include <ctype.h> -#include <stdio.h> - -#include "libcfg.h" - -int splitkv(rdline_t *rd, char **k, char **v) -{ -	char *key = rd->buffer, *value = rd->buffer; - -	while (*value != ' ' && *value != '\0') { -		if (!isalpha(*value)) { -			fprintf(stderr, -				"%s: %zu: unexpected '%c' in keyword\n", -				rd->filename, rd->lineno, *value); -			return -1; -		} -		++value; -	} - -	if (*value != ' ') { -		fprintf(stderr, "%s: %zu: expected argument after '%s'\n", -			rd->filename, rd->lineno, key); -		return -1; -	} - -	*(value++) = '\0'; - -	*k = key; -	*v = value; -	return 0; -} diff --git a/lib/util/rdsvc.c b/lib/util/rdsvc.c index 747d753..ca60731 100644 --- a/lib/util/rdsvc.c +++ b/lib/util/rdsvc.c @@ -266,8 +266,6 @@ service_t *rdsvc(int dirfd, const char *filename, int flags)  		argc = 0;  	} -	rdline_init(&rd, fd, filename, argc, args); -  	nlen = (arg != NULL) ? (size_t)(arg - filename) : strlen(filename);  	svc = calloc(1, sizeof(*svc) + nlen + 1); @@ -282,14 +280,17 @@ service_t *rdsvc(int dirfd, const char *filename, int flags)  	memcpy(svc->name, filename, nlen); -	if (rdcfg(svc, &rd, svc_params, ARRAY_SIZE(svc_params), flags)) -		goto fail; +	rdline_init(&rd, fd, filename, argc, args); + +	if (rdcfg(svc, &rd, svc_params, ARRAY_SIZE(svc_params), flags)) { +		delsvc(svc); +		svc = NULL; +	} -	close(fd); +	rdline_cleanup(&rd);  	return svc;  fail_oom:  	fputs("out of memory\n", stderr); -fail:  	delsvc(svc);  	close(fd);  	return NULL; | 
