mirror of
https://github.com/pygos/init.git
synced 2024-11-22 19:19:47 +01:00
Merge argument substitution into rdline
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
parent
352a9060b6
commit
ca7b7c15c5
5 changed files with 79 additions and 104 deletions
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in a new issue