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.
This commit is contained in:
Nicholas J. Kain 2016-05-06 16:44:10 -04:00
parent 04ec7c8f4b
commit 1fc7bd3144

View File

@ -1,4 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
@ -12,6 +15,7 @@
#include "nk/log.h" #include "nk/log.h"
#include "nk/privilege.h" #include "nk/privilege.h"
#include "nk/copy_cmdarg.h" #include "nk/copy_cmdarg.h"
#include "nk/io.h"
struct cfgparse { struct cfgparse {
char buf[MAX_BUF]; char buf[MAX_BUF];
@ -227,26 +231,58 @@ struct cfgparse {
static void parse_cfgfile(const char fname[static 1]) static void parse_cfgfile(const char fname[static 1])
{ {
bool reached_eof = false;
struct cfgparse ccfg; struct cfgparse ccfg;
memset(&ccfg, 0, sizeof 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]; char l[MAX_BUF];
size_t linenum = 0; size_t lc = 0;
while (linenum++, fgets(l, sizeof l, f)) { memset(l, 0, sizeof l);
size_t llen = strlen(l); int fd = open(fname, O_RDONLY|O_CLOEXEC, 0);
const char *p = l; if (fd < 0)
const char *pe = l + llen; suicide("Unable to open config file '%s'.", fname);
%% write init;
%% write exec;
if (ccfg.cs == file_cfg_error) size_t linenum = 0;
suicide("error parsing config file line %zu: malformed", linenum); for (;;) {
if (ccfg.cs < file_cfg_first_final) if (lc + 1 >= sizeof l) suicide("sizeof l - 1 - lc would underflow");
suicide("error parsing config file line %zu: incomplete", linenum); 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;
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);
} }
%%{ %%{