From 1fc7bd31448a284b8b3dc7ade5436d586de06fb5 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Fri, 6 May 2016 16:44:10 -0400 Subject: [PATCH] Eliminate fopen() in cfg.rl. Use unbuffered i/o instead. This is fairly tricky, but fopen() almost surely interally calls malloc when it creates the FILE* that it returns. I did promise that ndhc doesn't call malloc after initialization, besides what libc may do internally, but it feels a bit dishonest given that fopen() is basically sure to do so on any general-purpose libc. Thus, eliminate it and just use direct POSIX i/o. With the previous pidfile changes, ndhc doesn't use C fopen() at all. In practice, this change won't really be noticeable as most libcs, particularly with dynamic linking, will end up calling malloc themselves during program initialization before main() is invoked. --- src/cfg.rl | 64 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/src/cfg.rl b/src/cfg.rl index 23ff81b..e5833ae 100644 --- a/src/cfg.rl +++ b/src/cfg.rl @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include @@ -12,6 +15,7 @@ #include "nk/log.h" #include "nk/privilege.h" #include "nk/copy_cmdarg.h" +#include "nk/io.h" struct cfgparse { char buf[MAX_BUF]; @@ -227,26 +231,58 @@ struct cfgparse { static void parse_cfgfile(const char fname[static 1]) { + bool reached_eof = false; struct cfgparse ccfg; memset(&ccfg, 0, sizeof ccfg); - FILE *f = fopen(fname, "r"); - if (!f) - suicide("Unable to open config file '%s'.", fname); char l[MAX_BUF]; + size_t lc = 0; + memset(l, 0, sizeof l); + int fd = open(fname, O_RDONLY|O_CLOEXEC, 0); + if (fd < 0) + suicide("Unable to open config file '%s'.", fname); + size_t linenum = 0; - while (linenum++, fgets(l, sizeof l, f)) { - size_t llen = strlen(l); - const char *p = l; - const char *pe = l + llen; - %% write init; - %% write exec; + for (;;) { + if (lc + 1 >= sizeof l) suicide("sizeof l - 1 - lc would underflow"); + ssize_t rc = safe_read(fd, l + lc, sizeof l - 1 - lc); + if (rc < 0) + suicide("Error reading config file '%s'.", fname); + if (rc == 0) { + l[lc] = '\n'; rc = 1; reached_eof = true; // Emulate a LF to terminate the line. + } + lc += rc; + + size_t lstart = 0, lend = 0, consumed = 0; + for (; lend < lc; ++lend) { + if (l[lend] == '\n') { + ++linenum; consumed = lend; - if (ccfg.cs == file_cfg_error) - suicide("error parsing config file line %zu: malformed", linenum); - if (ccfg.cs < file_cfg_first_final) - suicide("error parsing config file line %zu: incomplete", linenum); + size_t llen = lend - lstart; + const char *p = l + lstart; + const char *pe = l + lstart + llen + 1; + %% write init; + %% write exec; + + if (ccfg.cs == file_cfg_error) + suicide("error parsing config file line %zu: malformed", linenum); + if (ccfg.cs < file_cfg_first_final) + suicide("error parsing config file line %zu: incomplete", linenum); + lstart = lend + 1; + } + } + if (reached_eof) + break; + if (!consumed && lend >= sizeof l - 1) + suicide("Line %u in config file '%s' is too long: %u > %u.", + linenum, fname, lend, sizeof l - 1); + + if (consumed + 1 > lc) suicide("lc[%zu] - consumed[%zu] would underflow", lc, lend); + if (consumed) { + memmove(l, l + consumed + 1, lc - consumed - 1); + lc -= consumed + 1; + } } - fclose(f); + close(fd); } %%{