Header And Logo

PostgreSQL
| The world's most advanced open source database.

streamutil.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * streamutil.c - utility functions for pg_basebackup and pg_receivelog
00004  *
00005  * Author: Magnus Hagander <[email protected]>
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  *
00009  * IDENTIFICATION
00010  *        src/bin/pg_basebackup/streamutil.c
00011  *-------------------------------------------------------------------------
00012  */
00013 
00014 #include "postgres_fe.h"
00015 #include "streamutil.h"
00016 
00017 #include <stdio.h>
00018 #include <string.h>
00019 
00020 const char *progname;
00021 char       *connection_string = NULL;
00022 char       *dbhost = NULL;
00023 char       *dbuser = NULL;
00024 char       *dbport = NULL;
00025 int         dbgetpassword = 0;  /* 0=auto, -1=never, 1=always */
00026 static char *dbpassword = NULL;
00027 PGconn     *conn = NULL;
00028 
00029 /*
00030  * Connect to the server. Returns a valid PGconn pointer if connected,
00031  * or NULL on non-permanent error. On permanent error, the function will
00032  * call exit(1) directly.
00033  */
00034 PGconn *
00035 GetConnection(void)
00036 {
00037     PGconn     *tmpconn;
00038     int         argcount = 7;   /* dbname, replication, fallback_app_name,
00039                                  * host, user, port, password */
00040     int         i;
00041     const char **keywords;
00042     const char **values;
00043     char       *password = NULL;
00044     const char *tmpparam;
00045     PQconninfoOption *conn_opts = NULL;
00046     PQconninfoOption *conn_opt;
00047     char       *err_msg = NULL;
00048 
00049     /*
00050      * Merge the connection info inputs given in form of connection string,
00051      * options and default values (dbname=replication, replication=true,
00052      * etc.)
00053      */
00054     i = 0;
00055     if (connection_string)
00056     {
00057         conn_opts = PQconninfoParse(connection_string, &err_msg);
00058         if (conn_opts == NULL)
00059         {
00060             fprintf(stderr, "%s: %s\n", progname, err_msg);
00061             return NULL;
00062         }
00063 
00064         for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
00065         {
00066             if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
00067                 argcount++;
00068         }
00069 
00070         keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
00071         values = pg_malloc0((argcount + 1) * sizeof(*values));
00072 
00073         for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
00074         {
00075             if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
00076             {
00077                 keywords[i] = conn_opt->keyword;
00078                 values[i] = conn_opt->val;
00079                 i++;
00080             }
00081         }
00082     }
00083     else
00084     {
00085         keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
00086         values = pg_malloc0((argcount + 1) * sizeof(*values));
00087     }
00088 
00089     keywords[i] = "dbname";
00090     values[i] = "replication";
00091     i++;
00092     keywords[i] = "replication";
00093     values[i] = "true";
00094     i++;
00095     keywords[i] = "fallback_application_name";
00096     values[i] = progname;
00097     i++;
00098 
00099     if (dbhost)
00100     {
00101         keywords[i] = "host";
00102         values[i] = dbhost;
00103         i++;
00104     }
00105     if (dbuser)
00106     {
00107         keywords[i] = "user";
00108         values[i] = dbuser;
00109         i++;
00110     }
00111     if (dbport)
00112     {
00113         keywords[i] = "port";
00114         values[i] = dbport;
00115         i++;
00116     }
00117 
00118     while (true)
00119     {
00120         if (password)
00121             free(password);
00122 
00123         if (dbpassword)
00124         {
00125             /*
00126              * We've saved a password when a previous connection succeeded,
00127              * meaning this is the call for a second session to the same
00128              * database, so just forcibly reuse that password.
00129              */
00130             keywords[i] = "password";
00131             values[i] = dbpassword;
00132             dbgetpassword = -1; /* Don't try again if this fails */
00133         }
00134         else if (dbgetpassword == 1)
00135         {
00136             password = simple_prompt(_("Password: "), 100, false);
00137             keywords[i] = "password";
00138             values[i] = password;
00139         }
00140 
00141         tmpconn = PQconnectdbParams(keywords, values, true);
00142 
00143         /*
00144          * If there is too little memory even to allocate the PGconn object
00145          * and PQconnectdbParams returns NULL, we call exit(1) directly.
00146          */
00147         if (!tmpconn)
00148         {
00149             fprintf(stderr, _("%s: could not connect to server\n"),
00150                     progname);
00151             exit(1);
00152         }
00153 
00154         if (PQstatus(tmpconn) == CONNECTION_BAD &&
00155             PQconnectionNeedsPassword(tmpconn) &&
00156             dbgetpassword != -1)
00157         {
00158             dbgetpassword = 1;  /* ask for password next time */
00159             PQfinish(tmpconn);
00160             continue;
00161         }
00162 
00163         if (PQstatus(tmpconn) != CONNECTION_OK)
00164         {
00165             fprintf(stderr, _("%s: could not connect to server: %s\n"),
00166                     progname, PQerrorMessage(tmpconn));
00167             PQfinish(tmpconn);
00168             free(values);
00169             free(keywords);
00170             if (conn_opts)
00171                 PQconninfoFree(conn_opts);
00172             return NULL;
00173         }
00174 
00175         /* Connection ok! */
00176         free(values);
00177         free(keywords);
00178         if (conn_opts)
00179             PQconninfoFree(conn_opts);
00180 
00181         /*
00182          * Ensure we have the same value of integer timestamps as the server
00183          * we are connecting to.
00184          */
00185         tmpparam = PQparameterStatus(tmpconn, "integer_datetimes");
00186         if (!tmpparam)
00187         {
00188             fprintf(stderr,
00189                     _("%s: could not determine server setting for integer_datetimes\n"),
00190                     progname);
00191             PQfinish(tmpconn);
00192             exit(1);
00193         }
00194 
00195 #ifdef HAVE_INT64_TIMESTAMP
00196         if (strcmp(tmpparam, "on") != 0)
00197 #else
00198         if (strcmp(tmpparam, "off") != 0)
00199 #endif
00200         {
00201             fprintf(stderr,
00202              _("%s: integer_datetimes compile flag does not match server\n"),
00203                     progname);
00204             PQfinish(tmpconn);
00205             exit(1);
00206         }
00207 
00208         /* Store the password for next run */
00209         if (password)
00210             dbpassword = password;
00211         return tmpconn;
00212     }
00213 }