static PyObject * psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs) { char *err = NULL; PQconninfoOption *options = NULL; PyObject *res = NULL, *dsn; static char *kwlist[] = {"dsn", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) { return NULL; } Py_INCREF(dsn); /* for ensure_bytes */ if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; } options = PQconninfoParse(Bytes_AS_STRING(dsn), &err); if (options == NULL) { if (err != NULL) { PyErr_Format(ProgrammingError, "invalid dsn: %s", err); PQfreemem(err); } else { PyErr_SetString(OperationalError, "PQconninfoParse() failed"); } goto exit; } res = psycopg_dict_from_conninfo_options(options, /* include_password = */ 1); exit: PQconninfoFree(options); /* safe on null */ Py_XDECREF(dsn); return res; }
inline PGconn* pg_connect(std::string const& connection) { PGconn* conn; if ( ! connection.size() ) throw pdal_error("unable to connect to database, no connection " "string was given!"); /* Validate the connection string and get verbose error (?) */ #ifdef PQconninfoParse char *errstr; PQconninfoOption *connOptions = PQconninfoParse(connection.c_str(), &errstr); if ( ! connOptions ) { throw pdal_error(errstr); } #endif /* connect to database */ conn = PQconnectdb(connection.c_str()); if ( PQstatus(conn) != CONNECTION_OK ) { throw pdal_error(PQerrorMessage(conn)); } return conn; }
/* Establishes two network connections to a Postgres server: one for SQL, and one * for replication. context->conninfo contains the connection string or URL to connect * to, and context->app_name is the client name (which appears, for example, in * pg_stat_activity). Returns 0 on success. */ int client_connect(client_context_t context) { if (!context->conninfo || context->conninfo[0] == '\0') { client_error(context, "conninfo must be set in client context"); return EINVAL; } if (!context->app_name || context->app_name[0] == '\0') { client_error(context, "app_name must be set in client context"); return EINVAL; } context->sql_conn = PQconnectdb(context->conninfo); if (PQstatus(context->sql_conn) != CONNECTION_OK) { client_error(context, "Connection to database failed: %s", PQerrorMessage(context->sql_conn)); return EIO; } /* Parse the connection string into key-value pairs */ char *error = NULL; PQconninfoOption *parsed_opts = PQconninfoParse(context->conninfo, &error); if (!parsed_opts) { client_error(context, "Replication connection info: %s", error); PQfreemem(error); return EIO; } /* Copy the key-value pairs into a new structure with added replication options */ PQconninfoOption *option; int optcount = 2; /* replication, fallback_application_name */ for (option = parsed_opts; option->keyword != NULL; option++) { if (option->val != NULL && option->val[0] != '\0') optcount++; } const char **keys = malloc((optcount + 1) * sizeof(char *)); const char **values = malloc((optcount + 1) * sizeof(char *)); int i = 0; for (option = parsed_opts; option->keyword != NULL; option++) { if (option->val != NULL && option->val[0] != '\0') { keys[i] = option->keyword; values[i] = option->val; i++; } } keys[i] = "replication"; values[i] = "database"; i++; keys[i] = "fallback_application_name"; values[i] = context->app_name; i++; keys[i] = NULL; values[i] = NULL; int err = 0; context->repl.conn = PQconnectdbParams(keys, values, true); if (PQstatus(context->repl.conn) != CONNECTION_OK) { client_error(context, "Replication connection failed: %s", PQerrorMessage(context->repl.conn)); err = EIO; } free(keys); free(values); PQconninfoFree(parsed_opts); return err; }
static PyObject * psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs) { char *err = NULL; PQconninfoOption *options = NULL, *o; PyObject *dict = NULL, *res = NULL, *dsn; static char *kwlist[] = {"dsn", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) { return NULL; } Py_INCREF(dsn); /* for ensure_bytes */ if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; } options = PQconninfoParse(Bytes_AS_STRING(dsn), &err); if (options == NULL) { if (err != NULL) { PyErr_Format(ProgrammingError, "error parsing the dsn: %s", err); PQfreemem(err); } else { PyErr_SetString(OperationalError, "PQconninfoParse() failed"); } goto exit; } if (!(dict = PyDict_New())) { goto exit; } for (o = options; o->keyword != NULL; o++) { if (o->val != NULL) { PyObject *value; if (!(value = Text_FromUTF8(o->val))) { goto exit; } if (PyDict_SetItemString(dict, o->keyword, value) != 0) { Py_DECREF(value); goto exit; } Py_DECREF(value); } } /* success */ res = dict; dict = NULL; exit: PQconninfoFree(options); /* safe on null */ Py_XDECREF(dict); Py_XDECREF(dsn); return res; }
static PGconn *get_pqdb_connection(void) { persistent_users_db_t *pud = get_persistent_users_db(); PGconn *pqdbconnection = (PGconn*)pthread_getspecific(connection_key); if(pqdbconnection) { ConnStatusType status = PQstatus(pqdbconnection); if(status != CONNECTION_OK) { PQfinish(pqdbconnection); pqdbconnection = NULL; (void) pthread_setspecific(connection_key, pqdbconnection); } } if(!pqdbconnection) { char *errmsg=NULL; PQconninfoOption *co = PQconninfoParse(pud->userdb, &errmsg); if(!co) { if(errmsg) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection <%s>, connection string format error: %s\n",pud->userdb,errmsg); turn_free(errmsg,strlen(errmsg)+1); } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, unknown connection string format error\n",pud->userdb); } } else { PQconninfoFree(co); if(errmsg) turn_free(errmsg,strlen(errmsg)+1); pqdbconnection = PQconnectdb(pud->userdb); if(!pqdbconnection) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb); } else { ConnStatusType status = PQstatus(pqdbconnection); if(status != CONNECTION_OK) { PQfinish(pqdbconnection); pqdbconnection = NULL; TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb); } else if(!donot_print_connection_success){ TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "PostgreSQL DB connection success: %s\n",pud->userdb); donot_print_connection_success = 1; } } } if(pqdbconnection) { (void) pthread_setspecific(connection_key, pqdbconnection); } } return pqdbconnection; }
RAISES_NEG static int obscure_password(connectionObject *conn) { PQconninfoOption *options; PyObject *d = NULL, *v = NULL, *dsn = NULL; char *tmp; int rv = -1; if (!conn || !conn->dsn) { return 0; } if (!(options = PQconninfoParse(conn->dsn, NULL))) { /* unlikely: the dsn was already tested valid */ return 0; } if (!(d = psycopg_dict_from_conninfo_options( options, /* include_password = */ 1))) { goto exit; } if (NULL == PyDict_GetItemString(d, "password")) { /* the dsn doesn't have a password */ rv = 0; goto exit; } /* scrub the password and put back the connection string together */ if (!(v = Text_FromUTF8("xxx"))) { goto exit; } if (0 > PyDict_SetItemString(d, "password", v)) { goto exit; } if (!(dsn = psycopg_make_dsn(Py_None, d))) { goto exit; } if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; } /* Replace the connection string on the connection object */ tmp = conn->dsn; psycopg_strdup(&conn->dsn, Bytes_AS_STRING(dsn), -1); PyMem_Free(tmp); rv = 0; exit: PQconninfoFree(options); Py_XDECREF(v); Py_XDECREF(d); Py_XDECREF(dsn); return rv; }
/* Return 1 if the "replication" keyword is set in the DSN, 0 otherwise */ static int dsn_has_replication(char *pgdsn) { int ret = 0; PQconninfoOption *connopts, *ptr; connopts = PQconninfoParse(pgdsn, NULL); for(ptr = connopts; ptr->keyword != NULL; ptr++) { if(strcmp(ptr->keyword, "replication") == 0 && ptr->val != NULL) ret = 1; } PQconninfoFree(connopts); return ret; }
/* * Parse configuration file; if any errors are encountered, * list them and exit. * * Ensure any default values set here are synced with repmgr.conf.sample * and any other documentation. */ bool parse_config(t_configuration_options *options) { FILE *fp; char *s, buff[MAXLINELENGTH]; char name[MAXLEN]; char value[MAXLEN]; /* For sanity-checking provided conninfo string */ PQconninfoOption *conninfo_options; char *conninfo_errmsg = NULL; /* Collate configuration file errors here for friendlier reporting */ static ErrorList config_errors = { NULL, NULL }; fp = fopen(config_file_path, "r"); /* * Since some commands don't require a config file at all, not having one * isn't necessarily a problem. * * If the user explictly provided a configuration file and we can't * read it we'll raise an error. * * If no configuration file was provided, we'll try and read the default\ * file if it exists and is readable, but won't worry if it's not. */ if (fp == NULL) { if (config_file_provided) { log_err(_("unable to open provided configuration file '%s'; terminating\n"), config_file_path); exit(ERR_BAD_CONFIG); } log_notice(_("no configuration file provided and default file '%s' not found - " "continuing with default values\n"), DEFAULT_CONFIG_FILE); return false; } /* Initialize configuration options with sensible defaults * note: the default log level is set in log.c and does not need * to be initialised here */ memset(options->cluster_name, 0, sizeof(options->cluster_name)); options->node = -1; options->upstream_node = NO_UPSTREAM_NODE; options->use_replication_slots = 0; memset(options->conninfo, 0, sizeof(options->conninfo)); options->failover = MANUAL_FAILOVER; options->priority = DEFAULT_PRIORITY; memset(options->node_name, 0, sizeof(options->node_name)); memset(options->promote_command, 0, sizeof(options->promote_command)); memset(options->follow_command, 0, sizeof(options->follow_command)); memset(options->rsync_options, 0, sizeof(options->rsync_options)); memset(options->ssh_options, 0, sizeof(options->ssh_options)); memset(options->pg_bindir, 0, sizeof(options->pg_bindir)); memset(options->pg_ctl_options, 0, sizeof(options->pg_ctl_options)); memset(options->pg_basebackup_options, 0, sizeof(options->pg_basebackup_options)); /* default master_response_timeout is 60 seconds */ options->master_response_timeout = 60; /* default to 6 reconnection attempts at intervals of 10 seconds */ options->reconnect_attempts = 6; options->reconnect_interval = 10; options->monitor_interval_secs = 2; options->retry_promote_interval_secs = 300; memset(options->event_notification_command, 0, sizeof(options->event_notification_command)); options->tablespace_mapping.head = NULL; options->tablespace_mapping.tail = NULL; /* Read next line */ while ((s = fgets(buff, sizeof buff, fp)) != NULL) { bool known_parameter = true; /* Parse name/value pair from line */ parse_line(buff, name, value); /* Skip blank lines */ if (!strlen(name)) continue; /* Skip comments */ if (name[0] == '#') continue; /* Copy into correct entry in parameters struct */ if (strcmp(name, "cluster") == 0) strncpy(options->cluster_name, value, MAXLEN); else if (strcmp(name, "node") == 0) options->node = repmgr_atoi(value, "node", &config_errors); else if (strcmp(name, "upstream_node") == 0) options->upstream_node = repmgr_atoi(value, "upstream_node", &config_errors); else if (strcmp(name, "conninfo") == 0) strncpy(options->conninfo, value, MAXLEN); else if (strcmp(name, "rsync_options") == 0) strncpy(options->rsync_options, value, QUERY_STR_LEN); else if (strcmp(name, "ssh_options") == 0) strncpy(options->ssh_options, value, QUERY_STR_LEN); else if (strcmp(name, "loglevel") == 0) strncpy(options->loglevel, value, MAXLEN); else if (strcmp(name, "logfacility") == 0) strncpy(options->logfacility, value, MAXLEN); else if (strcmp(name, "failover") == 0) { char failoverstr[MAXLEN]; strncpy(failoverstr, value, MAXLEN); if (strcmp(failoverstr, "manual") == 0) { options->failover = MANUAL_FAILOVER; } else if (strcmp(failoverstr, "automatic") == 0) { options->failover = AUTOMATIC_FAILOVER; } else { log_err(_("value for 'failover' must be 'automatic' or 'manual'\n")); exit(ERR_BAD_CONFIG); } } else if (strcmp(name, "priority") == 0) options->priority = repmgr_atoi(value, "priority", &config_errors); else if (strcmp(name, "node_name") == 0) strncpy(options->node_name, value, MAXLEN); else if (strcmp(name, "promote_command") == 0) strncpy(options->promote_command, value, MAXLEN); else if (strcmp(name, "follow_command") == 0) strncpy(options->follow_command, value, MAXLEN); else if (strcmp(name, "master_response_timeout") == 0) options->master_response_timeout = repmgr_atoi(value, "master_response_timeout", &config_errors); /* 'primary_response_timeout' as synonym for 'master_response_timeout' - * we'll switch terminology in a future release (3.1?) */ else if (strcmp(name, "primary_response_timeout") == 0) options->master_response_timeout = repmgr_atoi(value, "primary_response_timeout", &config_errors); else if (strcmp(name, "reconnect_attempts") == 0) options->reconnect_attempts = repmgr_atoi(value, "reconnect_attempts", &config_errors); else if (strcmp(name, "reconnect_interval") == 0) options->reconnect_interval = repmgr_atoi(value, "reconnect_interval", &config_errors); else if (strcmp(name, "pg_bindir") == 0) strncpy(options->pg_bindir, value, MAXLEN); else if (strcmp(name, "pg_ctl_options") == 0) strncpy(options->pg_ctl_options, value, MAXLEN); else if (strcmp(name, "pg_basebackup_options") == 0) strncpy(options->pg_basebackup_options, value, MAXLEN); else if (strcmp(name, "logfile") == 0) strncpy(options->logfile, value, MAXLEN); else if (strcmp(name, "monitor_interval_secs") == 0) options->monitor_interval_secs = repmgr_atoi(value, "monitor_interval_secs", &config_errors); else if (strcmp(name, "retry_promote_interval_secs") == 0) options->retry_promote_interval_secs = repmgr_atoi(value, "retry_promote_interval_secs", &config_errors); else if (strcmp(name, "use_replication_slots") == 0) /* XXX we should have a dedicated boolean argument format */ options->use_replication_slots = repmgr_atoi(value, "use_replication_slots", &config_errors); else if (strcmp(name, "event_notification_command") == 0) strncpy(options->event_notification_command, value, MAXLEN); else if (strcmp(name, "event_notifications") == 0) parse_event_notifications_list(options, value); else if (strcmp(name, "tablespace_mapping") == 0) tablespace_list_append(options, value); else { known_parameter = false; log_warning(_("%s/%s: unknown name/value pair provided; ignoring\n"), name, value); } /* * Raise an error if a known parameter is provided with an empty value. * Currently there's no reason why empty parameters are needed; if * we want to accept those, we'd need to add stricter default checking, * as currently e.g. an empty `node` value will be converted to '0'. */ if (known_parameter == true && !strlen(value)) { char error_message_buf[MAXLEN] = ""; snprintf(error_message_buf, MAXLEN, _("no value provided for parameter \"%s\""), name); error_list_append(&config_errors, error_message_buf); } } fclose(fp); /* Check config settings */ /* The following checks are for the presence of the parameter */ if (*options->cluster_name == '\0') { error_list_append(&config_errors, _("\"cluster\": parameter was not found\n")); } if (options->node == -1) { error_list_append(&config_errors, _("\"node\": parameter was not found\n")); } if (*options->node_name == '\0') { error_list_append(&config_errors, _("\"node_name\": parameter was not found\n")); } if (*options->conninfo == '\0') { error_list_append(&config_errors, _("\"conninfo\": parameter was not found\n")); } else { /* Sanity check the provided conninfo string * * NOTE: this verifies the string format and checks for valid options * but does not sanity check values */ conninfo_options = PQconninfoParse(options->conninfo, &conninfo_errmsg); if (conninfo_options == NULL) { char error_message_buf[MAXLEN] = ""; snprintf(error_message_buf, MAXLEN, _("\"conninfo\": %s"), conninfo_errmsg); error_list_append(&config_errors, error_message_buf); } PQconninfoFree(conninfo_options); } // exit_with_errors here if (config_errors.head != NULL) { exit_with_errors(&config_errors); } return true; }
pgConn::pgConn(const wxString &server, const wxString &service, const wxString &hostaddr, const wxString &database, const wxString &username, const wxString &password, int port, const wxString &rolename, int sslmode, OID oid, const wxString &applicationname, const wxString &sslcert, const wxString &sslkey, const wxString &sslrootcert, const wxString &sslcrl, const bool sslcompression) : m_cancelConn(NULL) { wxString msg; save_server = server; save_hostaddr = hostaddr; save_service = service; save_database = database; save_username = username; save_password = password; save_port = port; save_rolename = rolename; save_sslmode = sslmode; save_oid = oid; save_applicationname = applicationname; save_sslcert = sslcert; save_sslkey = sslkey; save_sslrootcert = sslrootcert; save_sslcrl = sslcrl; save_sslcompression = sslcompression; memset(features, 0, sizeof(features)); majorVersion = 0; conv = &wxConvLibc; needColQuoting = false; utfConnectString = false; // Check the hostname/ipaddress conn = 0; noticeArg = 0; connStatus = PGCONN_BAD; // Create the connection string if (!server.IsEmpty()) { connstr.Append(wxT(" host=")); connstr.Append(qtConnString(server)); } if (!hostaddr.IsEmpty()) { connstr.Append(wxT(" hostaddr=")); connstr.Append(qtConnString(hostaddr)); } if (!service.IsEmpty()) { connstr.Append(wxT(" service=")); connstr.Append(qtConnString(service)); } if (!database.IsEmpty()) { connstr.Append(wxT(" dbname=")); connstr.Append(qtConnString(database)); } if (!username.IsEmpty()) { connstr.Append(wxT(" user="******" password="******" port=")); connstr.Append(NumToStr((long)port)); } if (libpqVersion > 7.3) { switch (sslmode) { case 1: connstr.Append(wxT(" sslmode=require")); break; case 2: connstr.Append(wxT(" sslmode=prefer")); break; case 3: connstr.Append(wxT(" sslmode=allow")); break; case 4: connstr.Append(wxT(" sslmode=disable")); break; case 5: connstr.Append(wxT(" sslmode=verify-ca")); break; case 6: connstr.Append(wxT(" sslmode=verify-full")); break; } } else { switch (sslmode) { case 1: connstr.Append(wxT(" requiressl=1")); break; case 2: connstr.Append(wxT(" requiressl=0")); break; } } if (libpqVersion > 8.3 && sslmode != 4) { if (!sslcert.IsEmpty()) { connstr.Append(wxT(" sslcert=")); connstr.Append(qtConnString(sslcert)); } if (!sslkey.IsEmpty()) { connstr.Append(wxT(" sslkey=")); connstr.Append(qtConnString(sslkey)); } if (!sslrootcert.IsEmpty()) { connstr.Append(wxT(" sslrootcert=")); connstr.Append(qtConnString(sslrootcert)); } if (!sslcrl.IsEmpty()) { connstr.Append(wxT(" sslcrl=")); connstr.Append(qtConnString(sslcrl)); } } if (libpqVersion > 9.1 && sslmode != 4) { if (!sslcompression) { connstr.Append(wxT(" sslcompression=0")); } } connstr.Trim(false); dbHost = server; dbHostName = server; dbRole = rolename; #ifdef HAVE_CONNINFO_PARSE if (!applicationname.IsEmpty()) { // Check connection string with application_name char *errmsg; wxString connstr_with_applicationname = connstr + wxT(" application_name='") + applicationname + wxT("'"); if (PQconninfoParse(connstr_with_applicationname.mb_str(wxConvUTF8), &errmsg)) { connstr = connstr_with_applicationname; } else if (PQconninfoParse(connstr_with_applicationname.mb_str(wxConvLibc), &errmsg)) { connstr = connstr_with_applicationname; } } #endif // Open the connection wxString cleanConnStr = connstr; cleanConnStr.Replace(qtConnString(password), wxT("'XXXXXX'")); wxLogInfo(wxT("Opening connection with connection string: %s"), cleanConnStr.c_str()); DoConnect(); }
void dbgPgConn::Init( const wxString &server, const wxString &database, const wxString &username, const wxString &password, const wxString &port, int sslmode, const wxString &applicationname, bool startThread ) { bool utfConnectString = false; bool libcConnectString = false; m_pgConn = NULL; m_majorVersion = 0; m_minorVersion = 0; m_debuggerApiVersion = DEBUGGER_UNKNOWN_API; m_isEdb = false; if( startThread ) m_workerThread = new dbgPgThread( *this ); else m_workerThread = NULL; wxString msg; wxString delimiter; // To keep the user interface thread responsive while we're waiting for the // PostgreSQL server, we create a separate thread to interact with the // database - the worker thread sleeps until the GUI thread signals that it // has some work to do. When the result set arrives from the server, the // worker thread creates a DBResult event and posts it to the GUI thread's // event queue. if( m_workerThread ) { m_workerThread->Create(); m_workerThread->Run(); } // Figure out the hostname/IP address struct hostent *host; in_addr_t addr; wxString hostip, hostname; #ifdef __WXMSW__ struct in_addr ipaddr; #else unsigned long ipaddr; #endif #ifndef __WXMSW__ if (!(server.IsEmpty() || server.StartsWith(wxT("/")))) { #endif addr = inet_addr(server.ToAscii()); if (addr == INADDR_NONE) // szServer is not an IP address { host = gethostbyname(server.ToAscii()); if (host == NULL) { wxLogError(__("Could not resolve hostname %s"), server.c_str()); return; } memcpy(&(ipaddr), host->h_addr, host->h_length); hostip = wxString::FromAscii(inet_ntoa(*((struct in_addr *) host->h_addr_list[0]))); hostname = server; } else { hostip = server; hostname = server; } #ifndef __WXMSW__ } else hostname = server; #endif // Build up a connection string wxString connectParams; if(hostname.Length()) { connectParams.Append(wxT( "host=")); connectParams.Append(hostname); msg += delimiter + server; delimiter = _(":"); } if (hostip.Length()) { connectParams.Append(wxT(" hostaddr=")); connectParams.Append(hostip); } if(port.Length()) { connectParams += wxT(" port="); connectParams += port; msg += delimiter + port; delimiter = _(":"); } if(database.Length()) { connectParams.Append(wxT(" dbname=")); connectParams.Append(qtConnString(database)); msg += delimiter + database; delimiter = _(":"); } if(username.Length()) { connectParams.Append(wxT(" user="******":"); } if(password.Length()) { connectParams.Append(wxT(" password="******" sslmode=require")); break; case 2: connectParams.Append(wxT(" sslmode=prefer")); break; case 3: connectParams.Append(wxT(" sslmode=allow")); break; case 4: connectParams.Append(wxT(" sslmode=disable")); break; case 5: connectParams.Append(wxT(" sslmode=verify-ca")); break; case 6: connectParams.Append(wxT(" sslmode=verify-full")); break; default: break; } connectParams.Trim(true); connectParams.Trim(false); #ifdef HAVE_CONNINFO_PARSE if (!applicationname.IsEmpty()) { // Check connection string with application_name char *errmsg; wxString connectParams_with_applicationname = connectParams + wxT(" application_name='") + applicationname + wxT("'"); if (PQconninfoParse(connectParams_with_applicationname.mb_str(wxConvUTF8), &errmsg)) { utfConnectString = true; connectParams = connectParams_with_applicationname; } else if (PQconninfoParse(connectParams_with_applicationname.mb_str(wxConvLibc), &errmsg)) { libcConnectString = true; connectParams = connectParams_with_applicationname; } } #endif m_frame->getStatusBar()->SetStatusText( wxString::Format(_( "Connecting to %s" ), msg.c_str()), 1 ); wxCharBuffer cstrUTF = connectParams.mb_str(wxConvUTF8); wxCharBuffer cstrLibc = connectParams.mb_str(wxConvLibc); if (!libcConnectString) m_pgConn = PQconnectdb(cstrUTF); else m_pgConn = PQconnectdb(cstrLibc); if (PQstatus(m_pgConn) != CONNECTION_OK) { PQfinish(m_pgConn); m_pgConn = PQconnectdb(cstrLibc); } if( PQstatus( m_pgConn ) == CONNECTION_OK ) { m_frame->getStatusBar()->SetStatusText( wxString::Format(_( "Connected to %s" ), msg.c_str()), 1 ); PQsetClientEncoding( m_pgConn, "UNICODE" ); } else { throw( std::runtime_error( PQerrorMessage( m_pgConn ))); } }
/* * Parse configuration file; if any errors are encountered, * list them and exit. * * Ensure any default values set here are synced with repmgr.conf.sample * and any other documentation. */ void _parse_config(t_configuration_options *options, ItemList *error_list) { FILE *fp; char *s, buf[MAXLINELENGTH]; char name[MAXLEN]; char value[MAXLEN]; /* For sanity-checking provided conninfo string */ PQconninfoOption *conninfo_options; char *conninfo_errmsg = NULL; bool node_found = false; /* Initialize configuration options with sensible defaults * note: the default log level is set in log.c and does not need * to be initialised here */ memset(options->cluster_name, 0, sizeof(options->cluster_name)); options->node = UNKNOWN_NODE_ID; options->upstream_node = NO_UPSTREAM_NODE; options->use_replication_slots = 0; memset(options->conninfo, 0, sizeof(options->conninfo)); memset(options->barman_server, 0, sizeof(options->barman_server)); memset(options->barman_config, 0, sizeof(options->barman_config)); options->failover = MANUAL_FAILOVER; options->priority = DEFAULT_PRIORITY; memset(options->node_name, 0, sizeof(options->node_name)); memset(options->promote_command, 0, sizeof(options->promote_command)); memset(options->follow_command, 0, sizeof(options->follow_command)); memset(options->service_stop_command, 0, sizeof(options->service_stop_command)); memset(options->service_start_command, 0, sizeof(options->service_start_command)); memset(options->service_restart_command, 0, sizeof(options->service_restart_command)); memset(options->service_reload_command, 0, sizeof(options->service_reload_command)); memset(options->service_promote_command, 0, sizeof(options->service_promote_command)); memset(options->rsync_options, 0, sizeof(options->rsync_options)); memset(options->ssh_options, 0, sizeof(options->ssh_options)); memset(options->pg_bindir, 0, sizeof(options->pg_bindir)); memset(options->pg_ctl_options, 0, sizeof(options->pg_ctl_options)); memset(options->pg_basebackup_options, 0, sizeof(options->pg_basebackup_options)); memset(options->restore_command, 0, sizeof(options->restore_command)); /* default master_response_timeout is 60 seconds */ options->master_response_timeout = 60; /* default to 6 reconnection attempts at intervals of 10 seconds */ options->reconnect_attempts = 6; options->reconnect_interval = 10; options->monitor_interval_secs = 2; options->retry_promote_interval_secs = 300; /* default to resyncing repl_nodes table every 30 seconds on the witness server */ options->witness_repl_nodes_sync_interval_secs = 30; memset(options->event_notification_command, 0, sizeof(options->event_notification_command)); options->event_notifications.head = NULL; options->event_notifications.tail = NULL; options->tablespace_mapping.head = NULL; options->tablespace_mapping.tail = NULL; /* * If no configuration file available (user didn't specify and none found * in the default locations), return with default values */ if (config_file_found == false) { log_verbose(LOG_NOTICE, _("no configuration file provided and no default file found - " "continuing with default values\n")); return; } fp = fopen(config_file_path, "r"); /* * A configuration file has been found, either provided by the user * or found in one of the default locations. If we can't open it, * fail with an error. */ if (fp == NULL) { if (config_file_provided) { log_err(_("unable to open provided configuration file \"%s\"; terminating\n"), config_file_path); } else { log_err(_("unable to open default configuration file \"%s\"; terminating\n"), config_file_path); } exit(ERR_BAD_CONFIG); } /* Read file */ while ((s = fgets(buf, sizeof buf, fp)) != NULL) { bool known_parameter = true; /* Parse name/value pair from line */ parse_line(buf, name, value); /* Skip blank lines */ if (!strlen(name)) continue; /* Skip comments */ if (name[0] == '#') continue; /* Copy into correct entry in parameters struct */ if (strcmp(name, "cluster") == 0) strncpy(options->cluster_name, value, MAXLEN); else if (strcmp(name, "node") == 0) { options->node = repmgr_atoi(value, "node", error_list, false); node_found = true; } else if (strcmp(name, "upstream_node") == 0) options->upstream_node = repmgr_atoi(value, "upstream_node", error_list, false); else if (strcmp(name, "conninfo") == 0) strncpy(options->conninfo, value, MAXLEN); else if (strcmp(name, "barman_server") == 0) strncpy(options->barman_server, value, MAXLEN); else if (strcmp(name, "barman_config") == 0) strncpy(options->barman_config, value, MAXLEN); else if (strcmp(name, "rsync_options") == 0) strncpy(options->rsync_options, value, QUERY_STR_LEN); else if (strcmp(name, "ssh_options") == 0) strncpy(options->ssh_options, value, QUERY_STR_LEN); else if (strcmp(name, "loglevel") == 0) strncpy(options->loglevel, value, MAXLEN); else if (strcmp(name, "logfacility") == 0) strncpy(options->logfacility, value, MAXLEN); else if (strcmp(name, "failover") == 0) { char failoverstr[MAXLEN]; strncpy(failoverstr, value, MAXLEN); if (strcmp(failoverstr, "manual") == 0) { options->failover = MANUAL_FAILOVER; } else if (strcmp(failoverstr, "automatic") == 0) { options->failover = AUTOMATIC_FAILOVER; } else { item_list_append(error_list, _("value for 'failover' must be 'automatic' or 'manual'\n")); } } else if (strcmp(name, "priority") == 0) options->priority = repmgr_atoi(value, "priority", error_list, true); else if (strcmp(name, "node_name") == 0) strncpy(options->node_name, value, MAXLEN); else if (strcmp(name, "promote_command") == 0) strncpy(options->promote_command, value, MAXLEN); else if (strcmp(name, "follow_command") == 0) strncpy(options->follow_command, value, MAXLEN); else if (strcmp(name, "service_stop_command") == 0) strncpy(options->service_stop_command, value, MAXLEN); else if (strcmp(name, "service_start_command") == 0) strncpy(options->service_start_command, value, MAXLEN); else if (strcmp(name, "service_restart_command") == 0) strncpy(options->service_restart_command, value, MAXLEN); else if (strcmp(name, "service_reload_command") == 0) strncpy(options->service_reload_command, value, MAXLEN); else if (strcmp(name, "service_promote_command") == 0) strncpy(options->service_promote_command, value, MAXLEN); else if (strcmp(name, "master_response_timeout") == 0) options->master_response_timeout = repmgr_atoi(value, "master_response_timeout", error_list, false); /* * 'primary_response_timeout' as synonym for 'master_response_timeout' - * we'll switch terminology in a future release (3.1?) */ else if (strcmp(name, "primary_response_timeout") == 0) options->master_response_timeout = repmgr_atoi(value, "primary_response_timeout", error_list, false); else if (strcmp(name, "reconnect_attempts") == 0) options->reconnect_attempts = repmgr_atoi(value, "reconnect_attempts", error_list, false); else if (strcmp(name, "reconnect_interval") == 0) options->reconnect_interval = repmgr_atoi(value, "reconnect_interval", error_list, false); else if (strcmp(name, "pg_bindir") == 0) strncpy(options->pg_bindir, value, MAXLEN); else if (strcmp(name, "pg_ctl_options") == 0) strncpy(options->pg_ctl_options, value, MAXLEN); else if (strcmp(name, "pg_basebackup_options") == 0) strncpy(options->pg_basebackup_options, value, MAXLEN); else if (strcmp(name, "logfile") == 0) strncpy(options->logfile, value, MAXLEN); else if (strcmp(name, "monitor_interval_secs") == 0) options->monitor_interval_secs = repmgr_atoi(value, "monitor_interval_secs", error_list, false); else if (strcmp(name, "retry_promote_interval_secs") == 0) options->retry_promote_interval_secs = repmgr_atoi(value, "retry_promote_interval_secs", error_list, false); else if (strcmp(name, "witness_repl_nodes_sync_interval_secs") == 0) options->witness_repl_nodes_sync_interval_secs = repmgr_atoi(value, "witness_repl_nodes_sync_interval_secs", error_list, false); else if (strcmp(name, "use_replication_slots") == 0) /* XXX we should have a dedicated boolean argument format */ options->use_replication_slots = repmgr_atoi(value, "use_replication_slots", error_list, false); else if (strcmp(name, "event_notification_command") == 0) strncpy(options->event_notification_command, value, MAXLEN); else if (strcmp(name, "event_notifications") == 0) parse_event_notifications_list(options, value); else if (strcmp(name, "tablespace_mapping") == 0) tablespace_list_append(options, value); else if (strcmp(name, "restore_command") == 0) strncpy(options->restore_command, value, MAXLEN); else { known_parameter = false; log_warning(_("%s/%s: unknown name/value pair provided; ignoring\n"), name, value); } /* * Raise an error if a known parameter is provided with an empty value. * Currently there's no reason why empty parameters are needed; if * we want to accept those, we'd need to add stricter default checking, * as currently e.g. an empty `node` value will be converted to '0'. */ if (known_parameter == true && !strlen(value)) { char error_message_buf[MAXLEN] = ""; snprintf(error_message_buf, MAXLEN, _("no value provided for parameter \"%s\""), name); item_list_append(error_list, error_message_buf); } } fclose(fp); if (node_found == false) { item_list_append(error_list, _("\"node\": parameter was not found")); } else if (options->node == 0) { item_list_append(error_list, _("\"node\": must be greater than zero")); } if (strlen(options->conninfo)) { /* Sanity check the provided conninfo string * * NOTE: PQconninfoParse() verifies the string format and checks for valid options * but does not sanity check values */ conninfo_options = PQconninfoParse(options->conninfo, &conninfo_errmsg); if (conninfo_options == NULL) { char error_message_buf[MAXLEN] = ""; snprintf(error_message_buf, MAXLEN, _("\"conninfo\": %s"), conninfo_errmsg); item_list_append(error_list, error_message_buf); } PQconninfoFree(conninfo_options); } }
/* * Connect to the server. Returns a valid PGconn pointer if connected, * or NULL on non-permanent error. On permanent error, the function will * call exit(1) directly. */ PGconn * GetConnection(void) { PGconn *tmpconn; int argcount = 7; /* dbname, replication, fallback_app_name, * host, user, port, password */ int i; const char **keywords; const char **values; const char *tmpparam; bool need_password; PQconninfoOption *conn_opts = NULL; PQconninfoOption *conn_opt; char *err_msg = NULL; /* * Merge the connection info inputs given in form of connection string, * options and default values (dbname=replication, replication=true, etc.) */ i = 0; if (connection_string) { conn_opts = PQconninfoParse(connection_string, &err_msg); if (conn_opts == NULL) { fprintf(stderr, "%s: %s", progname, err_msg); exit(1); } for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { if (conn_opt->val != NULL && conn_opt->val[0] != '\0') argcount++; } keywords = pg_malloc0((argcount + 1) * sizeof(*keywords)); values = pg_malloc0((argcount + 1) * sizeof(*values)); for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { if (conn_opt->val != NULL && conn_opt->val[0] != '\0') { keywords[i] = conn_opt->keyword; values[i] = conn_opt->val; i++; } } } else { keywords = pg_malloc0((argcount + 1) * sizeof(*keywords)); values = pg_malloc0((argcount + 1) * sizeof(*values)); } keywords[i] = "dbname"; values[i] = "replication"; i++; keywords[i] = "replication"; values[i] = "true"; i++; keywords[i] = "fallback_application_name"; values[i] = progname; i++; if (dbhost) { keywords[i] = "host"; values[i] = dbhost; i++; } if (dbuser) { keywords[i] = "user"; values[i] = dbuser; i++; } if (dbport) { keywords[i] = "port"; values[i] = dbport; i++; } /* If -W was given, force prompt for password, but only the first time */ need_password = (dbgetpassword == 1 && dbpassword == NULL); while (true) { /* Get a new password if appropriate */ if (need_password) { if (dbpassword) free(dbpassword); dbpassword = simple_prompt(_("Password: "******"password"; values[i] = dbpassword; } else { keywords[i] = NULL; values[i] = NULL; } tmpconn = PQconnectdbParams(keywords, values, true); /* * If there is too little memory even to allocate the PGconn object * and PQconnectdbParams returns NULL, we call exit(1) directly. */ if (!tmpconn) { fprintf(stderr, _("%s: could not connect to server\n"), progname); exit(1); } /* If we need a password and -w wasn't given, loop back and get one */ if (PQstatus(tmpconn) == CONNECTION_BAD && PQconnectionNeedsPassword(tmpconn) && dbgetpassword != -1) { PQfinish(tmpconn); need_password = true; } else break; } if (PQstatus(tmpconn) != CONNECTION_OK) { fprintf(stderr, _("%s: could not connect to server: %s\n"), progname, PQerrorMessage(tmpconn)); PQfinish(tmpconn); free(values); free(keywords); if (conn_opts) PQconninfoFree(conn_opts); return NULL; } /* Connection ok! */ free(values); free(keywords); if (conn_opts) PQconninfoFree(conn_opts); /* * Ensure we have the same value of integer timestamps as the server we * are connecting to. */ tmpparam = PQparameterStatus(tmpconn, "integer_datetimes"); if (!tmpparam) { fprintf(stderr, _("%s: could not determine server setting for integer_datetimes\n"), progname); PQfinish(tmpconn); exit(1); } #ifdef HAVE_INT64_TIMESTAMP if (strcmp(tmpparam, "on") != 0) #else if (strcmp(tmpparam, "off") != 0) #endif { fprintf(stderr, _("%s: integer_datetimes compile flag does not match server\n"), progname); PQfinish(tmpconn); exit(1); } return tmpconn; }
int main(int argc, char **argv) { int c; const char *progname; const char *pghost = NULL; const char *pgport = NULL; const char *pguser = NULL; const char *pgdbname = NULL; const char *connect_timeout = DEFAULT_CONNECT_TIMEOUT; const char *pghost_str = NULL; const char *pgport_str = NULL; #define PARAMS_ARRAY_SIZE 7 const char *keywords[PARAMS_ARRAY_SIZE]; const char *values[PARAMS_ARRAY_SIZE]; bool quiet = false; PGPing rv; PQconninfoOption *opts = NULL; PQconninfoOption *defs = NULL; PQconninfoOption *opt; PQconninfoOption *def; char *errmsg = NULL; /* * We accept user and database as options to avoid useless errors from * connecting with invalid params */ static struct option long_options[] = { {"dbname", required_argument, NULL, 'd'}, {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"quiet", no_argument, NULL, 'q'}, {"timeout", required_argument, NULL, 't'}, {"username", required_argument, NULL, 'U'}, {NULL, 0, NULL, 0} }; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts")); handle_help_version_opts(argc, argv, progname, help); while ((c = getopt_long(argc, argv, "d:h:p:qt:U:", long_options, NULL)) != -1) { switch (c) { case 'd': pgdbname = pg_strdup(optarg); break; case 'h': pghost = pg_strdup(optarg); break; case 'p': pgport = pg_strdup(optarg); break; case 'q': quiet = true; break; case 't': connect_timeout = pg_strdup(optarg); break; case 'U': pguser = pg_strdup(optarg); break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); /* * We need to make sure we don't return 1 here because someone * checking the return code might infer unintended meaning */ exit(PQPING_NO_ATTEMPT); } } if (optind < argc) { fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); /* * We need to make sure we don't return 1 here because someone * checking the return code might infer unintended meaning */ exit(PQPING_NO_ATTEMPT); } keywords[0] = "host"; values[0] = pghost; keywords[1] = "port"; values[1] = pgport; keywords[2] = "user"; values[2] = pguser; keywords[3] = "dbname"; values[3] = pgdbname; keywords[4] = "connect_timeout"; values[4] = connect_timeout; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = NULL; values[6] = NULL; /* * Get the host and port so we can display them in our output */ if (pgdbname) { opts = PQconninfoParse(pgdbname, &errmsg); if (opts == NULL) { fprintf(stderr, _("%s: %s"), progname, errmsg); exit(PQPING_NO_ATTEMPT); } } defs = PQconndefaults(); if (defs == NULL) { fprintf(stderr, _("%s: could not fetch default options\n"), progname); exit(PQPING_NO_ATTEMPT); } for (opt = opts, def = defs; def->keyword; def++) { if (strcmp(def->keyword, "hostaddr") == 0 || strcmp(def->keyword, "host") == 0) { if (opt && opt->val) pghost_str = opt->val; else if (pghost) pghost_str = pghost; else if (def->val) pghost_str = def->val; else pghost_str = DEFAULT_PGSOCKET_DIR; } else if (strcmp(def->keyword, "port") == 0) { if (opt && opt->val) pgport_str = opt->val; else if (pgport) pgport_str = pgport; else if (def->val) pgport_str = def->val; } if (opt) opt++; } rv = PQpingParams(keywords, values, 1); if (!quiet) { printf("%s:%s - ", pghost_str, pgport_str); switch (rv) { case PQPING_OK: printf("accepting connections\n"); break; case PQPING_REJECT: printf("rejecting connections\n"); break; case PQPING_NO_RESPONSE: printf("no response\n"); break; case PQPING_NO_ATTEMPT: printf("no attempt\n"); break; default: printf("unknown\n"); } } exit(rv); }