From: Marko Kreen Date: Mon, 22 Nov 2010 22:47:17 +0000 (+0200) Subject: Use for config parsing. X-Git-Tag: pgbouncer_1_4_rc3~5 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9d20155f074d24809975301a943615596a3bd9bd;p=pgbouncer Use for config parsing. 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. --- diff --git a/include/bouncer.h b/include/bouncer.h index 5d2727c..a17aff5 100644 --- a/include/bouncer.h +++ b/include/bouncer.h @@ -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); diff --git a/include/loader.h b/include/loader.h index 5eea1f0..1400b61 100644 --- a/include/loader.h +++ b/include/loader.h @@ -16,57 +16,8 @@ * 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 6ab8fc1..e67d821 160000 --- a/lib +++ b/lib @@ -1 +1 @@ -Subproject commit 6ab8fc19041727d8d24427f2777263d30948c3dd +Subproject commit e67d8210bfe4ec342654160e98a7ae33d5d31257 diff --git a/src/admin.c b/src/admin.c index fd90ed9..2296095 100644 --- a/src/admin.c +++ b/src/admin.c @@ -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"); } diff --git a/src/loader.c b/src/loader.c index d4d2f99..4af3195 100644 --- a/src/loader.c +++ b/src/loader.c @@ -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; -} - diff --git a/src/main.c b/src/main.c index 1c1fa86..ee9436d 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include #include +#include #include @@ -31,12 +32,6 @@ #include #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 */ diff --git a/src/objects.c b/src/objects.c index 69b5dd4..f357c88 100644 --- a/src/objects.c +++ b/src/objects.c @@ -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);