Skip to content

Commit

Permalink
Eliminate fopen() in cfg.rl. Use unbuffered i/o instead.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
niklata committed May 6, 2016
1 parent 04ec7c8 commit 1fc7bd3
Showing 1 changed file with 50 additions and 14 deletions.
64 changes: 50 additions & 14 deletions src/cfg.rl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
Expand All @@ -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];
Expand Down Expand Up @@ -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);
}

%%{
Expand Down

0 comments on commit 1fc7bd3

Please sign in to comment.