1
0
Fork 0
mirror of https://github.com/pygos/init.git synced 2024-05-19 12:16:14 +02:00

Merge argument substitution into rdline

Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
David Oberhollenzer 2018-04-04 11:55:59 +02:00
parent 352a9060b6
commit ca7b7c15c5
5 changed files with 79 additions and 104 deletions

View file

@ -2,7 +2,7 @@ HEADRS = lib/include/util.h lib/include/service.h lib/include/telinit.h
libinit_a_SOURCES = lib/src/delsvc.c lib/src/rdline.c lib/src/svcmap.c
libinit_a_SOURCES += lib/src/splitkv.c lib/src/enum_by_name.c
libinit_a_SOURCES += lib/src/strexpand.c lib/src/rdsvc.c lib/src/svcscan.c
libinit_a_SOURCES += lib/src/rdsvc.c lib/src/svcscan.c
libinit_a_SOURCES += lib/src/del_svc_list.c lib/src/svc_tsort.c
libinit_a_SOURCES += lib/src/opensock.c lib/src/enum_to_name.c $(HEADRS)
libinit_a_CPPFLAGS = $(AM_CPPFLAGS)

View file

@ -55,8 +55,17 @@ typedef struct {
it with a backslash.
- If a second, coresponding '"' is not found, processing fails with
errno set to EILSEQ.
- 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
outside the bounds set by argc, processing fails and sets errno
to EINVAL. 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 with errno set to ELOOP.
*/
char *rdline(int fd);
char *rdline(int fd, int argc, const char *const *argv);
/*
Split a line of the shape "key = value" into key and value part.
@ -88,12 +97,5 @@ const enum_map_t *enum_by_name(const enum_map_t *map, const char *name);
*/
const char *enum_to_name(const enum_map_t *map, int value);
/*
Create a copy of the input string inp, but replace all occourances
of %<number> with argv[number] if the number is within the bounds
specified by argc.
*/
char *strexpand(const char *inp, size_t argc, const char *const *argv);
#endif /* UTIL_H */

View file

@ -27,33 +27,45 @@ enum {
STATE_STRING = 1,
STATE_STRING_ESC = 2,
STATE_COMMENT = 3,
STATE_ARG = 4,
};
char *rdline(int fd)
char *rdline(int fd, int argc, const char *const *argv)
{
size_t i = 0, bufsiz = 0, newsz;
int ret, state = STATE_INITIAL;
char c, *new, *buffer = NULL;
const char *argstr = NULL;
for (;;) {
switch (read(fd, &c, 1)) {
case 0:
if (i == 0) {
errno = 0;
return NULL;
}
c = '\0';
break;
case 1:
if (c == '\n')
if (argstr == NULL) {
switch (read(fd, &c, 1)) {
case 0:
if (i == 0) {
errno = 0;
return NULL;
}
c = '\0';
break;
default:
if (errno == EINTR)
break;
case 1:
break;
default:
if (errno == EINTR)
continue;
goto fail;
}
} else {
c = *(argstr++);
if (c == '\0') {
argstr = NULL;
continue;
goto fail;
}
}
if (c == '\n')
c = '\0';
switch (state) {
case STATE_STRING:
if (c == '\\')
@ -68,6 +80,20 @@ char *rdline(int fd)
if (c != '\0')
continue;
break;
case STATE_ARG:
state = STATE_INITIAL;
if (c == '%')
break;
if (!isdigit(c) || (c - '0') >= argc) {
errno = EINVAL;
goto fail;
}
if (argstr != NULL) {
errno = ELOOP;
goto fail;
}
argstr = argv[c - '0'];
continue;
default:
if (isspace(c))
c = ' ';
@ -77,6 +103,10 @@ char *rdline(int fd)
state = STATE_COMMENT;
continue;
}
if (c == '%') {
state = STATE_ARG;
continue;
}
if (c == '"')
state = STATE_STRING;
break;

View file

@ -171,7 +171,7 @@ static const struct {
service_t *rdsvc(int dirfd, const char *filename)
{
const char *arg, *args[1];
const char *arg, *args[1], *error;
char *line, *key, *value;
size_t i, argc, lineno;
service_t *svc;
@ -213,15 +213,30 @@ service_t *rdsvc(int dirfd, const char *filename)
for (lineno = 1; ; ++lineno) {
errno = 0;
line = rdline(fd);
line = rdline(fd, argc, args);
if (line == NULL) {
if (errno != 0) {
fprintf(stderr, "read: %s: %zu: %s\n",
filename, lineno, strerror(errno));
goto fail;
if (errno == 0)
break;
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;
}
break;
fprintf(stderr, "%s: %zu: %s\n",
filename, lineno, error);
goto fail;
}
if (splitkv(line, &key, &value)) {
@ -258,7 +273,7 @@ service_t *rdsvc(int dirfd, const char *filename)
goto fail_line;
}
value = strexpand(value, argc, args);
value = strdup(value);
if (value == NULL) {
fputs("out of memory", stderr);
goto fail_line;

View file

@ -1,72 +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 <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "util.h"
char *strexpand(const char *inp, size_t argc, const char *const *argv)
{
char *out, *dst;
const char *ptr;
size_t i, len;
ptr = inp;
len = 0;
while (*ptr != '\0') {
if (ptr[0] == '%' && isdigit(ptr[1])) {
i = ptr[1] - '0';
if (i < argc)
len += strlen(argv[i]);
ptr += 2;
} else if (ptr[0] == '%' && ptr[1] == '%') {
ptr += 2;
len += 1;
} else {
++ptr;
++len;
}
}
out = calloc(1, len + 1);
if (out == NULL)
return NULL;
dst = out;
while (*inp != '\0') {
if (inp[0] == '%' && isdigit(inp[1])) {
i = inp[1] - '0';
if (i < argc) {
len = strlen(argv[i]);
memcpy(dst, argv[i], len);
dst += len;
}
inp += 2;
} else if (inp[0] == '%' && inp[1] == '%') {
*(dst++) = '%';
inp += 2;
} else {
*(dst++) = *(inp++);
}
}
return out;
}