diff --git a/initd/runlst.c b/initd/runlst.c index 908ec15..ee8c5c5 100644 --- a/initd/runlst.c +++ b/initd/runlst.c @@ -37,15 +37,28 @@ static NORETURN void split_and_exec(char *cmd) while (*cmd != '\0') { argv[i++] = cmd; /* FIXME: buffer overflow!! */ - while (*cmd != '\0' && !isspace(*cmd)) - ++cmd; + if (*cmd == '"') { + while (*cmd != '\0' && *cmd != '"') { + if (cmd[0] == '\\' && cmd[1] != '\0') + ++cmd; - if (isspace(*cmd)) { - *(cmd++) = '\0'; - - while (isspace(*cmd)) ++cmd; + } + + if (*cmd == '"') + *(cmd++) = '\0'; + + unescape(argv[i - 1]); + } else { + while (*cmd != '\0' && *cmd != ' ') + ++cmd; + + if (*cmd == ' ') + *(cmd++) = '\0'; } + + while (*cmd == ' ') + ++cmd; } argv[i] = NULL; diff --git a/lib/include/util.h b/lib/include/util.h index e99be3b..0ed7002 100644 --- a/lib/include/util.h +++ b/lib/include/util.h @@ -68,20 +68,10 @@ typedef struct { char *rdline(int fd, int argc, const char *const *argv); /* - Split a line of the shape "key = value" into key and value part. - - The key can contain alphanumeric characters and can be padded with - spaces or tabs. - - The value can be either a sequence of alphanumeric characters, period - or underscore OR a string in quotation marks. For strings, the - quotation marks are removed and escape sequences are processed. - - The value may also be padded with spaces or tabs but the line may not - contain anything else after the value, except for spaces, tabs or - the '#' symbol which is interpreted as start of a comment. + Remove double quotes ('"') from a string and substitute escape + sequences in between double quotes. */ -int splitkv(char *line, char **key, char **value); +int unescape(char *src); /* Search through an array of enum_map_t entries to resolve a string to diff --git a/lib/src/rdsvc.c b/lib/src/rdsvc.c index b186cd9..04cf30f 100644 --- a/lib/src/rdsvc.c +++ b/lib/src/rdsvc.c @@ -28,10 +28,21 @@ #include "service.h" #include "util.h" +static int try_unescape(char *arg, const char *filename, size_t lineno) +{ + if (unescape(arg)) { + fprintf(stderr, "%s: %zu: malformed string constant\n", + filename, lineno); + return -1; + } + return 0; +} + static int svc_desc(service_t *svc, char *arg, const char *filename, size_t lineno) { - (void)filename; (void)lineno; + if (try_unescape(arg, filename, lineno)) + return -1; svc->desc = arg; return 0; } @@ -39,7 +50,8 @@ static int svc_desc(service_t *svc, char *arg, static int svc_tty(service_t *svc, char *arg, const char *filename, size_t lineno) { - (void)filename; (void)lineno; + if (try_unescape(arg, filename, lineno)) + return -1; svc->ctty = arg; return 0; } @@ -63,8 +75,12 @@ static int svc_exec(service_t *svc, char *arg, static int svc_before(service_t *svc, char *arg, const char *filename, size_t lineno) { - char **new = realloc(svc->before, - sizeof(char*) * (svc->num_before + 1)); + char **new; + + if (try_unescape(arg, filename, lineno)) + return -1; + + new = realloc(svc->before, sizeof(char*) * (svc->num_before + 1)); if (new == NULL) { fprintf(stderr, "%s: %zu: out of memory\n", filename, lineno); @@ -80,7 +96,12 @@ static int svc_before(service_t *svc, char *arg, static int svc_after(service_t *svc, char *arg, const char *filename, size_t lineno) { - char **new = realloc(svc->after, sizeof(char*) * (svc->num_after + 1)); + char **new; + + if (try_unescape(arg, filename, lineno)) + return -1; + + new = realloc(svc->after, sizeof(char*) * (svc->num_after + 1)); if (new == NULL) { fprintf(stderr, "%s: %zu: out of memory\n", filename, lineno); @@ -96,7 +117,22 @@ static int svc_after(service_t *svc, char *arg, static int svc_type(service_t *svc, char *arg, const char *filename, size_t lineno) { - int type = svc_type_from_string(arg); + char *extra; + int type; + + if (try_unescape(arg, filename, lineno)) + return -1; + + for (extra = arg; *extra != ' ' && *extra != '\0'; ++extra) + ; + + if (*extra == ' ') { + *(extra++) = '\0'; + } else { + extra = NULL; + } + + type = svc_type_from_string(arg); if (type == -1) { fprintf(stderr, "%s: %zu: unknown service type '%s'\n", @@ -104,15 +140,51 @@ static int svc_type(service_t *svc, char *arg, return -1; } + if (extra != NULL) { + switch (type) { + case SVC_RESPAWN: + if (strncmp(extra, "limit ", 6) != 0) + goto fail_limit; + extra += 6; + + svc->rspwn_limit = 0; + + if (!isdigit(*extra)) + goto fail_limit; + + while (isdigit(*extra)) { + svc->rspwn_limit *= 10; + svc->rspwn_limit += *(extra++) - '0'; + } + + if (*extra != '\0') + goto fail_limit; + break; + default: + fprintf(stderr, "%s: %zu: unexpected extra arguments " + "for type '%s'\n", filename, lineno, arg); + return -1; + } + } + svc->type = type; free(arg); return 0; +fail_limit: + fprintf(stderr, "%s: %zu: expected 'limit ' after 'respawn'\n", + filename, lineno); + return -1; } static int svc_target(service_t *svc, char *arg, const char *filename, size_t lineno) { - int target = svc_target_from_string(arg); + int target; + + if (try_unescape(arg, filename, lineno)) + return -1; + + target = svc_target_from_string(arg); if (target == -1) { fprintf(stderr, "%s: %zu: unknown service target '%s'\n", @@ -125,33 +197,6 @@ static int svc_target(service_t *svc, char *arg, return 0; } -static int svc_rspwn_limit(service_t *svc, char *arg, - const char *filename, size_t lineno) -{ - const char *ptr; - - svc->rspwn_limit = 0; - - if (!isdigit(*arg)) - goto fail; - - for (ptr = arg; isdigit(*ptr); ++ptr) - svc->rspwn_limit = svc->rspwn_limit * 10 + (*ptr - '0'); - - if (*ptr != '\0') - goto fail; - - free(arg); - return 0; -fail: - fprintf(stderr, - "%s: %zu: expected numeric argument for respawn limit\n", - filename, lineno); - free(arg); - return -1; -} - - static const struct { const char *key; @@ -165,7 +210,6 @@ static const struct { { "tty", svc_tty }, { "before", svc_before }, { "after", svc_after }, - { "respawn_limit", svc_rspwn_limit }, }; @@ -239,36 +283,42 @@ service_t *rdsvc(int dirfd, const char *filename) goto fail; } - if (splitkv(line, &key, &value)) { - if (key == NULL) { - fprintf(stderr, - "%s: %zu: expected = \n", - filename, lineno); - } else if (value == NULL) { - fprintf(stderr, - "%s: %zu: expected value after %s\n", - filename, lineno, key); - } else { - fprintf(stderr, - "%s: %zu: unexpected arguments " - "after key-value pair\n", - filename, lineno); - } - goto fail; - } - - if (key == NULL) { + if (!strlen(line)) { free(line); continue; } + key = value = line; + + while (*value != ' ' && *value != '\0') { + if (!isalpha(*value)) { + fprintf(stderr, "%s: %zu: unexpected '%c' in " + "keyword\n", filename, lineno, *value); + goto fail_line; + } + ++value; + } + + if (*value == ' ') { + *(value++) = '\0'; + } else { + value = NULL; + } + for (i = 0; i < ARRAY_SIZE(svc_params); ++i) { if (!strcmp(svc_params[i].key, key)) break; } if (i >= ARRAY_SIZE(svc_params)) { - fprintf(stderr, "%s: %zu: unknown parameter '%s'\n", + fprintf(stderr, "%s: %zu: unknown keyword '%s'\n", + filename, lineno, key); + goto fail_line; + } + + if (value == NULL) { + fprintf(stderr, + "%s: %zu: expected argument after '%s'\n", filename, lineno, key); goto fail_line; } diff --git a/lib/src/splitkv.c b/lib/src/splitkv.c index b1ef8d3..3631ea8 100644 --- a/lib/src/splitkv.c +++ b/lib/src/splitkv.c @@ -19,13 +19,6 @@ #include "util.h" -static char *skpspc(char *ptr) -{ - while (*ptr == ' ' || *ptr == '\t') - ++ptr; - return ptr; -} - static int xdigit(int x) { if (isupper(x)) @@ -35,107 +28,61 @@ static int xdigit(int x) return x - '0'; } -static char *parse_str(char *src) +int unescape(char *src) { char *dst = src; int c; for (;;) { - c = *(src++); + while (*src != '"' && *src != '\0') + *(dst++) = *(src++); - switch (c) { - case '\\': - c = *(src++); - - switch (c) { - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 't': c = '\t'; break; - case '\\': break; - case '"': break; - case 'x': - c = 0; - if (isxdigit(*src)) - c = (c << 4) | xdigit(*(src++)); - if (isxdigit(*src)) - c = (c << 4) | xdigit(*(src++)); - break; - case '0': - c = 0; - if (isdigit(*src) && *src < '8') - c = (c << 3) | (*(src++) - '0'); - if (isdigit(*src) && *src < '8') - c = (c << 3) | (*(src++) - '0'); - if (isdigit(*src) && *src < '8') - c = (c << 3) | (*(src++) - '0'); - break; - default: - return NULL; - } + if (*src == '\0') break; - case '"': - *(dst++) = '\0'; - goto out; + + ++src; + + while ((c = *(src++)) != '"') { + if (c == '\0') + return -1; + + if (c == '\\') { + c = *(src++); + + switch (c) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case '\\': + case '"': + break; + case 'x': + c = 0; + if (isxdigit(*src)) + c = (c<<4) | xdigit(*(src++)); + if (isxdigit(*src)) + c = (c<<4) | xdigit(*(src++)); + break; + case '0': + c = 0; + if (isdigit(*src) && *src < '8') + c = (c<<3) | (*(src++) - '0'); + if (isdigit(*src) && *src < '8') + c = (c<<3) | (*(src++) - '0'); + if (isdigit(*src) && *src < '8') + c = (c<<3) | (*(src++) - '0'); + break; + default: + return -1; + } + } + + *(dst++) = c; } - - *(dst++) = c; - } -out: - return src; -} - -int splitkv(char *line, char **key, char **value) -{ - *key = NULL; - *value = NULL; - - line = skpspc(line); - - if (*line == '#' || *line == '\0') - return 0; - - if (!isalpha(*line)) - return -1; - - *key = line; - - while (isalnum(*line)) - ++line; - - if (*line == ' ' || *line == '\t') { - *(line++) = '\0'; - line = skpspc(line); } - if (*line != '=') - return -1; - - *(line++) = '\0'; - line = skpspc(line); - - if (*line == '"') { - ++line; - *value = line; - - line = parse_str(line); - } else if (isalnum(*line)) { - *value = line; - - while (isalnum(*line) || *line == '.' || *line == '_') - ++line; - - if (*line != '\0') - *(line++) = '\0'; - } else { - return -1; - } - - line = skpspc(line); - - if (*line != '\0' && *line != '#') - return -1; - + *(dst++) = '\0'; return 0; } diff --git a/services/agetty.in b/services/agetty.in index c0ae21b..c4f78ad 100644 --- a/services/agetty.in +++ b/services/agetty.in @@ -1,6 +1,6 @@ -description = "agetty on %0" -exec = "@SBINPATH@/agetty %0 linux" -type = respawn -target = boot -after = sysinit -tty = "/dev/%0" +description agetty on %0 +exec "@SBINPATH@/agetty" %0 linux +type respawn +target boot +after sysinit +tty "/dev/%0" diff --git a/services/hostname.in b/services/hostname.in index be0020d..55b71d9 100644 --- a/services/hostname.in +++ b/services/hostname.in @@ -1,6 +1,6 @@ -description = "reload hostname" -exec = "@BINPATH@/hostname --file /etc/hostname" -type = wait -target = boot -before = sysinit -after = hwclock +description reload hostname +exec "@BINPATH@/hostname" --file /etc/hostname +type wait +target boot +before sysinit +after hwclock diff --git a/services/hwclock.in b/services/hwclock.in index e8a2513..d07b3e7 100644 --- a/services/hwclock.in +++ b/services/hwclock.in @@ -1,5 +1,5 @@ -description = "restore time from RTC" -exec = "@SBINPATH@/hwclock --hctosys --utc" -type = wait -target = boot -before = sysinit +description restore time from RTC +exec "@SBINPATH@/hwclock" --hctosys --utc +type wait +target boot +before sysinit diff --git a/services/loopback.in b/services/loopback.in index 741ed1c..c44306c 100644 --- a/services/loopback.in +++ b/services/loopback.in @@ -1,9 +1,9 @@ -description = "configure network loopback device" -type = wait -target = boot -before = sysinit -after = hwclock -after = hostname +description configure network loopback device +type wait +target boot +before sysinit +after hwclock +after hostname -exec = "@SBINPATH@/ip addr add 127.0.0.1/8 dev lo brd +" -exec = "@SBINPATH@/ip link set lo up" +exec "@SBINPATH@/ip" addr add 127.0.0.1/8 dev lo brd + +exec "@SBINPATH@/ip" link set lo up diff --git a/services/reboot.in b/services/reboot.in index 94d1b78..3c3c689 100644 --- a/services/reboot.in +++ b/services/reboot.in @@ -1,7 +1,7 @@ -description = "system reboot" -exec = "@SBINPATH@/shutdown -nrf" -type = wait -target = reboot -after = "sync" -after = "sigkill" -after = "sigterm" +description system reboot +exec "@SBINPATH@/shutdown" -nrf +type wait +target reboot +after sync +after sigkill +after sigterm diff --git a/services/shutdown.in b/services/shutdown.in index 560dd47..c357b36 100644 --- a/services/shutdown.in +++ b/services/shutdown.in @@ -1,7 +1,7 @@ -description = "system shutdown" -exec = "@SBINPATH@/shutdown -npf" -type = wait -target = shutdown -after = "sync" -after = "sigkill" -after = "sigterm" +description system shutdown +exec "@SBINPATH@/shutdown" -npf +type wait +target shutdown +after sync +after sigkill +after sigterm diff --git a/services/sigkill.in b/services/sigkill.in index 10e96b4..8f09dd5 100644 --- a/services/sigkill.in +++ b/services/sigkill.in @@ -1,8 +1,8 @@ -description = "send SIGKILL to remaining processes" -exec = "@SCRIPTDIR@/killall5 9" -type = wait -target = "%0" -after = "sigterm" -before = "sync" -before = "shutdown" -before = "reboot" +description send SIGKILL to remaining processes +exec "@SCRIPTDIR@/killall5" 9 +type wait +target %0 +after sigterm +before sync +before shutdown +before reboot diff --git a/services/sigterm.in b/services/sigterm.in index 126d144..b00610c 100644 --- a/services/sigterm.in +++ b/services/sigterm.in @@ -1,9 +1,9 @@ -description = "send SIGTERM to all processes" -exec = "@SCRIPTDIR@/killall5 15" -exec = "@BINPATH@/sleep 5" -type = wait -target = "%0" -before = "sigkill" -before = "sync" -before = "reboot" -before = "shutdown" +description send SIGTERM to all processes +exec "@SCRIPTDIR@/killall5" 15 +exec "@BINPATH@/sleep" 5 +type wait +target %0 +before sigkill +before sync +before reboot +before shutdown diff --git a/services/sync.in b/services/sync.in index 69571cf..0ffb9a5 100644 --- a/services/sync.in +++ b/services/sync.in @@ -1,8 +1,8 @@ -description = "sync" -exec = "@BINPATH@/sync" -type = wait -target = "%0" -after = "sigkill" -after = "sigterm" -before = "reboot" -before = "shutdown" +description sync +exec "@BINPATH@/sync" +type wait +target %0 +after sigkill +after sigterm +before reboot +before shutdown diff --git a/services/sysctl.in b/services/sysctl.in index cd7b217..61edaf3 100755 --- a/services/sysctl.in +++ b/services/sysctl.in @@ -1,7 +1,7 @@ -description = "configure kernel paramters" -exec = "@SBINPATH@/sysctl --system" -type = wait -target = boot -before = sysinit -after = hwclock -after = hostname +description configure kernel paramters +exec "@SBINPATH@/sysctl" --system +type wait +target boot +before sysinit +after hwclock +after hostname diff --git a/services/sysinit b/services/sysinit index 12e5c55..cb5eb6b 100644 --- a/services/sysinit +++ b/services/sysinit @@ -1,3 +1,3 @@ -description = "basic system initialization" -type = once -target = boot +description basic system initialization +type once +target boot