mirror of
https://github.com/pygos/init.git
synced 2024-11-25 12:30:42 +01:00
Make line buffer static, move error reporting to rdline
- Expose rdline_t struct and move a lot of extra processing to rdline code - Make line buffer statically allocated - Simplify rdsvc code Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
parent
a42022c650
commit
77725291ef
4 changed files with 178 additions and 170 deletions
|
@ -36,13 +36,40 @@ typedef struct {
|
||||||
} enum_map_t;
|
} enum_map_t;
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
const char *const *argv;
|
||||||
|
|
||||||
|
bool string; /* inside a string? */
|
||||||
|
bool escape; /* reading an escape sequence? */
|
||||||
|
bool comment; /* inside a comment */
|
||||||
|
} rdline_t;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read from fd until end-of-file or a line feed is encountered.
|
Initialize the config line scanner.
|
||||||
|
|
||||||
Returns NULL with errno set on failure. Returns NULL with errno
|
The scanner reads from the provided fd. The filename is used for
|
||||||
cleared if end-of-file is reached.
|
error reporting. An argument count and vector can be set for argument
|
||||||
|
substitution in rdline.
|
||||||
|
*/
|
||||||
|
void rdline_init(rdline_t *t, int fd, const char *filename,
|
||||||
|
int argc, const char *const *argv);
|
||||||
|
|
||||||
The line must be deallocated with free().
|
/*
|
||||||
|
Read from file until end-of-file or a line feed is encountered.
|
||||||
|
|
||||||
|
Returns -1 on failure, +1 if end of file was reached,
|
||||||
|
0 if data was read successfully.
|
||||||
|
|
||||||
The following transformations are applied:
|
The following transformations are applied:
|
||||||
- Space characters are replaced with regular white space characters.
|
- Space characters are replaced with regular white space characters.
|
||||||
|
@ -53,19 +80,18 @@ typedef struct {
|
||||||
- If a '"' is encounterd, the above rules are disabled, until a
|
- If a '"' is encounterd, the above rules are disabled, until a
|
||||||
after the matching '"' is read. A '"' can be escaped by preceeding
|
after the matching '"' is read. A '"' can be escaped by preceeding
|
||||||
it with a backslash.
|
it with a backslash.
|
||||||
- If a second, coresponding '"' is not found, processing fails with
|
- If a second, coresponding '"' is not found, processing fails.
|
||||||
errno set to EILSEQ.
|
|
||||||
- If a '%' character is encountered, the next character is expected
|
- If a '%' character is encountered, the next character is expected
|
||||||
to be a single digit index into argv. If it is not a digit or
|
to be a single digit index into argv. If it is not a digit or
|
||||||
outside the bounds set by argc, processing fails and sets errno
|
outside the bounds set by argc, processing fails. On success,
|
||||||
to EINVAL. On success, the argv value is inserted and processed
|
the argv value is inserted and processed as described above.
|
||||||
as described above.
|
|
||||||
- A '%' character can be escaped by writing '%%' or, if inside
|
- A '%' character can be escaped by writing '%%' or, if inside
|
||||||
a double quite string, by writing \%.
|
a double quite string, by writing \%.
|
||||||
- An attempt to use such an indexed argument inside an argument
|
- An attempt to use such an indexed argument inside an argument
|
||||||
expansion, results in failure with errno set to ELOOP.
|
expansion, results in failure.
|
||||||
|
- If the resulting line is empty, processing is restarted.
|
||||||
*/
|
*/
|
||||||
char *rdline(int fd, int argc, const char *const *argv);
|
int rdline(rdline_t *t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Remove double quotes ('"') from a string and substitute escape
|
Remove double quotes ('"') from a string and substitute escape
|
||||||
|
|
106
lib/src/rdline.c
106
lib/src/rdline.c
|
@ -20,22 +20,10 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int fd; /* input file descriptor */
|
|
||||||
const char *argstr; /* if not NULL, read from this instead */
|
|
||||||
|
|
||||||
size_t i; /* buffer offset */
|
|
||||||
size_t bufsiz; /* buffer size */
|
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
bool string; /* inside a string? */
|
|
||||||
bool escape; /* reading an escape sequence? */
|
|
||||||
bool comment; /* inside a comment */
|
|
||||||
} rdline_t;
|
|
||||||
|
|
||||||
static int rdline_getc(rdline_t *t)
|
static int rdline_getc(rdline_t *t)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -69,9 +57,6 @@ out:
|
||||||
|
|
||||||
static int rdline_append(rdline_t *t, int c)
|
static int rdline_append(rdline_t *t, int c)
|
||||||
{
|
{
|
||||||
size_t newsz;
|
|
||||||
char *new;
|
|
||||||
|
|
||||||
if (t->comment) {
|
if (t->comment) {
|
||||||
if (c != '\0')
|
if (c != '\0')
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -102,67 +87,88 @@ static int rdline_append(rdline_t *t, int c)
|
||||||
t->i -= 1;
|
t->i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->i == t->bufsiz) {
|
if (t->i == sizeof(t->buffer))
|
||||||
newsz = t->bufsiz ? t->bufsiz * 2 : 16;
|
return -1;
|
||||||
new = realloc(t->buffer, newsz);
|
|
||||||
|
|
||||||
if (new == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
t->buffer = new;
|
|
||||||
t->bufsiz = newsz;
|
|
||||||
}
|
|
||||||
|
|
||||||
t->buffer[t->i++] = c;
|
t->buffer[t->i++] = c;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *rdline(int fd, int argc, const char *const *argv)
|
void rdline_init(rdline_t *t, int fd, const char *filename,
|
||||||
|
int argc, const char *const *argv)
|
||||||
{
|
{
|
||||||
rdline_t rd;
|
memset(t, 0, sizeof(*t));
|
||||||
int c, ret;
|
t->fd = fd;
|
||||||
|
t->filename = filename;
|
||||||
|
t->argc = argc;
|
||||||
|
t->argv = argv;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
int rdline(rdline_t *t)
|
||||||
rd.fd = fd;
|
{
|
||||||
|
const char *errstr;
|
||||||
|
int c;
|
||||||
|
retry:
|
||||||
|
t->i = 0;
|
||||||
|
t->argstr = NULL;
|
||||||
|
t->string = t->escape = t->comment = false;
|
||||||
|
t->lineno += 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
c = rdline_getc(&rd);
|
errno = 0;
|
||||||
if (c < 0)
|
c = rdline_getc(t);
|
||||||
|
if (c < 0) {
|
||||||
|
if (errno == 0)
|
||||||
|
return 1;
|
||||||
|
errstr = strerror(errno);
|
||||||
goto fail;
|
goto fail;
|
||||||
if (c == 0 && rd.string) {
|
}
|
||||||
errno = EILSEQ;
|
if (c == 0 && t->string) {
|
||||||
|
errstr = "missing \"";
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
c = rdline_getc(&rd);
|
c = rdline_getc(t);
|
||||||
if (c == 0)
|
if (c == 0) {
|
||||||
errno = EILSEQ;
|
errstr = "unexpected end of line after '%%'";
|
||||||
if (c <= 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
if (c < 0) {
|
||||||
|
errstr = strerror(errno);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (c != '%') {
|
if (c != '%') {
|
||||||
if (!isdigit(c) || (c - '0') >= argc) {
|
if (!isdigit(c)) {
|
||||||
errno = EINVAL;
|
errstr = "exptected digit after '%%'";
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (rd.argstr != NULL) {
|
if ((c - '0') >= t->argc) {
|
||||||
errno = ELOOP;
|
errstr = "argument out of range";
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
rd.argstr = argv[c - '0'];
|
if (t->argstr != NULL) {
|
||||||
|
errstr = "recursive argument "
|
||||||
|
"expansion";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
t->argstr = t->argv[c - '0'];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdline_append(&rd, c))
|
if (rdline_append(t, c)) {
|
||||||
|
errstr = "line too long";
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
} while (c != '\0');
|
} while (c != '\0');
|
||||||
|
|
||||||
return rd.buffer;
|
if (t->buffer[0] == '\0')
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
ret = errno;
|
fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr);
|
||||||
free(rd.buffer);
|
return -1;
|
||||||
errno = ret;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
193
lib/src/rdsvc.c
193
lib/src/rdsvc.c
|
@ -28,17 +28,17 @@
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static int try_unescape(char *arg, const char *filename, size_t lineno)
|
static int try_unescape(char *arg, rdline_t *rd)
|
||||||
{
|
{
|
||||||
if (unescape(arg)) {
|
if (unescape(arg)) {
|
||||||
fprintf(stderr, "%s: %zu: malformed string constant\n",
|
fprintf(stderr, "%s: %zu: malformed string constant\n",
|
||||||
filename, lineno);
|
rd->filename, rd->lineno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char **try_split_argv(char *str, const char *filename, size_t lineno)
|
static char **try_split_argv(char *str, rdline_t *rd)
|
||||||
{
|
{
|
||||||
char **argv = split_argv(str);
|
char **argv = split_argv(str);
|
||||||
|
|
||||||
|
@ -46,11 +46,11 @@ static char **try_split_argv(char *str, const char *filename, size_t lineno)
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
fprintf(stderr, "%s: %zu: malformed string constant\n",
|
fprintf(stderr, "%s: %zu: malformed string constant\n",
|
||||||
filename, lineno);
|
rd->filename, rd->lineno);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: %zu: %s\n", filename, lineno,
|
fprintf(stderr, "%s: %zu: %s\n",
|
||||||
strerror(errno));
|
rd->filename, rd->lineno, strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,43 +58,56 @@ static char **try_split_argv(char *str, const char *filename, size_t lineno)
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_desc(service_t *svc, char *arg,
|
static char *try_strdup(const char *str, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
if (try_unescape(arg, filename, lineno))
|
char *out = strdup(str);
|
||||||
return -1;
|
|
||||||
svc->desc = arg;
|
if (out == NULL) {
|
||||||
return 0;
|
fprintf(stderr, "%s: %zu: out of memory\n",
|
||||||
|
rd->filename, rd->lineno);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_tty(service_t *svc, char *arg,
|
static int svc_desc(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
if (try_unescape(arg, filename, lineno))
|
if (try_unescape(arg, rd))
|
||||||
return -1;
|
return -1;
|
||||||
svc->ctty = arg;
|
svc->desc = try_strdup(arg, rd);
|
||||||
return 0;
|
return svc->desc == NULL ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_exec(service_t *svc, char *arg,
|
static int svc_tty(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
{
|
||||||
|
if (try_unescape(arg, rd))
|
||||||
|
return -1;
|
||||||
|
svc->ctty = try_strdup(arg, rd);
|
||||||
|
return svc->ctty == NULL ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int svc_exec(service_t *svc, char *arg, rdline_t *rd)
|
||||||
{
|
{
|
||||||
exec_t *e, *end;
|
exec_t *e, *end;
|
||||||
char **argv;
|
|
||||||
|
|
||||||
argv = try_split_argv(arg, filename, lineno);
|
|
||||||
if (argv == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
e = calloc(1, sizeof(*e));
|
e = calloc(1, sizeof(*e));
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
fprintf(stderr, "%s: %zu: out of memory\n", filename, lineno);
|
fprintf(stderr, "%s: %zu: out of memory\n",
|
||||||
free(argv);
|
rd->filename, rd->lineno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
e->argv = argv;
|
e->raw_argv = try_strdup(arg, rd);
|
||||||
e->raw_argv = arg;
|
if (e->raw_argv == NULL) {
|
||||||
|
free(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->argv = try_split_argv(e->raw_argv, rd);
|
||||||
|
if (e->argv == NULL) {
|
||||||
|
free(e->raw_argv);
|
||||||
|
free(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc->exec == NULL) {
|
if (svc->exec == NULL) {
|
||||||
svc->exec = e;
|
svc->exec = e;
|
||||||
|
@ -106,47 +119,50 @@ static int svc_exec(service_t *svc, char *arg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_before(service_t *svc, char *arg,
|
static int svc_before(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
if (svc->before != NULL) {
|
if (svc->before != NULL) {
|
||||||
fprintf(stderr, "%s: %zu: 'before' dependencies respecified\n",
|
fprintf(stderr, "%s: %zu: 'before' dependencies respecified\n",
|
||||||
filename, lineno);
|
rd->filename, rd->lineno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc->before = try_split_argv(arg, filename, lineno);
|
svc->raw_before = try_strdup(arg, rd);
|
||||||
|
if (svc->raw_before == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
svc->before = try_split_argv(svc->raw_before, rd);
|
||||||
if (svc->before == NULL)
|
if (svc->before == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
svc->raw_before = arg;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_after(service_t *svc, char *arg,
|
static int svc_after(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
if (svc->after != NULL) {
|
if (svc->after != NULL) {
|
||||||
fprintf(stderr, "%s: %zu: 'after' dependencies respecified\n",
|
fprintf(stderr, "%s: %zu: 'after' dependencies respecified\n",
|
||||||
filename, lineno);
|
rd->filename, rd->lineno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc->after = try_split_argv(arg, filename, lineno);
|
svc->raw_after = try_strdup(arg, rd);
|
||||||
|
if (svc->raw_after == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
svc->after = try_split_argv(svc->raw_after, rd);
|
||||||
if (svc->after == NULL)
|
if (svc->after == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
svc->raw_after = arg;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_type(service_t *svc, char *arg,
|
static int svc_type(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
char **args;
|
char **args;
|
||||||
int i, type;
|
int i, type;
|
||||||
|
|
||||||
args = try_split_argv(arg, filename, lineno);
|
args = try_split_argv(arg, rd);
|
||||||
|
|
||||||
if (args == NULL)
|
if (args == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -155,7 +171,7 @@ static int svc_type(service_t *svc, char *arg,
|
||||||
|
|
||||||
if (type == -1) {
|
if (type == -1) {
|
||||||
fprintf(stderr, "%s: %zu: unknown service type '%s'\n",
|
fprintf(stderr, "%s: %zu: unknown service type '%s'\n",
|
||||||
filename, lineno, args[0]);
|
rd->filename, rd->lineno, args[0]);
|
||||||
free(args);
|
free(args);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -183,48 +199,45 @@ static int svc_type(service_t *svc, char *arg,
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: %zu: unexpected extra arguments "
|
fprintf(stderr, "%s: %zu: unexpected extra arguments "
|
||||||
"for type '%s'\n", filename, lineno, arg);
|
"for type '%s'\n",
|
||||||
|
rd->filename, rd->lineno, arg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svc->type = type;
|
svc->type = type;
|
||||||
free(args);
|
free(args);
|
||||||
free(arg);
|
|
||||||
return 0;
|
return 0;
|
||||||
fail_limit:
|
fail_limit:
|
||||||
fprintf(stderr, "%s: %zu: expected 'limit <value>' after 'respawn'\n",
|
fprintf(stderr, "%s: %zu: expected 'limit <value>' after 'respawn'\n",
|
||||||
filename, lineno);
|
rd->filename, rd->lineno);
|
||||||
free(args);
|
free(args);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int svc_target(service_t *svc, char *arg,
|
static int svc_target(service_t *svc, char *arg, rdline_t *rd)
|
||||||
const char *filename, size_t lineno)
|
|
||||||
{
|
{
|
||||||
int target;
|
int target;
|
||||||
|
|
||||||
if (try_unescape(arg, filename, lineno))
|
if (try_unescape(arg, rd))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
target = svc_target_from_string(arg);
|
target = svc_target_from_string(arg);
|
||||||
|
|
||||||
if (target == -1) {
|
if (target == -1) {
|
||||||
fprintf(stderr, "%s: %zu: unknown service target '%s'\n",
|
fprintf(stderr, "%s: %zu: unknown service target '%s'\n",
|
||||||
filename, lineno, arg);
|
rd->filename, rd->lineno, arg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc->target = target;
|
svc->target = target;
|
||||||
free(arg);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct svc_param {
|
static const struct svc_param {
|
||||||
const char *key;
|
const char *key;
|
||||||
|
|
||||||
int (*handle)(service_t *svc, char *arg,
|
int (*handle)(service_t *svc, char *arg, rdline_t *rd);
|
||||||
const char *filename, size_t lineno);
|
|
||||||
} svc_params[] = {
|
} svc_params[] = {
|
||||||
{ "description", svc_desc },
|
{ "description", svc_desc },
|
||||||
{ "exec", svc_exec },
|
{ "exec", svc_exec },
|
||||||
|
@ -235,49 +248,15 @@ static const struct svc_param {
|
||||||
{ "after", svc_after },
|
{ "after", svc_after },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int splitkv(rdline_t *rd, char **k, char **v)
|
||||||
static char *get_line(int fd, const char *filename, size_t *lineno,
|
|
||||||
int argc, const char *const *args)
|
|
||||||
{
|
{
|
||||||
const char *error;
|
char *key = rd->buffer, *value = rd->buffer;
|
||||||
char *line;
|
|
||||||
int ret;
|
|
||||||
retry:
|
|
||||||
errno = 0;
|
|
||||||
line = rdline(fd, argc, args);
|
|
||||||
ret = errno;
|
|
||||||
|
|
||||||
if (line == NULL && errno != 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case EINVAL: error = "error in argument expansion"; break;
|
|
||||||
case ELOOP: error = "recursive argument expansion"; break;
|
|
||||||
case EILSEQ: error = "missing \""; break;
|
|
||||||
default: error = strerror(errno); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "%s: %zu: %s\n", filename, *lineno, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line != NULL && strlen(line) == 0) {
|
|
||||||
free(line);
|
|
||||||
(*lineno) += 1;
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = ret;
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int splitkv(const char *filename, size_t lineno,
|
|
||||||
char *line, char **k, char **v)
|
|
||||||
{
|
|
||||||
char *key = line, *value = line;
|
|
||||||
|
|
||||||
while (*value != ' ' && *value != '\0') {
|
while (*value != ' ' && *value != '\0') {
|
||||||
if (!isalpha(*value)) {
|
if (!isalpha(*value)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: %zu: unexpected '%c' in keyword\n",
|
"%s: %zu: unexpected '%c' in keyword\n",
|
||||||
filename, lineno, *value);
|
rd->filename, rd->lineno, *value);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
++value;
|
++value;
|
||||||
|
@ -285,7 +264,7 @@ static int splitkv(const char *filename, size_t lineno,
|
||||||
|
|
||||||
if (*value != ' ') {
|
if (*value != ' ') {
|
||||||
fprintf(stderr, "%s: %zu: expected argument after '%s'\n",
|
fprintf(stderr, "%s: %zu: expected argument after '%s'\n",
|
||||||
filename, lineno, key);
|
rd->filename, rd->lineno, key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,8 +275,7 @@ static int splitkv(const char *filename, size_t lineno,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct svc_param *find_param(const char *filename, size_t lineno,
|
static const struct svc_param *find_param(rdline_t *rd, const char *name)
|
||||||
const char *name)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -307,19 +285,20 @@ static const struct svc_param *find_param(const char *filename, size_t lineno,
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s: %zu: unknown keyword '%s'\n",
|
fprintf(stderr, "%s: %zu: unknown keyword '%s'\n",
|
||||||
filename, lineno, name);
|
rd->filename, rd->lineno, name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
service_t *rdsvc(int dirfd, const char *filename)
|
service_t *rdsvc(int dirfd, const char *filename)
|
||||||
{
|
{
|
||||||
char *line = NULL, *key, *value;
|
|
||||||
const struct svc_param *p;
|
const struct svc_param *p;
|
||||||
const char *arg, *args[1];
|
const char *arg, *args[1];
|
||||||
service_t *svc = NULL;
|
service_t *svc = NULL;
|
||||||
size_t argc, lineno;
|
char *key, *value;
|
||||||
int fd;
|
size_t argc;
|
||||||
|
rdline_t rd;
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
fd = openat(dirfd, filename, O_RDONLY);
|
fd = openat(dirfd, filename, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
@ -335,6 +314,8 @@ service_t *rdsvc(int dirfd, const char *filename)
|
||||||
argc = 0;
|
argc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rdline_init(&rd, fd, filename, argc, args);
|
||||||
|
|
||||||
svc = calloc(1, sizeof(*svc));
|
svc = calloc(1, sizeof(*svc));
|
||||||
if (svc == NULL)
|
if (svc == NULL)
|
||||||
goto fail_oom;
|
goto fail_oom;
|
||||||
|
@ -348,32 +329,26 @@ service_t *rdsvc(int dirfd, const char *filename)
|
||||||
if (svc->name == NULL)
|
if (svc->name == NULL)
|
||||||
goto fail_oom;
|
goto fail_oom;
|
||||||
|
|
||||||
for (lineno = 1; ; ++lineno) {
|
while ((ret = rdline(&rd)) == 0) {
|
||||||
line = get_line(fd, filename, &lineno, argc, args);
|
if (splitkv(&rd, &key, &value))
|
||||||
if (line == NULL) {
|
|
||||||
if (errno == 0)
|
|
||||||
break;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (splitkv(filename, lineno, line, &key, &value))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
p = find_param(filename, lineno, key);
|
p = find_param(&rd, key);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
memmove(line, value, strlen(value) + 1);
|
if (p->handle(svc, value, &rd))
|
||||||
if (p->handle(svc, line, filename, lineno))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return svc;
|
return svc;
|
||||||
fail_oom:
|
fail_oom:
|
||||||
fputs("out of memory\n", stderr);
|
fputs("out of memory\n", stderr);
|
||||||
fail:
|
fail:
|
||||||
free(line);
|
|
||||||
delsvc(svc);
|
delsvc(svc);
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -59,6 +59,7 @@ int unescape(char *src)
|
||||||
case 't': c = '\t'; break;
|
case 't': c = '\t'; break;
|
||||||
case '\\':
|
case '\\':
|
||||||
case '"':
|
case '"':
|
||||||
|
case '%':
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
c = 0;
|
c = 0;
|
||||||
|
|
Loading…
Reference in a new issue