Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/* 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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
/* 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;
}
Ejemplo n.º 8
0
/*
 * 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;
}
Ejemplo n.º 9
0
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();
}
Ejemplo n.º 10
0
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 )));
	}
}
Ejemplo n.º 11
0
/*
 * 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);
	}
}
Ejemplo n.º 12
0
/*
 * 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;
}
Ejemplo n.º 13
0
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);
}