1
0
Fork 0
mirror of https://github.com/pygos/init.git synced 2024-11-22 11:19:45 +01: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/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/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/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_SOURCES += lib/src/opensock.c lib/src/enum_to_name.c $(HEADRS)
libinit_a_CPPFLAGS = $(AM_CPPFLAGS) libinit_a_CPPFLAGS = $(AM_CPPFLAGS)

View file

@ -55,8 +55,17 @@ typedef struct {
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 with
errno set to EILSEQ. 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. 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); 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 */ #endif /* UTIL_H */

View file

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

View file

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