]> granicus.if.org Git - pgbouncer/commitdiff
Use <usual/cfparser.h> for config parsing.
authorMarko Kreen <markokr@gmail.com>
Mon, 22 Nov 2010 22:47:17 +0000 (00:47 +0200)
committerMarko Kreen <markokr@gmail.com>
Mon, 22 Nov 2010 22:47:17 +0000 (00:47 +0200)
Need to use cfparser defalt values for strings,
as it wants all non-NULL string to be allocated.

So move all defaults to cfparser values.

include/bouncer.h
include/loader.h
lib
src/admin.c
src/loader.c
src/main.c
src/objects.c

index 5d2727cd78b9927dce0080f046ce69dc58c6bce4..a17aff510b1c19cf6ff19fd41e66c3ff1d9d804a 100644 (file)
@@ -371,8 +371,6 @@ extern int cf_log_connections;
 extern int cf_log_disconnections;
 extern int cf_log_pooler_errors;
 
-extern ConfElem bouncer_params[];
-
 extern usec_t g_suspend_start;
 
 extern struct DNSContext *adns;
@@ -394,6 +392,10 @@ first_socket(struct StatList *slist)
        return container_of(slist->head.next, PgSocket, head);
 }
 
-void load_config(bool reload);
+void load_config(void);
+
 
+bool set_config_param(const char *key, const char *val);
+void config_for_each(void (*param_cb)(void *arg, const char *name, const char *val, bool reloadable),
+                    void *arg);
 
index 5eea1f004574206304aa20eedceb5e13f715d6e0..1400b61a7f938d70b8420d16981072ccf50e13fb 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* configuration parsing */
-#define CF_INT         {cf_get_int, cf_set_int}
-#define CF_STR         {cf_get_str, cf_set_str}
-#define CF_TIME                {cf_get_time, cf_set_time}
-
-#define CF_SECT_VARS   1       /* senction contains pre-defined key-var pairs */
-#define CF_SECT_DATA   2       /* key-val pairs are data */
-
-typedef struct ConfElem ConfElem;
-
-/* callback for CF_SECT_DATA loading */
-typedef void (*conf_data_callback_fn)(char *key, char *value);
-
-typedef const char * (*conf_var_get_fn)(ConfElem *elem);
-typedef bool (*conf_var_set_fn)(ConfElem *elem, const char *value, PgSocket *console) _MUSTCHECK;
-
-typedef struct {
-       conf_var_get_fn fn_get;
-       conf_var_set_fn fn_set;
-} ConfAccess;
-
-struct ConfElem {
-       const char *name;
-       bool reloadable;
-       ConfAccess io;
-       void *dst;
-       bool allocated;
-};
-
-typedef struct ConfSection {
-       const char *name;
-       ConfElem *elem_list;
-       conf_data_callback_fn data_fn;
-} ConfSection;
-
-bool iniparser(const char *fn, ConfSection *sect_list, bool reload)  _MUSTCHECK;
-
-const char * cf_get_int(ConfElem *elem);
-bool cf_set_int(ConfElem *elem, const char *value, PgSocket *console);
-
-const char * cf_get_time(ConfElem *elem);
-bool cf_set_time(ConfElem *elem, const char *value, PgSocket *console);
-
-const char *cf_get_str(ConfElem *elem);
-bool cf_set_str(ConfElem *elem, const char *value, PgSocket *console);
-
-const char *conf_to_text(ConfElem *elem);
-bool set_config_param(ConfElem *elem_list, const char *key, const char *val, bool reload, PgSocket *console) /* _MUSTCHECK */;
-
 /* connstring parsing */
-void parse_database(char *name, char *connstr);
+bool parse_database(void *base, const char *name, const char *connstr);
 
 /* user file parsing */
 bool load_auth_file(const char *fn)  /* _MUSTCHECK */;
diff --git a/lib b/lib
index 6ab8fc19041727d8d24427f2777263d30948c3dd..e67d8210bfe4ec342654160e98a7ae33d5d31257 160000 (submodule)
--- a/lib
+++ b/lib
@@ -1 +1 @@
-Subproject commit 6ab8fc19041727d8d24427f2777263d30948c3dd
+Subproject commit e67d8210bfe4ec342654160e98a7ae33d5d31257
index fd90ed9cd11e77ea95a46f153a228ac22ffc9bfe..2296095c7fa4bca6c10abc78ba9db637065ec4d9 100644 (file)
@@ -215,12 +215,14 @@ static bool fake_set(PgSocket *admin, const char *key, const char *val)
 static bool admin_set(PgSocket *admin, const char *key, const char *val)
 {
        char tmp[512];
+       bool ok;
 
        if (fake_set(admin, key, val))
                return true;
 
        if (admin->admin_user) {
-               if (set_config_param(bouncer_params, key, val, true, admin)) {
+               ok = set_config_param(key, val);
+               if (ok) {
                        snprintf(tmp, sizeof(tmp), "SET %s=%s", key, val);
                        return admin_ready(admin, tmp);
                } else {
@@ -752,11 +754,16 @@ static bool admin_show_mem(PgSocket *admin, const char *arg)
        return true;
 }
 
+static void show_one_param(void *arg, const char *name, const char *val, bool reloadable)
+{
+       PktBuf *buf = arg;
+       pktbuf_write_DataRow(buf, "sss", name, val,
+                            reloadable ? "yes" : "no");
+}
+
 /* Command: SHOW CONFIG */
 static bool admin_show_config(PgSocket *admin, const char *arg)
 {
-       ConfElem *cf;
-       int i = 0;
        PktBuf *buf;
 
        buf = pktbuf_dynamic(256);
@@ -766,16 +773,11 @@ static bool admin_show_config(PgSocket *admin, const char *arg)
        }
 
        pktbuf_write_RowDescription(buf, "sss", "key", "value", "changeable");
-       while (1) {
-               cf = &bouncer_params[i++];
-               if (!cf->name)
-                       break;
 
-               pktbuf_write_DataRow(buf, "sss",
-                                    cf->name, conf_to_text(cf),
-                                    cf->reloadable ? "yes" : "no");
-       }
+       config_for_each(show_one_param, buf);
+
        admin_flush(admin, buf, "SHOW");
+
        return true;
 }
 
@@ -789,7 +791,7 @@ static bool admin_cmd_reload(PgSocket *admin, const char *arg)
                return admin_error(admin, "admin access needed");
 
        log_info("RELOAD command issued");
-       load_config(true);
+       load_config();
        return admin_ready(admin, "RELOAD");
 }
 
index d4d2f990ba382927aac7690e2b0e5af9ad8e624b..4af31953c9d0f04fba2cf2e098496dbafd180728 100644 (file)
@@ -156,7 +156,7 @@ static void set_connect_query(PgDatabase *db, const char *new)
                log_error("no memory, cannot assign connect_query for %s", db->name);
 }
 
-static void set_autodb(char *connstr)
+static void set_autodb(const char *connstr)
 {
        char *tmp = strdup(connstr);
        if (!tmp) {
@@ -169,7 +169,7 @@ static void set_autodb(char *connstr)
 }
 
 /* fill PgDatabase from connstr */
-void parse_database(char *name, char *connstr)
+bool parse_database(void *base, const char *name, const char *connstr)
 {
        char *p, *key, *val;
        PktBuf *msg;
@@ -178,7 +178,8 @@ void parse_database(char *name, char *connstr)
        int res_pool_size = -1;
        int dbname_ofs;
 
-       char *dbname = name;
+       char *tmp_connstr;
+       const char *dbname = name;
        char *host = NULL;
        char *port = "5432";
        char *username = NULL;
@@ -193,15 +194,19 @@ void parse_database(char *name, char *connstr)
 
        if (strcmp(name, "*") == 0) {
                set_autodb(connstr);
-               return;
+               return true;
        }
 
-       p = connstr;
+       tmp_connstr = strdup(connstr);
+       if (!tmp_connstr)
+               return false;
+
+       p = tmp_connstr;
        while (*p) {
                p = cstr_get_pair(p, &key, &val);
                if (p == NULL) {
                        log_error("%s: syntax error in connstring", name);
-                       return;
+                       goto fail;
                } else if (!key[0])
                        break;
 
@@ -232,7 +237,7 @@ void parse_database(char *name, char *connstr)
                else {
                        log_error("skipping database %s because"
                                  " of unknown parameter in connstring: %s", name, key);
-                       return;
+                       goto fail;
                }
        }
 
@@ -241,13 +246,13 @@ void parse_database(char *name, char *connstr)
        if (v_port == 0) {
                log_error("skipping database %s because"
                          " of bad port: %s", name, port);
-               return;
+               goto fail;
        }
 
        db = add_database(name);
        if (!db) {
                log_error("cannot create database, no memory?");
-               return;
+               goto fail;
        }
 
        /* host= */
@@ -255,7 +260,7 @@ void parse_database(char *name, char *connstr)
                host = strdup(host);
                if (!host) {
                        log_error("failed to allocate host=");
-                       return;
+                       goto fail;
                }
        }
        if (!host) {
@@ -263,7 +268,7 @@ void parse_database(char *name, char *connstr)
                if (!*cf_unix_socket_dir) {
                        log_error("skipping database %s because"
                                " unix socket not configured", name);
-                       return;
+                       goto fail;
                }
        }
 
@@ -355,6 +360,11 @@ void parse_database(char *name, char *connstr)
 
        /* remember dbname */
        db->dbname = (char *)msg->buf + dbname_ofs;
+       free(tmp_connstr);
+       return true;
+fail:
+       free(tmp_connstr);
+       return true;
 }
 
 /*
@@ -513,247 +523,3 @@ bool load_auth_file(const char *fn)
        return true;
 }
 
-/*
- * Config parameter handling.
- */
-
-bool cf_set_int(ConfElem *elem, const char *val, PgSocket *console)
-{
-       int *int_p = elem->dst;
-       if (*val < '0' || *val > '9') {
-               admin_error(console, "bad value: %s", val);
-               return false;
-       }
-       *int_p = atoi(val);
-       return true;
-}
-
-const char *cf_get_int(ConfElem *elem)
-{
-       static char numbuf[32];
-       int val;
-
-       val = *(int *)elem->dst;
-       snprintf(numbuf, sizeof(numbuf), "%d", val);
-       return numbuf;
-}
-bool cf_set_time(ConfElem *elem, const char *val, PgSocket *console)
-{
-       usec_t *time_p = elem->dst;
-       if (*val < '0' || *val > '9') {
-               admin_error(console, "bad value: %s", val);
-               return false;
-       }
-       *time_p = USEC * (usec_t)atoi(val);
-       return true;
-}
-
-const char *cf_get_time(ConfElem *elem)
-{
-       static char numbuf[32];
-       usec_t val;
-
-       val = *(usec_t *)elem->dst;
-       snprintf(numbuf, sizeof(numbuf), "%d", (int)(val / USEC));
-       return numbuf;
-}
-
-bool cf_set_str(ConfElem *elem, const char *val, PgSocket *console)
-{
-       char **str_p = elem->dst;
-       char *tmp;
-
-       /* don't touch if not changed */
-       if (*str_p && strcmp(*str_p, val) == 0)
-               return true;
-
-       /* if dynamically allocated, free it */
-       if (elem->allocated)
-               free(*str_p);
-
-       tmp = strdup(val);
-       if (!tmp)
-               return false;
-
-       *str_p = tmp;
-       elem->allocated = true;
-       return true;
-}
-
-const char * cf_get_str(ConfElem *elem)
-{
-       return *(char **)elem->dst;
-}
-
-bool set_config_param(ConfElem *elem_list,
-                     const char *key, const char *val,
-                     bool reload, PgSocket *console)
-{
-       ConfElem *desc;
-
-       for (desc = elem_list; desc->name; desc++) {
-               if (strcasecmp(key, desc->name) != 0)
-                       continue;
-       
-               /* if reload not allowed, skip it */
-               if (reload && !desc->reloadable) {
-                       if (console)
-                               admin_error(console,
-                                       "%s cannot be changed online", key);
-                       return false;
-               }
-
-               /* got config, parse it */
-               return desc->io.fn_set(desc, val, console);
-       }
-       return false;
-}
-
-static void map_config(ConfSection *sect, char *key, char *val, bool reload)
-{
-       if (sect == NULL)
-               return;
-
-       if (sect->data_fn)
-               sect->data_fn(key, val);
-       else
-               set_config_param(sect->elem_list, key, val, reload, NULL);
-}
-
-const char *conf_to_text(ConfElem *elem)
-{
-       return elem->io.fn_get(elem);
-}
-
-static ConfSection *find_section(ConfSection *sect, const char *name)
-{
-       for (; sect->name; sect++)
-               if (strcasecmp(sect->name, name) == 0)
-                       return sect;
-       log_warning("unknown section in config: %s", name);
-       return NULL;
-}
-
-/*
- * INI file parser.
- */
-
-static int count_lines(const char *s, const char *end)
-{
-       int lineno = 1;
-       for (; s < end; s++) {
-               if (*s == '\n')
-                       lineno++;
-       }
-       return lineno;
-}
-
-static bool unquote_ident(char **src_p, char *dst, int dstlen)
-{
-       char *src = *src_p;
-       char *end = dst + dstlen;
-       if (*src++ != '"')
-               return false;
-       while (*src && dst < end) {
-               if (src[0] == '"') {
-                       if (src[1] != '"')
-                               break;
-                       src++;
-               }
-               *dst++ = *src++;
-       }
-       if (*src != '"' || dst >= end)
-               return false;
-       *dst = 0;
-       *src_p = src + 1;
-       return true;
-}
-
-bool iniparser(const char *fn, ConfSection *sect_list, bool reload)
-{
-       char *buf;
-       char *p, *key, *val;
-       int klen, vlen;
-       ConfSection *cur_section = NULL;
-       char keybuf[MAX_DBNAME*2];
-
-       buf = load_file(fn, NULL);
-       if (buf == NULL) {
-               if (!reload)
-                       exit(1);
-               else
-                       return false;
-       }
-
-       p = buf;
-       while (*p) {
-               /* space at the start of line - including empty lines */
-               while (*p && isspace(*p)) p++;
-
-               /* skip comment lines */
-               if (*p == '#' || *p == ';') {
-                       while (*p && *p != '\n') p++;
-                       continue;
-               }
-               /* got new section */
-               if (*p == '[') {
-                       key = ++p;
-                       while (*p && *p != ']' && *p != '\n') p++;
-                       if (*p != ']')
-                               goto syntax_error;
-                       *p++ = 0;
-
-                       cur_section = find_section(sect_list, key);
-                       continue;
-               }
-
-               /* done? */
-               if (*p == 0) break;
-
-               /* read key val */
-               if (*p == '"') {
-                       if (!unquote_ident(&p, keybuf, sizeof(keybuf)))
-                               goto syntax_error;
-                       key = keybuf;
-                       klen = strlen(keybuf);
-               } else {
-                       key = p;
-                       while (*p && (isalnum(*p) || strchr("_.-*", *p))) p++;
-                       klen = p - key;
-               }
-
-               /* expect '=', skip it */
-               while (*p && (*p == ' ' || *p == '\t')) p++;
-               if (*p != '=') {
-                       goto syntax_error;
-               } else
-                       p++;
-               while (*p && (*p == ' ' || *p == '\t')) p++;
-
-               /* now read value */
-               val = p;
-               while (*p && (*p != '\n'))
-                       p++;
-               vlen = p - val;
-               /* eat space at end */
-               while (vlen > 0 && isspace(val[vlen - 1]))
-                       vlen--;
-
-               /* skip junk */
-               while (*p && isspace(*p)) p++;
-
-               /* our buf is r/w, so take it easy */
-               key[klen] = 0;
-               val[vlen] = 0;
-               map_config(cur_section, key, val, reload);
-       }
-
-       free(buf);
-       return true;
-
-syntax_error:
-       log_error("syntax error in configuration (%s:%d), stopping loading", fn, count_lines(buf, p));
-       free(buf);
-       return true;
-}
-
index 1c1fa8611e90d075648006342dc7ff3602be98f0..ee9436dd6be2c25256874c5d07484202ff93ed44 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <usual/signal.h>
 #include <usual/err.h>
+#include <usual/cfparser.h>
 
 #include <getopt.h>
 
 #include <sys/resource.h>
 #endif
 
-static bool set_mode(ConfElem *elem, const char *val, PgSocket *console);
-static const char *get_mode(ConfElem *elem);
-static bool set_auth(ConfElem *elem, const char *val, PgSocket *console);
-static const char *get_auth(ConfElem *elem);
-static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console);
-
 static const char usage_str[] =
 "Usage: %s [OPTION]... config.ini\n"
 "  -d, --daemon           Run in background (as a daemon)\n"
@@ -60,226 +55,212 @@ struct DNSContext *adns;
  * configuration storage
  */
 
-int cf_daemon = 0;
+int cf_daemon;
 int cf_pause_mode = P_NONE;
-int cf_shutdown = 0; /* 1 - wait for queries to finish, 2 - shutdown immediately */
-int cf_reboot = 0;
-static char *cf_username = "";
-char *cf_config_file = "";
-
-char *cf_listen_addr = NULL;
-int cf_listen_port = 6432;
-int cf_listen_backlog = 128;
-#ifndef WIN32
-char *cf_unix_socket_dir = "/tmp";
-#else
-char *cf_unix_socket_dir = "";
-#endif
+int cf_shutdown; /* 1 - wait for queries to finish, 2 - shutdown immediately */
+int cf_reboot;
+static char *cf_username;
+char *cf_config_file;
+
+char *cf_listen_addr;
+int cf_listen_port;
+int cf_listen_backlog;
+char *cf_unix_socket_dir;
 
 int cf_pool_mode = POOL_SESSION;
 
 /* sbuf config */
-int cf_sbuf_len = 2048;
-int cf_sbuf_loopcnt = 5;
-int cf_tcp_socket_buffer = 0;
+int cf_sbuf_len;
+int cf_sbuf_loopcnt;
+int cf_tcp_socket_buffer;
 #if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
 int cf_tcp_defer_accept = 1;
 #else
 int cf_tcp_defer_accept = 0;
 #endif
-int cf_tcp_keepalive = 0;
-int cf_tcp_keepcnt = 0;
-int cf_tcp_keepidle = 0;
-int cf_tcp_keepintvl = 0;
+int cf_tcp_keepalive;
+int cf_tcp_keepcnt;
+int cf_tcp_keepidle;
+int cf_tcp_keepintvl;
 
 int cf_auth_type = AUTH_MD5;
-char *cf_auth_file = "unconfigured_file";
+char *cf_auth_file;
 
-int cf_max_client_conn = 100;
-int cf_default_pool_size = 20;
-int cf_res_pool_size = 0;
-usec_t cf_res_pool_timeout = 5;
+int cf_max_client_conn;
+int cf_default_pool_size;
+int cf_res_pool_size;
+usec_t cf_res_pool_timeout;
 
-char *cf_server_reset_query = "";
-char *cf_server_check_query = "select 1";
-usec_t cf_server_check_delay = 30 * USEC;
-int cf_server_round_robin = 0;
-int cf_disable_pqexec = 0;
-usec_t cf_dns_max_ttl = 15 * USEC;
+char *cf_server_reset_query;
+char *cf_server_check_query;
+usec_t cf_server_check_delay;
+int cf_server_round_robin;
+int cf_disable_pqexec;
+usec_t cf_dns_max_ttl;
 
-char *cf_ignore_startup_params = "";
+char *cf_ignore_startup_params;
 
-char *cf_autodb_connstr = NULL; /* here is "" different from NULL */
+char *cf_autodb_connstr; /* here is "" different from NULL */
 
-usec_t cf_autodb_idle_timeout = 3600*USEC;
+usec_t cf_autodb_idle_timeout;
 
-usec_t cf_server_lifetime = 60*60*USEC;
-usec_t cf_server_idle_timeout = 10*60*USEC;
-usec_t cf_server_connect_timeout = 15*USEC;
-usec_t cf_server_login_retry = 15*USEC;
-usec_t cf_query_timeout = 0*USEC;
-usec_t cf_query_wait_timeout = 0*USEC;
-usec_t cf_client_idle_timeout = 0*USEC;
-usec_t cf_client_login_timeout = 60*USEC;
-usec_t cf_suspend_timeout = 10*USEC;
+usec_t cf_server_lifetime;
+usec_t cf_server_idle_timeout;
+usec_t cf_server_connect_timeout;
+usec_t cf_server_login_retry;
+usec_t cf_query_timeout;
+usec_t cf_query_wait_timeout;
+usec_t cf_client_idle_timeout;
+usec_t cf_client_login_timeout;
+usec_t cf_suspend_timeout;
 
-usec_t g_suspend_start = 0;
+usec_t g_suspend_start;
 
-char *cf_pidfile = "";
-char *cf_jobname = "pgbouncer";
+char *cf_pidfile;
+char *cf_jobname;
 
-char *cf_admin_users = "";
-char *cf_stats_users = "";
-int cf_stats_period = 60;
+char *cf_admin_users;
+char *cf_stats_users;
+int cf_stats_period;
 
-int cf_log_connections = 1;
-int cf_log_disconnections = 1;
-int cf_log_pooler_errors = 1;
+int cf_log_connections;
+int cf_log_disconnections;
+int cf_log_pooler_errors;
 
 /*
  * config file description
  */
-ConfElem bouncer_params[] = {
-{"job_name",           false, CF_STR, &cf_jobname},
+
+static bool set_defer_accept(struct CfValue *cv, const char *val);
+#define DEFER_OPS {set_defer_accept, cf_get_int}
+
+static const struct CfLookup auth_type_map[] = {
+       { "any", AUTH_ANY },
+       { "trust", AUTH_TRUST },
+       { "plain", AUTH_PLAIN },
+#ifdef HAVE_CRYPT
+       { "crypt", AUTH_CRYPT },
+#endif
+       { "md5", AUTH_MD5 },
+       { NULL }
+};
+
+static const struct CfLookup pool_mode_map[] = {
+       { "session", POOL_SESSION },
+       { "transaction", POOL_TX },
+       { "statement", POOL_STMT },
+       { NULL }
+};
+
+static const struct CfKey bouncer_params [] = {
+CF_ABS("job_name", CF_STR, cf_jobname, CF_NO_RELOAD, "pgbouncer"),
 #ifdef WIN32
-{"service_name",       false, CF_STR, &cf_jobname}, /* alias for job_name */
+CF_ABS("service_name", CF_STR, cf_jobname, CF_NO_RELOAD, NULL), /* alias for job_name */
 #endif
-{"conffile",           true, CF_STR, &cf_config_file},
-{"logfile",            true, CF_STR, &cf_logfile},
-{"pidfile",            false, CF_STR, &cf_pidfile},
-{"listen_addr",                false, CF_STR, &cf_listen_addr},
-{"listen_port",                false, CF_INT, &cf_listen_port},
-{"listen_backlog",     false, CF_INT, &cf_listen_backlog},
+CF_ABS("conffile", CF_STR, cf_config_file, 0, NULL),
+CF_ABS("logfile", CF_STR, cf_logfile, 0, ""),
+CF_ABS("pidfile", CF_STR, cf_pidfile, CF_NO_RELOAD, ""),
+CF_ABS("listen_addr", CF_STR, cf_listen_addr, CF_NO_RELOAD, ""),
+CF_ABS("listen_port", CF_INT, cf_listen_port, CF_NO_RELOAD, "6432"),
+CF_ABS("listen_backlog", CF_INT, cf_listen_backlog, CF_NO_RELOAD, "128"),
 #ifndef WIN32
-{"unix_socket_dir",    false, CF_STR, &cf_unix_socket_dir},
+CF_ABS("unix_socket_dir", CF_STR, cf_unix_socket_dir, CF_NO_RELOAD, "/tmp"),
 #endif
-{"auth_type",          true, {get_auth, set_auth}},
-{"auth_file",          true, CF_STR, &cf_auth_file},
-{"pool_mode",          true, {get_mode, set_mode}},
-{"max_client_conn",    true, CF_INT, &cf_max_client_conn},
-{"default_pool_size",  true, CF_INT, &cf_default_pool_size},
-{"reserve_pool_size",  true, CF_INT, &cf_res_pool_size},
-{"reserve_pool_timeout",true, CF_INT, &cf_res_pool_timeout},
-{"syslog",             true, CF_INT, &cf_syslog},
-{"syslog_facility",    true, CF_STR, &cf_syslog_facility},
-{"syslog_ident",       true, CF_STR, &cf_syslog_ident},
+CF_ABS("auth_type", CF_LOOKUP(auth_type_map), cf_auth_type, 0, "md5"),
+CF_ABS("auth_file", CF_STR, cf_auth_file, 0, "unconfigured_file"),
+CF_ABS("pool_mode", CF_LOOKUP(pool_mode_map), cf_pool_mode, 0, "session"),
+CF_ABS("max_client_conn", CF_INT, cf_max_client_conn, 0, "100"),
+CF_ABS("default_pool_size", CF_INT, cf_default_pool_size, 0, "20"),
+CF_ABS("reserve_pool_size", CF_INT, cf_res_pool_size, 0, "0"),
+CF_ABS("reserve_pool_timeout", CF_INT, cf_res_pool_timeout, 0, "5"),
+CF_ABS("syslog", CF_INT, cf_syslog, 0, "0"),
+CF_ABS("syslog_facility", CF_STR, cf_syslog_facility, 0, "daemon"),
+CF_ABS("syslog_ident", CF_STR, cf_syslog_ident, 0, "pgbouncer"),
 #ifndef WIN32
-{"user",               false, CF_STR, &cf_username},
+CF_ABS("user", CF_STR, cf_username, CF_NO_RELOAD, NULL),
 #endif
 
-{"autodb_idle_timeout",        true, CF_TIME, &cf_autodb_idle_timeout},
-
-{"server_reset_query", true, CF_STR, &cf_server_reset_query},
-{"server_check_query", true, CF_STR, &cf_server_check_query},
-{"server_check_delay", true, CF_TIME, &cf_server_check_delay},
-{"query_timeout",      true, CF_TIME, &cf_query_timeout},
-{"query_wait_timeout", true, CF_TIME, &cf_query_wait_timeout},
-{"client_idle_timeout",        true, CF_TIME, &cf_client_idle_timeout},
-{"client_login_timeout",true, CF_TIME, &cf_client_login_timeout},
-{"server_lifetime",    true, CF_TIME, &cf_server_lifetime},
-{"server_idle_timeout",        true, CF_TIME, &cf_server_idle_timeout},
-{"server_connect_timeout",true, CF_TIME, &cf_server_connect_timeout},
-{"server_login_retry", true, CF_TIME, &cf_server_login_retry},
-{"server_round_robin", true, CF_INT, &cf_server_round_robin},
-{"suspend_timeout",    true, CF_TIME, &cf_suspend_timeout},
-{"ignore_startup_parameters", true, CF_STR, &cf_ignore_startup_params},
-{"disable_pqexec",     false, CF_INT, &cf_disable_pqexec},
-{"dns_max_ttl",                true, CF_TIME, &cf_dns_max_ttl},
-
-{"pkt_buf",            false, CF_INT, &cf_sbuf_len},
-{"sbuf_loopcnt",       true, CF_INT, &cf_sbuf_loopcnt},
-{"tcp_defer_accept",   true, {cf_get_int, set_defer_accept}, &cf_tcp_defer_accept},
-{"tcp_socket_buffer",  true, CF_INT, &cf_tcp_socket_buffer},
-{"tcp_keepalive",      true, CF_INT, &cf_tcp_keepalive},
-{"tcp_keepcnt",                true, CF_INT, &cf_tcp_keepcnt},
-{"tcp_keepidle",       true, CF_INT, &cf_tcp_keepidle},
-{"tcp_keepintvl",      true, CF_INT, &cf_tcp_keepintvl},
-{"verbose",            true, CF_INT, &cf_verbose},
-{"admin_users",                true, CF_STR, &cf_admin_users},
-{"stats_users",                true, CF_STR, &cf_stats_users},
-{"stats_period",       true, CF_INT, &cf_stats_period},
-{"log_connections",    true, CF_INT, &cf_log_connections},
-{"log_disconnections", true, CF_INT, &cf_log_disconnections},
-{"log_pooler_errors",  true, CF_INT, &cf_log_pooler_errors},
-{NULL},
-};
-
-static ConfSection bouncer_config [] = {
-{"pgbouncer", bouncer_params, NULL},
-{"databases", NULL, parse_database},
+CF_ABS("autodb_idle_timeout", CF_TIME_USEC, cf_autodb_idle_timeout, 0, "3600"),
+
+CF_ABS("server_reset_query", CF_STR, cf_server_reset_query, 0, ""),
+CF_ABS("server_check_query", CF_STR, cf_server_check_query, 0, "select 1"),
+CF_ABS("server_check_delay", CF_TIME_USEC, cf_server_check_delay, 0, "30"),
+CF_ABS("query_timeout", CF_TIME_USEC, cf_query_timeout, 0, "0"),
+CF_ABS("query_wait_timeout", CF_TIME_USEC, cf_query_wait_timeout, 0, "0"),
+CF_ABS("client_idle_timeout", CF_TIME_USEC, cf_client_idle_timeout, 0, "0"),
+CF_ABS("client_login_timeout", CF_TIME_USEC, cf_client_login_timeout, 0, "60"),
+CF_ABS("server_lifetime", CF_TIME_USEC, cf_server_lifetime, 0, "3600"),
+CF_ABS("server_idle_timeout", CF_TIME_USEC, cf_server_idle_timeout, 0, "600"),
+CF_ABS("server_connect_timeout", CF_TIME_USEC, cf_server_connect_timeout, 0, "15"),
+CF_ABS("server_login_retry", CF_TIME_USEC, cf_server_login_retry, 0, "15"),
+CF_ABS("server_round_robin", CF_INT, cf_server_round_robin, 0, "0"),
+CF_ABS("suspend_timeout", CF_TIME_USEC, cf_suspend_timeout, 0, "10"),
+CF_ABS("ignore_startup_parameters", CF_STR, cf_ignore_startup_params, 0, ""),
+CF_ABS("disable_pqexec", CF_INT, cf_disable_pqexec, CF_NO_RELOAD, "0"),
+CF_ABS("dns_max_ttl", CF_TIME_USEC, cf_dns_max_ttl, 0, "15"),
+
+CF_ABS("pkt_buf", CF_INT, cf_sbuf_len, CF_NO_RELOAD, "2048"),
+CF_ABS("sbuf_loopcnt", CF_INT, cf_sbuf_loopcnt, 0, "5"),
+CF_ABS("tcp_defer_accept", DEFER_OPS, cf_tcp_defer_accept, 0, NULL),
+CF_ABS("tcp_socket_buffer", CF_INT, cf_tcp_socket_buffer, 0, "0"),
+CF_ABS("tcp_keepalive", CF_INT, cf_tcp_keepalive, 0, "0"),
+CF_ABS("tcp_keepcnt", CF_INT, cf_tcp_keepcnt, 0, "0"),
+CF_ABS("tcp_keepidle", CF_INT, cf_tcp_keepidle, 0, "0"),
+CF_ABS("tcp_keepintvl", CF_INT, cf_tcp_keepintvl, 0, "0"),
+CF_ABS("verbose", CF_INT, cf_verbose, 0, NULL),
+CF_ABS("admin_users", CF_STR, cf_admin_users, 0, ""),
+CF_ABS("stats_users", CF_STR, cf_stats_users, 0, ""),
+CF_ABS("stats_period", CF_INT, cf_stats_period, 0, "60"),
+CF_ABS("log_connections", CF_INT, cf_log_connections, 0, "1"),
+CF_ABS("log_disconnections", CF_INT, cf_log_disconnections, 0, "1"),
+CF_ABS("log_pooler_errors", CF_INT, cf_log_pooler_errors, 0, "1"),
 {NULL}
 };
 
-static const char *get_mode(ConfElem *elem)
-{
-       switch (cf_pool_mode) {
-       case POOL_STMT: return "statement";
-       case POOL_TX: return "transaction";
-       case POOL_SESSION: return "session";
-       default:
-               fatal("borken mode? should not happen");
-               return NULL;
+static const struct CfSect config_sects [] = {
+       {
+               .sect_name = "pgbouncer",
+               .key_list = bouncer_params,
+       }, {
+               .sect_name = "databases",
+               .set_key = parse_database,
+       }, {
+               .sect_name = NULL,
        }
-}
+};
 
-static bool set_mode(ConfElem *elem, const char *val, PgSocket *console)
-{
-       if (strcasecmp(val, "session") == 0)
-               cf_pool_mode = POOL_SESSION;
-       else if (strcasecmp(val, "transaction") == 0)
-               cf_pool_mode = POOL_TX;
-       else if (strcasecmp(val, "statement") == 0)
-               cf_pool_mode = POOL_STMT;
-       else {
-               admin_error(console, "bad mode: %s", val);
-               return false;
-       }
-       return true;
-}
+static struct CfContext main_config = { config_sects, };
 
-static const char *get_auth(ConfElem *elem)
+bool set_config_param(const char *key, const char *val)
 {
-       switch (cf_auth_type) {
-       case AUTH_ANY: return "any";
-       case AUTH_TRUST: return "trust";
-       case AUTH_PLAIN: return "plain";
-       case AUTH_CRYPT: return "crypt";
-       case AUTH_MD5: return "md5";
-       default:
-               fatal("borken auth? should not happen");
-               return NULL;
-       }
+       return cf_set(&main_config, "pgbouncer", key, val);
 }
 
-static bool set_auth(ConfElem *elem, const char *val, PgSocket *console)
+void config_for_each(void (*param_cb)(void *arg, const char *name, const char *val, bool reloadable),
+                    void *arg)
 {
-       if (strcasecmp(val, "any") == 0)
-               cf_auth_type = AUTH_ANY;
-       else if (strcasecmp(val, "trust") == 0)
-               cf_auth_type = AUTH_TRUST;
-       else if (strcasecmp(val, "plain") == 0)
-               cf_auth_type = AUTH_PLAIN;
-#ifdef HAVE_CRYPT
-       else if (strcasecmp(val, "crypt") == 0)
-               cf_auth_type = AUTH_CRYPT;
-#endif
-       else if (strcasecmp(val, "md5") == 0)
-               cf_auth_type = AUTH_MD5;
-       else {
-               admin_error(console, "bad auth type: %s", val);
-               return false;
+       const struct CfKey *k = bouncer_params;
+       char buf[256];
+       bool reloadable;
+       const char *val;
+       int ro = CF_NO_RELOAD | CF_READONLY;
+
+       for (; k->key_name; k++) {
+               val = cf_get(&main_config, "pgbouncer", k->key_name, buf, sizeof(buf));
+               reloadable = (k->flags & ro) == 0;
+               param_cb(arg, k->key_name, val, reloadable);
        }
-       return true;
 }
 
-static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console)
+static bool set_defer_accept(struct CfValue *cv, const char *val)
 {
+       int *p = cv->value_p;
        bool ok;
-       int oldval = cf_tcp_defer_accept;
-       ok = cf_set_int(elem, val, console);
-       if (ok && !!oldval != !!cf_tcp_defer_accept)
-               pooler_tune_accept(cf_tcp_defer_accept);
-       return true;
+       int oldval = *p;
+       ok = cf_set_int(cv, val);
+       if (ok && !!oldval != !!*p)
+               pooler_tune_accept(*p);
+       return ok;
 }
 
 static void set_dbs_dead(bool flag)
@@ -298,14 +279,14 @@ static void set_dbs_dead(bool flag)
 }
 
 /* config loading, tries to be tolerant to errors */
-void load_config(bool reload)
+void load_config(void)
 {
        bool ok;
 
        set_dbs_dead(true);
 
        /* actual loading */
-       ok = iniparser(cf_config_file, bouncer_config, reload);
+       ok = cf_load_file(&main_config, cf_config_file);
        if (ok) {
                /* load users if needed */
                if (cf_auth_type >= AUTH_TRUST)
@@ -319,7 +300,7 @@ void load_config(bool reload)
        }
 
        /* reopen logfile */
-       if (reload)
+       if (main_config.loaded)
                reset_logging();
 }
 
@@ -392,7 +373,7 @@ static void handle_sigusr2(int sock, short flags, void *arg)
 static void handle_sighup(int sock, short flags, void *arg)
 {
        log_info("Got SIGHUP re-reading config");
-       load_config(true);
+       load_config();
 }
 #endif
 
@@ -715,19 +696,23 @@ int main(int argc, char *argv[])
                fprintf(stderr, "Need config file.  See pgbouncer -h for usage.\n");
                exit(1);
        }
-       cf_config_file = argv[optind];
+       cf_config_file = xstrdup(argv[optind]);
 
        init_objects();
-       load_config(false);
+       load_config();
+       main_config.loaded = true;
        init_caches();
        logging_prefix_cb = log_socket_prefix;
 
        /* prefer cmdline over config for username */
-       if (arg_username)
-               cf_username = arg_username;
+       if (arg_username) {
+               if (cf_username)
+                       free(cf_username);
+               cf_username = xstrdup(arg_username);
+       }
 
        /* switch user is needed */
-       if (*cf_username)
+       if (cf_username && *cf_username)
                change_user(cf_username);
 
        /* disallow running as root */
index 69b5dd429a7b4f35b9718008b9b2e77837ca3ed6..f357c8897bf5c0aec76e63eb88c83941dcfea7cd 100644 (file)
@@ -325,7 +325,7 @@ PgDatabase *register_auto_database(const char *name)
        if (!cs)
                return NULL;
        memcpy(cs, cf_autodb_connstr, len + 1);
-       parse_database((char*)name, cs);
+       parse_database(NULL, (char*)name, cs);
        free(cs);
 
        db = find_database(name);