#include #include // rename #undef EOF // used as a label #include "buffer.h" #include "case.h" #include "cdbmake.h" #include "logmsg.h" #include "open.h" #include "stralloc.h" #define WHO "setforward" static void usage() { logmsg(WHO, 100, USAGE, "setforward data.cdb data.tmp"); } static void nomem() { logmsg(WHO, 111, FATAL, "out of memory"); } static void missingsemicolon() { logmsg(WHO, 100, FATAL, "final instruction must end with semicolon"); } static void extracolon() { logmsg(WHO, 100, FATAL, "double colons are not permitted"); } static void extracomma() { logmsg(WHO, 100, FATAL, "commas are not permitted before colons"); } static void nulbyte() { logmsg(WHO, 100, FATAL, "NUL bytes are not permitted"); } static void longaddress() { logmsg(WHO, 100, FATAL, "addresses over 800 bytes are not permitted"); } char *fncdb; char *fntmp; int fd; struct cdb_make cdb; stralloc key = {0}; stralloc target = {0}; /* always initialized; no NUL */ stralloc command = {0}; /* always initialized; no NUL */ stralloc instr = {0}; /* always initialized */ int flagtarget = 0; /* 0: reading target; command is empty; instr is empty */ /* 1: target is complete; instr still has to be written; reading command */ static void writeerr() { logmsg(WHO, 111, FATAL, B("unable to write to: ", fntmp)); } static void doit(char *prepend, char *data, int datalen) { if (!stralloc_copys(&key, prepend)) nomem(); if (!stralloc_cat(&key, &target)) nomem(); case_lowerb(key.s, key.len); if (cdb_make_add(&cdb, key.s, key.len, data, datalen) == -1) writeerr(); } static int getch(char *ch) { int r; r = buffer_get(buffer_0small, ch, 1); if (r == -1) logmsg(WHO, 111, FATAL, "unable to read input: "); return r; } int main(int argc, char **argv) { char ch; if (!stralloc_copys(&target, "")) nomem(); if (!stralloc_copys(&command, "")) nomem(); if (!stralloc_copys(&instr, "")) nomem(); fncdb = argv[1]; if (!fncdb) usage(); fntmp = argv[2]; if (!fntmp) usage(); fd = open_trunc(fntmp); if (fd == -1) logmsg(WHO, 111, FATAL, B("unable to create: ", fntmp)); if (cdb_make_start(&cdb, fd) == -1) writeerr(); for (;;) { if (!getch(&ch)) goto EOF; if (ch == '#') { while (ch != '\n') if (!getch(&ch)) goto EOF; continue; } if (ch == ' ') continue; if (ch == '\n') continue; if (ch == '\t') continue; if (ch == ':') { if (flagtarget) extracolon(); flagtarget = 1; continue; } if ((ch == ',') || (ch == ';')) { if (!flagtarget) extracomma(); if (command.len) { if (command.s[0] == '?') { doit("?", command.s + 1, command.len - 1); } else if ((command.s[0] == '|') || (command.s[0] == '!')) { if (!stralloc_cat(&instr, &command)) nomem(); if (!stralloc_0(&instr)) nomem(); } else if ((command.s[0] == '.') || (command.s[0] == '/')) { if (!stralloc_cat(&instr, &command)) nomem(); if (!stralloc_0(&instr)) nomem(); } else { if (command.len > 800) longaddress(); if (command.s[0] != '&') if (!stralloc_cats(&instr, "&")) nomem(); if (!stralloc_cat(&instr, &command)) nomem(); if (!stralloc_0(&instr)) nomem(); } } if (!stralloc_copys(&command, "")) nomem(); if (ch == ';') { if (instr.len) doit(":", instr.s, instr.len); if (!stralloc_copys(&target, "")) nomem(); if (!stralloc_copys(&instr, "")) nomem(); flagtarget = 0; } continue; } if (ch == '\\') if (!getch(&ch)) goto EOF; if (ch == 0) nulbyte(); if (!stralloc_append(flagtarget ? &command : &target, &ch)) nomem(); } EOF: if (flagtarget || target.len) missingsemicolon(); if (cdb_make_finish(&cdb) == -1) writeerr(); if (fsync(fd) == -1) writeerr(); if (close(fd) == -1) writeerr(); /* NFS stupidity */ if (rename(fntmp, fncdb) == -1) logmsg(WHO, 111, FATAL, B("unable to move ", fntmp, " to: ", fncdb)); _exit(0); }