summaryrefslogtreecommitdiffstats
path: root/prog/6/conf.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--prog/6/conf.c561
1 files changed, 498 insertions, 63 deletions
diff --git a/prog/6/conf.c b/prog/6/conf.c
index 6945876..b8ce0be 100644
--- a/prog/6/conf.c
+++ b/prog/6/conf.c
@@ -1,88 +1,523 @@
-#include <stdio.h>
-#include <search.h>
-#include <string.h>
+#include <stdbool.h>
+#include <confuse.h>
#include <arpa/inet.h>
-int ipv6_compare (const struct in6_addr * a, const struct in6_addr * b) {
- return memcmp(a->s6_addr, b->s6_addr, sizeof a->s6_addr);
+enum type {
+ nothing,
+ network,
+ ns,
+ ptr,
+ ptr6c
+};
+struct trie {
+ struct trie * dir[3]; // left, right, up
+ enum type type;
+ void * data;
+};
+struct trie * next (struct trie * trie) { // for depth-first walking the trie, pass in the root trie first
+ if (trie->dir[0])
+ return trie->dir[0];
+ if (trie->dir[1])
+ return trie->dir[1];
+ while (trie->dir[2]) {
+ if (trie->dir[2]->dir[1])
+ if (trie->dir[2]->dir[1] != trie)
+ return trie->dir[2]->dir[1];
+ trie = trie->dir[2];
+ }
+ return NULL;
+ // lahko noč!
}
-struct zone {
+struct network {
struct in6_addr addr;
int mask;
char * email;
- char ** ns;
- int nslen;
- struct zone * next;
+ char ** ns; // first one is master
+ time_t serial; // for soa record
+ time_t ttl;
+ struct suffix * suffix; // network does not own a suffix
+ char * from; // master that sent us this network or NULL if I am the master
};
+void free_network (struct network * network) {
+ if (!network)
+ return;
+ char ** pcp = network->ns;
+ if (pcp)
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(network->ns);
+ free(network->email);
+ free(network->from);
+ free(network);
+}
struct ns {
struct in6_addr addr;
int mask;
char ** ns;
- int nslen;
- struct ns * next;
+ time_t ttl;
+ char * from; // master that sent us this ns or NULL if I am the master
};
+void free_ns (struct ns * ns) {
+ if (!ns)
+ return;
+ char ** pcp = ns->ns;
+ if (pcp)
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(ns->ns);
+ free(ns->from);
+ free(ns);
+}
struct ptr {
struct in6_addr addr;
- int mask;
- char ptr;
- time_t created;
+ char * hostname;
+ time_t ttl; // time of creation for ptr6c records
+ char * from; // master that sent us this ptr or NULL if I am the master
+};
+void free_ptr (struct ptr * ptr) {
+ if (!ptr)
+ return;
+ free(ptr->hostname);
+ free(ptr->from);
+ free(ptr);
+}
+void free_trie (struct trie * trie) {
+ if (!trie)
+ return;
+ switch (trie->type) {
+ case network:
+ free_network((struct network *) trie->data);
+ break;
+ case ns:
+ free_ns((struct ns *) trie->data);
+ break;
+ case ptr:
+ case ptr6c:
+ free_ptr((struct ptr *) trie->data);
+ break;
+ case nothing:
+ break;
+ }
+ free_trie(trie->dir[0]);
+ free_trie(trie->dir[1]);
+ free(trie);
+}
+void free_trie_ptr (struct trie * trie) { // also frees all tries above that don't hold nothing else and would be useless to keep
+ if (!trie)
+ return;
+ if (trie->dir[2])
+ if (!trie->dir[2]->dir[0] || !trie->dir[2]->dir[1])
+ free_trie_ptr(trie->dir[2]);
+ free_trie(trie);
+}
+struct suffix {
+ char * suffix;
+ struct trie * accept; // trie structure: http://upload.šijanec.eu./d/suffix.jpg (data is irrelevant)
+ char ** ns; // first one is master
+ char * email;
+ time_t ttl;
+ time_t serial;
+ char * from; // master that sent us this suffix or NULL if I am the master
};
+void free_suffix (struct suffix * suffix) {
+ if (!suffix)
+ return;
+ free(suffix->suffix);
+ free_trie(suffix->accept);
+ char ** pcp = suffix->ns;
+ if (pcp)
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(suffix->ns);
+ free(suffix->email);
+ free(suffix->from);
+ free(suffix);
+}
struct config {
- struct * zone; // linked list TODO use https://en.wikipedia.org/wiki/Trie instead
- struct * ns; // linked list TODO use https://en.wikipedia.org/wiki/Trie instead
- void * ptrrp; // ptr root pointer for tsearch(3)
+ struct trie * trie;
+ char ** master_servers;
+ // char ** master_zones;
+ char ** slaves;
+ int poll_interval;
+ char * ptr_file;
+ void * suffixrp; // for tsearch(3)
};
-struct config config (FILE * file) {
- char line[1024];
- while (!ferror(file) && !feof(file)) {
- char * ret = fgets(line, sizeof line, file);
- if (!ret)
- break;
- char * cp = strchr(line, '/');
- int mask = -1;
- if (cp) {
- cp = '\0';
- if (cp[1] <= '9' && cp[1] >= '0')
- mask = strtol(cp+1, &cp, 10);
- else
- cp++;
- } else {
- cp = line;
- for (; strchr("0123456789abcdefABCDEF:", *cp); cp++);
- if (!*cp)
- continue;
- cp++;
+void add_accept (struct trie * trie, struct in6_addr addr, int mask) {
+ int depth = 0;
+ while (depth < mask) {
+ bool bit = !!(addr.s6_addr[depth/8] & (1 << (7-depth%8)));
+ if (!trie->dir[bit])
+ trie->dir[bit] = calloc(1, sizeof *trie);
+ trie = trie->dir[bit];
+ }
+}
+bool is_acceptable (struct trie * trie, struct in6_addr addr) {
+ int depth = 0;
+ for (;;) {
+ bool bit = !!(addr.s6_addr[depth/8] & (1 << (7-depth%8)));
+ if (!trie->dir[0] && !trie->dir[1])
+ return true;
+ if (!trie->dir[bit])
+ return false;
+ trie = trie->dir[bit];
+ }
+}
+int validate_nonnegative (cfg_t * cfg, cfg_opt_t * opt) {
+ int value = cfg_opt_getnint(opt, cfg_opt_size(opt) - 1);
+ if (value < 0) {
+ cfg_error(cfg, "integer option '%s' must be nonnegative in section '%s'", opt->name, cfg->name);
+ return -1;
+ }
+ return 0;
+}
+int validate_positive (cfg_t * cfg, cfg_opt_t * opt) {
+ int value = cfg_opt_getnint(opt, cfg_opt_size(opt) - 1);
+ if (value < 1) {
+ cfg_error(cfg, "integer option '%s' must be positive in section '%s'", opt->name, cfg->name);
+ return -1;
+ }
+ return 0;
+}
+int validate_remote (cfg_t * cfg, cfg_opt_t * opt) {
+ char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
+ char * cp = strchr(value, '/');
+ if (cp) {
+ char * cp2;
+ int port = strtol(cp+1, &cp2, 10);
+ if (*cp2) {
+ cfg_error(cfg, "remote server specification %s in %s in section %s has non-numeric characters as part of the port", value, opt->name, cfg->name);
+ return -1;
}
- struct in6_addr addr;
- switch (inet_pton(AF_INET6, line, addr.s6_addr)) {
+ if (port < 1 || port > 65535) {
+ cfg_error(cfg, "specified port %d of remote server specification %s in %s section %s is not in range 1-65535", port, value, opt->name, cfg->name);
+ return -1;
+ }
+ }
+ if (cp)
+ *cp = '\0';
+ if (strchr(value, ':')) {
+ struct in6_addr tmp;
+ switch (inet_pton(AF_INET6, value, &tmp)) {
+ case -1:
+ cfg_error(cfg, "error while parsing remote server specification %s in section %s: inet_pton(AF_INET6, \"%s\", &tmp): %s --- your libc must support IPv6", opt->name, cfg->name, value, strerror(errno));
+ if (cp)
+ *cp = '/';
+ return -1;
case 0:
- continue;
+ cfg_error(cfg, "remote server specification %s in section %s is an invalid ipv6 or v4mapped address (%s). see section AF_INET6 in `man inet_pton` for syntax.", opt->name, cfg->name, value);
+ if (cp)
+ *cp = '/';
+ return -1;
+ }
+ return 0;
+ }
+ unsigned char tmp[PACKETSZ];
+ if (res_mkquery(QUERY, value, C_IN, T_AAAA, NULL, 0, NULL, tmp, PACKETSZ) == -1) {
+ cfg_error(cfg, "hostname %s in remote server specification %s in section %s couldn't be parsed by res_mkquery", value, opt->name, cfg->name);
+ if (cp)
+ *cp = '/';
+ return -1;
+ }
+ if (cp)
+ *cp = '/';
+ return 0;
+}
+int validate_zone (cfg_t * cfg, cfg_opt_t * opt) {
+ char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
+ char * cp = strchr(value, '/');
+ if (cp) {
+ char * cp2;
+ int mask = strtol(cp+1, &cp2, 10);
+ if (*cp2) {
+ cfg_error(cfg, "zone %s in %s in section %s has non-numeric characters as part of the netmask", value, opt->name, cfg->name);
+ return -1;
+ }
+ if (mask < 0 || mask > 128) {
+ cfg_error(cfg, "specified mask %d of zone %s in %s section %s is not in range 0-128", mask, value, opt->name, cfg->name);
+ return -1;
+ }
+ if (mask % 4) {
+ cfg_error(cfg, "specified mask %d of zone %s in %s section %s is not divisible by 4", mask, value, opt->name, cfg->name);
+ return -1;
+ }
+ *cp = '\0';
+ struct in6_addr tmp;
+ switch (inet_pton(AF_INET6, value, &tmp)) {
case -1:
- perror("inet_pton");
- exit(EXIT_FAILURE);
+ cfg_error(cfg, "error while parsing zone %s in section %s: inet_pton(AF_INET6, \"%s\", &tmp): %s --- your libc must support IPv6", opt->name, cfg->name, value, strerror(errno));
+ if (cp)
+ *cp = '/';
+ return -1;
+ case 0:
+ cfg_error(cfg, "zone %s in section %s is an invalid ipv6 or v4mapped address (%s). see section AF_INET6 in `man inet_pton` for syntax.", opt->name, cfg->name, value);
+ if (cp)
+ *cp = '/';
+ return -1;
}
- line = cp;
- char * saveptr = NULL;
- cp = strtok_r(line, "\t\r\n ", &saveptr);
- if (!cp)
- continue;
- if (mask == -1) { // ptr record
- struct ;
- continue;
+ for (int i = mask; i < 128; i++)
+ if (tmp.s6_addr[i/8] & (1 << (7-i%8))) {
+ cfg_error(cfg, "zone %s in section %s has host bits set (%s/%d) (debug: %d).", opt->name, cfg->name, value, mask, i);
+ if (cp)
+ *cp = '/';
+ return -1;
+ }
+ *cp = '/';
+ return 0;
+ }
+ unsigned char tmp[PACKETSZ];
+ if (res_mkquery(QUERY, value, C_IN, T_AAAA, NULL, 0, NULL, tmp, PACKETSZ) == -1) {
+ cfg_error(cfg, "zone %s in zone specification %s in section %s couldn't be parsed by res_mkquery", value, opt->name, cfg->name);
+ return -1;
+ }
+ return 0;
+}
+int validate_fqdn (cfg_t * cfg, cfg_opt_t * opt) {
+ char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
+ unsigned char tmp[PACKETSZ];
+ if (res_mkquery(QUERY, value, C_IN, T_AAAA, NULL, 0, NULL, tmp, PACKETSZ) == -1) {
+ cfg_error(cfg, "FQDN %s in option %s in section %s couldn't be parsed by res_mkquery", value, opt->name, cfg->name);
+ return -1;
+ }
+ return 0;
+}
+int validate_email (cfg_t * cfg, cfg_opt_t * opt) {
+ char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
+ value = strdup(value);
+ char * cp = strchr(value, '@');
+ if (!cp) {
+ cfg_error(cfg, "e-mail %s in option %s in section %s does not contain the '@' sign", value, opt->name, cfg->name);
+ return -1;
+ }
+ *cp = '\0';
+ while (strchr(value, '.'))
+ strchr(value, '.')[0] = '@';
+ *cp = '.';
+ unsigned char tmp[PACKETSZ];
+ if (res_mkquery(QUERY, value, C_IN, T_AAAA, NULL, 0, NULL, tmp, PACKETSZ) == -1) {
+ cfg_error(cfg, "e-mail converted to domain name %s in option %s in section %s couldn't be parsed by res_mkquery", value, opt->name, cfg->name);
+ free(value);
+ return -1;
+ }
+ free(value);
+ return 0;
+}
+int validate_network (cfg_t * cfg, cfg_opt_t * opt) {
+ cfg_t * sec = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
+ if (!cfg_size(sec, "networks")) {
+ cfg_error(sec, "%s section does not contain any networks", opt->name);
+ return -1;
+ }
+ char * master = cfg_getstr(sec, "master");
+ if (!master) {
+ cfg_error(cfg, "%s section does not contain required option master", opt->name);
+ return -1;
+ }
+ return 0;
+}
+int validate_netspec (cfg_t * cfg, cfg_opt_t * opt) {
+ char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
+ char * cp = strchr(value, '/');
+ if (!cp) {
+ cfg_error(cfg, "network specification %s in %s in section %s must contain the '/' character", value, opt->name, cfg->name);
+ return -1;
+ }
+ char * cp2;
+ int mask = strtol(cp+1, &cp2, 10);
+ if (*cp2) {
+ cfg_error(cfg, "network specification %s in %s in section %s has non-numeric characters as part of the netmask", value, opt->name, cfg->name);
+ return -1;
+ }
+ if (mask < 0 || mask > 128) {
+ cfg_error(cfg, "specified mask %d of network specification %s in %s section %s is not in range 0-128", mask, value, opt->name, cfg->name);
+ return -1;
+ }
+ if (mask % 4) {
+ cfg_error(cfg, "specified mask %d of network specification %s in %s section %s is not divisible by 4", mask, value, opt->name, cfg->name);
+ return -1;
+ }
+ *cp = '\0';
+ struct in6_addr tmp;
+ switch (inet_pton(AF_INET6, value, &tmp)) {
+ case -1:
+ cfg_error(cfg, "error while parsing network specification %s in section %s: inet_pton(AF_INET6, \"%s\", &tmp): %s --- your libc must support IPv6", opt->name, cfg->name, value, strerror(errno));
+ *cp = '/';
+ return -1;
+ case 0:
+ cfg_error(cfg, "network specification %s in section %s is an invalid ipv6 or v4mapped address (%s). see section AF_INET6 in `man inet_pton` for syntax.", opt->name, cfg->name, value);
+ *cp = '/';
+ return -1;
+ }
+ for (int i = mask; i < 128; i++)
+ if (tmp.s6_addr[i/8] & (1 << (7-i%8))) {
+ cfg_error(cfg, "network specification %s in section %s has host bits set (%s/%d) (debug: %d).", opt->name, cfg->name, value, mask, i);
+ *cp = '/';
+ return -1;
}
+ *cp = '/';
+ return 0;
+}
+int validate_ptr (cfg_t * cfg, cfg_opt_t * opt) {
+ cfg_t * sec = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
+ char * hostname = cfg_getstr(sec, "hostname");
+ if (!hostname) {
+ cfg_error(cfg, "%s section %s does not contain required option hostname", opt->name, sec->title);
+ return -1;
+ }
+ struct in6_addr tmp;
+ switch (inet_pton(AF_INET6, sec->title, &tmp)) {
+ case -1:
+ cfg_error(cfg, "error while parsing address %s in section %s: inet_pton(AF_INET6, \"%s\", &tmp): %s --- your libc must support IPv6", opt->name, sec->name, sec->title, strerror(errno));
+ return -1;
+ case 0:
+ cfg_error(cfg, "address in section %s is an invalid ipv6 or v4mapped address (%s). see section AF_INET6 in `man inet_pton` for syntax.", sec->name, sec->title);
+ return -1;
+ }
+ return 0;
+}
+int validate_ns (cfg_t * cfg, cfg_opt_t * opt) {
+ cfg_t * sec = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
+ if (!cfg_size(sec, "networks")) {
+ cfg_error(cfg, "%s section does not contain any networks", opt->name);
+ return -1;
}
+ if (!cfg_size(sec, "ns")) {
+ cfg_error(sec, "%s section does not contain any NS records", opt->name);
+ return -1;
+ }
+ return 0;
}
-/*
-int main (int argc, char ** argv) {
- if (argc != 2) {
- fprintf(stderr, "6d configuration file checker\n"
- " usage: %s configfile\n"
- "an example configuration file can be found in the following locations:\n"
- " /etc/6d\n"
- " /usr/share/doc/6d/conf\n"
- " http://ni.šijanec.eu/sijanec/r/tree/prog/6/6d.conf\n"
- , argv[0]);
- return 1;
+int config (struct config * conf, const char * filename, FILE * output) {
+ cfg_opt_t network_opts[] = {
+ CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT), // REQUIRED at least one
+ CFG_STR_LIST("slaves", "{}", CFGF_NONE),
+ CFG_STR("admin", "6@sijanec.eu", CFGF_NONE),
+ CFG_STR("master", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_STR("suffix", NULL, CFGF_NONE),
+ CFG_INT("ttl", 420, CFGF_NONE),
+ CFG_END()
+ };
+ cfg_opt_t suffix_opts[] = {
+ CFG_STR_LIST("suffixes", NULL, CFGF_NODEFAULT), // REQUIRED at least one
+ CFG_STR_LIST("accept", "{::/0}", CFGF_NONE),
+ CFG_STR_LIST("slaves", "{}", CFGF_NONE),
+ CFG_STR("admin", "6@sijanec.eu", CFGF_NONE),
+ CFG_STR("master", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_INT("ttl", 420, CFGF_NONE),
+ CFG_END()
+ };
+ cfg_opt_t ptr_opts[] = {
+ CFG_STR("hostname", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_INT("ttl", 420, CFGF_NONE),
+ CFG_END()
+ };
+ cfg_opt_t ns_opts[] = {
+ CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT), // REQUIRED at least one
+ CFG_STR_LIST("ns", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_INT("ttl", 420, CFGF_NONE),
+ CFG_END()
+ };
+ cfg_opt_t opts[] = {
+ CFG_STR_LIST("master_servers", "{}", CFGF_NONE),
+ // CFG_STR_LIST("master_zones", "{}", CFGF_NONE),
+ CFG_INT("poll_interval", 69, CFGF_NONE),
+ CFG_STR("ptr_file", "/var/lib/cache/6/backup", CFGF_NONE),
+ CFG_STR_LIST("slaves", "{}", CFGF_NONE),
+ CFG_SEC("network", network_opts, CFGF_MULTI),
+ CFG_SEC("suffix", suffix_opts, CFGF_MULTI),
+ CFG_SEC("ptr", ptr_opts, CFGF_TITLE | CFGF_MULTI | CFGF_NO_TITLE_DUPES),
+ CFG_SEC("ns", ns_opts, CFGF_MULTI),
+ CFG_END()
+ };
+ cfg_t * cfg;
+ cfg = cfg_init(opts, CFGF_NONE);
+ cfg_set_validate_func(cfg, "poll_interval", validate_nonnegative);
+ cfg_set_validate_func(cfg, "network|ttl", validate_positive);
+ cfg_set_validate_func(cfg, "suffix|ttl", validate_positive);
+ cfg_set_validate_func(cfg, "ptr|ttl", validate_positive);
+ cfg_set_validate_func(cfg, "ns|ttl", validate_positive);
+ cfg_set_validate_func(cfg, "master_servers", validate_remote);
+ cfg_set_validate_func(cfg, "slaves", validate_remote);
+ // cfg_set_validate_func(cfg, "master_zones", validate_zone);
+ cfg_set_validate_func(cfg, "network|slaves", validate_fqdn);
+ cfg_set_validate_func(cfg, "suffix|slaves", validate_fqdn);
+ cfg_set_validate_func(cfg, "ptr|hostname", validate_fqdn);
+ cfg_set_validate_func(cfg, "ns|ns", validate_fqdn);
+ cfg_set_validate_func(cfg, "suffix|suffixes", validate_fqdn);
+ cfg_set_validate_func(cfg, "suffix|admin", validate_email);
+ cfg_set_validate_func(cfg, "network|admin", validate_email);
+ cfg_set_validate_func(cfg, "network|networks", validate_netspec);
+ cfg_set_validate_func(cfg, "suffix|accept", validate_netspec);
+ cfg_set_validate_func(cfg, "ns|networks", validate_netspec);
+ cfg_set_validate_func(cfg, "network", validate_network);
+ cfg_set_validate_func(cfg, "ptr", validate_ptr);
+ cfg_set_validate_func(cfg, "ns", validate_ns);
+ switch (cfg_parse(cfg, filename)) {
+ case CFG_FILE_ERROR:
+ if (output)
+ fprintf(output, "# configuration file '%s' could not be read: %s\n", filename, strerror(errno));
+ return 1;
+ case CFG_PARSE_ERROR:
+ fprintf(output, "# configuration file '%s' could not be parsed\n", filename);
+ return 2;
+ }
+ if (conf->master_servers) {
+ char ** pcp = conf->master_servers;
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(conf->master_servers);
+ }
+ conf->master_servers = calloc(cfg_size(cfg, "master_servers")+1, sizeof *conf->master_servers);
+ for (size_t i = 0; i < cfg_size(cfg, "master_servers"); i++)
+ conf->master_servers[i] = strdup(cfg_getnstr(cfg, "master_servers", i));
+ /* if (conf->master_zones) {
+ char ** pcp = conf->master_zones;
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(conf->master_zones);
+ }
+ conf->master_zones = calloc(cfg_size(cfg, "master_zones")+1, sizeof *conf->master_zones);
+ for (size_t i = 0; i < cfg_size(cfg, "master_zones"); i++)
+ conf->master_zones[i] = strdup(cfg_getnstr(cfg, "master_zones", i)); */
+ conf->poll_interval = cfg_getint(cfg, "poll_interval");
+ free(conf->ptr_file);
+ conf->ptr_file = strdup(cfg_getstr(cfg, "ptr_file"));
+ if (conf->slaves) {
+ char ** pcp = conf->slaves;
+ for (; *pcp; pcp++)
+ free(*pcp);
+ free(conf->slaves);
+ }
+ conf->slaves = calloc(cfg_size(cfg, "slaves")+1, sizeof *conf->slaves);
+ for (size_t i = 0; i < cfg_size(cfg, "slaves"); i++)
+ conf->slaves[i] = strdup(cfg_getnstr(cfg, "slaves", i));
+ for (size_t i = 0; i < cfg_size(cfg, "suffix"); i++) {
+ cfg_t * cfg_suffix = cfg_getnsec(cfg, "suffix", i);
+ for (size_t j = 0; j < cfg_size(cfg_suffix, "suffixes"); j++) {
+
+ }
+ }
+ if (!output)
+ return 0;
+ fprintf(output, "master_servers = {");
+ char ** pcp = conf->master_servers;
+ while (*pcp) {
+ fprintf(output, "\"%s\"", *pcp);
+ if (*++pcp)
+ fprintf(output, ", ");
+ }
+ /* fprintf(output, "}\nmaster_zones = {");
+ pcp = conf->master_zones;
+ while (*pcp) {
+ fprintf(output, "\"%s\"", *pcp);
+ if (*++pcp)
+ fprintf(output, ", ");
+ } */
+ fprintf(output, "}\npoll_interval = %d\nptr_file = \"%s\"\nslaves = {", conf->poll_interval, conf->ptr_file);
+ pcp = conf->slaves;
+ while (*pcp) {
+ fprintf(output, "\"%s\"", *pcp);
+ if (*++pcp)
+ fprintf(output, ", ");
}
- config_file();
+ fprintf(output, "}\n");
+ return 0;
}
-*/