mirror of
https://github.com/postgres/postgres.git
synced 2025-06-01 00:01:20 -04:00
hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
681 lines
15 KiB
C
681 lines
15 KiB
C
/*
|
|
* psql - the PostgreSQL interactive terminal
|
|
*
|
|
* Copyright 2000 by PostgreSQL Global Development Group
|
|
*
|
|
* $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.38 2000/11/13 15:18:14 momjian Exp $
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include <sys/types.h>
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else /* WIN32 */
|
|
#include <io.h>
|
|
#include <windows.h>
|
|
#include <win32.h>
|
|
#endif /* WIN32 */
|
|
|
|
#ifdef HAVE_GETOPT_H
|
|
#include <getopt.h>
|
|
#endif
|
|
|
|
#include "libpq-fe.h"
|
|
|
|
#include "command.h"
|
|
#include "common.h"
|
|
#include "describe.h"
|
|
#include "help.h"
|
|
#include "input.h"
|
|
#include "mainloop.h"
|
|
#include "print.h"
|
|
#include "settings.h"
|
|
#include "variables.h"
|
|
|
|
#ifdef MULTIBYTE
|
|
#include "miscadmin.h"
|
|
#include "mb/pg_wchar.h"
|
|
#else
|
|
/* XXX Grand unified hard-coded badness; this should go into libpq */
|
|
#define pg_encoding_to_char(x) "SQL_ASCII"
|
|
#endif
|
|
|
|
/*
|
|
* Global psql options
|
|
*/
|
|
PsqlSettings pset;
|
|
|
|
|
|
/*
|
|
* Structures to pass information between the option parsing routine
|
|
* and the main function
|
|
*/
|
|
enum _actions
|
|
{
|
|
ACT_NOTHING = 0,
|
|
ACT_SINGLE_SLASH,
|
|
ACT_LIST_DB,
|
|
ACT_SINGLE_QUERY,
|
|
ACT_FILE
|
|
};
|
|
|
|
struct adhoc_opts
|
|
{
|
|
char *dbname;
|
|
char *host;
|
|
char *port;
|
|
char *unixsocket;
|
|
char *username;
|
|
enum _actions action;
|
|
char *action_string;
|
|
bool no_readline;
|
|
bool no_psqlrc;
|
|
};
|
|
|
|
static void
|
|
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options);
|
|
|
|
static void
|
|
process_psqlrc(void);
|
|
|
|
static void
|
|
showVersion(void);
|
|
|
|
#ifdef USE_SSL
|
|
static void
|
|
printSSLInfo(void);
|
|
#endif
|
|
|
|
|
|
/*
|
|
*
|
|
* main
|
|
*
|
|
*/
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct adhoc_opts options;
|
|
int successResult;
|
|
|
|
char *username = NULL;
|
|
char *password = NULL;
|
|
bool need_pass;
|
|
|
|
if (!strrchr(argv[0], SEP_CHAR))
|
|
pset.progname = argv[0];
|
|
else
|
|
pset.progname = strrchr(argv[0], SEP_CHAR) + 1;
|
|
|
|
pset.cur_cmd_source = stdin;
|
|
pset.cur_cmd_interactive = false;
|
|
pset.encoding = PQenv2encoding();
|
|
|
|
pset.vars = CreateVariableSpace();
|
|
if (!pset.vars)
|
|
{
|
|
fprintf(stderr, "%s: out of memory\n", pset.progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
pset.popt.topt.format = PRINT_ALIGNED;
|
|
pset.queryFout = stdout;
|
|
pset.popt.topt.border = 1;
|
|
pset.popt.topt.pager = true;
|
|
|
|
SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
|
|
|
|
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
|
|
|
|
/* This is obsolete and should be removed sometime. */
|
|
#ifdef PSQL_ALWAYS_GET_PASSWORDS
|
|
pset.getPassword = true;
|
|
#else
|
|
pset.getPassword = false;
|
|
#endif
|
|
|
|
parse_psql_options(argc, argv, &options);
|
|
|
|
if (!pset.popt.topt.fieldSep)
|
|
pset.popt.topt.fieldSep = xstrdup(DEFAULT_FIELD_SEP);
|
|
if (!pset.popt.topt.recordSep)
|
|
pset.popt.topt.recordSep = xstrdup(DEFAULT_RECORD_SEP);
|
|
|
|
if (options.username)
|
|
{
|
|
|
|
/*
|
|
* The \001 is a hack to support the deprecated -u option which
|
|
* issues a username prompt. The recommended option is -U followed
|
|
* by the name on the command line.
|
|
*/
|
|
if (strcmp(options.username, "\001") == 0)
|
|
username = simple_prompt("Username: ", 100, true);
|
|
else
|
|
username = strdup(options.username);
|
|
}
|
|
|
|
if (pset.getPassword)
|
|
password = simple_prompt("Password: ", 100, false);
|
|
|
|
/* loop until we have a password if requested by backend */
|
|
do
|
|
{
|
|
need_pass = false;
|
|
/* FIXME use PQconnectdb to allow setting the unix socket */
|
|
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
|
|
options.action == ACT_LIST_DB ? "template1" : options.dbname,
|
|
username, password);
|
|
|
|
if (PQstatus(pset.db) == CONNECTION_BAD &&
|
|
strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0)
|
|
{
|
|
PQfinish(pset.db);
|
|
need_pass = true;
|
|
free(password);
|
|
password = NULL;
|
|
password = simple_prompt("Password: ", 100, false);
|
|
}
|
|
} while (need_pass);
|
|
|
|
free(username);
|
|
free(password);
|
|
|
|
if (PQstatus(pset.db) == CONNECTION_BAD)
|
|
{
|
|
fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
|
|
PQfinish(pset.db);
|
|
exit(EXIT_BADCONN);
|
|
}
|
|
|
|
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
|
|
|
|
/*
|
|
* We need to save the encoding because we want to have it available
|
|
* even if the database connection goes bad.
|
|
*/
|
|
pset.encoding = PQclientEncoding(pset.db);
|
|
|
|
if (options.action == ACT_LIST_DB)
|
|
{
|
|
int success = listAllDbs(false);
|
|
|
|
PQfinish(pset.db);
|
|
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
|
|
SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
|
|
SetVariable(pset.vars, "USER", PQuser(pset.db));
|
|
SetVariable(pset.vars, "HOST", PQhost(pset.db));
|
|
SetVariable(pset.vars, "PORT", PQport(pset.db));
|
|
SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
|
|
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
|
|
|
|
#ifndef WIN32
|
|
pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
|
|
#endif
|
|
|
|
/*
|
|
* Now find something to do
|
|
*/
|
|
|
|
/*
|
|
* process file given by -f
|
|
*/
|
|
if (options.action == ACT_FILE)
|
|
{
|
|
if (!options.no_psqlrc)
|
|
process_psqlrc();
|
|
|
|
successResult = process_file(options.action_string);
|
|
}
|
|
|
|
/*
|
|
* process slash command if one was given to -c
|
|
*/
|
|
else if (options.action == ACT_SINGLE_SLASH)
|
|
{
|
|
const char *value;
|
|
|
|
if ((value = GetVariable(pset.vars, "ECHO")) && strcmp(value, "all") == 0)
|
|
puts(options.action_string);
|
|
successResult = HandleSlashCmds(options.action_string, NULL, NULL) != CMD_ERROR
|
|
? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* If the query given to -c was a normal one, send it
|
|
*/
|
|
else if (options.action == ACT_SINGLE_QUERY)
|
|
{
|
|
const char *value;
|
|
|
|
if ((value = GetVariable(pset.vars, "ECHO")) && strcmp(value, "all") == 0)
|
|
puts(options.action_string);
|
|
successResult = SendQuery(options.action_string)
|
|
? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* or otherwise enter interactive main loop
|
|
*/
|
|
else
|
|
{
|
|
pset.issuper = test_superuser(PQuser(pset.db));
|
|
if (!QUIET() && !pset.notty)
|
|
{
|
|
printf("Welcome to %s, the PostgreSQL interactive terminal.\n\n"
|
|
"Type: \\copyright for distribution terms\n"
|
|
" \\h for help with SQL commands\n"
|
|
" \\? for help on internal slash commands\n"
|
|
" \\g or terminate with semicolon to execute query\n"
|
|
" \\q to quit\n\n", pset.progname);
|
|
#ifdef USE_SSL
|
|
printSSLInfo();
|
|
#endif
|
|
}
|
|
|
|
SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
|
|
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
|
|
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
|
|
if (!options.no_psqlrc)
|
|
process_psqlrc();
|
|
if (!pset.notty)
|
|
initializeInput(options.no_readline ? 0 : 1);
|
|
successResult = MainLoop(stdin);
|
|
}
|
|
|
|
/* clean up */
|
|
PQfinish(pset.db);
|
|
setQFout(NULL);
|
|
|
|
return successResult;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Parse command line options
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
/* getopt is not in the standard includes on Win32 */
|
|
int getopt(int, char *const[], const char *);
|
|
|
|
/* And it requires progname to be set */
|
|
char *__progname = "psql";
|
|
|
|
#endif
|
|
|
|
static void
|
|
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
|
|
{
|
|
#ifdef HAVE_GETOPT_LONG
|
|
static struct option long_options[] =
|
|
{
|
|
{"echo-all", no_argument, NULL, 'a'},
|
|
{"no-align", no_argument, NULL, 'A'},
|
|
{"command", required_argument, NULL, 'c'},
|
|
{"dbname", required_argument, NULL, 'd'},
|
|
{"echo-queries", no_argument, NULL, 'e'},
|
|
{"echo-hidden", no_argument, NULL, 'E'},
|
|
{"file", required_argument, NULL, 'f'},
|
|
{"field-separator", required_argument, NULL, 'F'},
|
|
{"host", required_argument, NULL, 'h'},
|
|
{"html", no_argument, NULL, 'H'},
|
|
{"unixsocket", required_argument, NULL, 'k'},
|
|
{"list", no_argument, NULL, 'l'},
|
|
{"no-readline", no_argument, NULL, 'n'},
|
|
{"output", required_argument, NULL, 'o'},
|
|
{"port", required_argument, NULL, 'p'},
|
|
{"pset", required_argument, NULL, 'P'},
|
|
{"quiet", no_argument, NULL, 'q'},
|
|
{"record-separator", required_argument, NULL, 'R'},
|
|
{"single-step", no_argument, NULL, 's'},
|
|
{"single-line", no_argument, NULL, 'S'},
|
|
{"tuples-only", no_argument, NULL, 't'},
|
|
{"table-attr", required_argument, NULL, 'T'},
|
|
{"username", required_argument, NULL, 'U'},
|
|
{"set", required_argument, NULL, 'v'},
|
|
{"variable", required_argument, NULL, 'v'},
|
|
{"version", no_argument, NULL, 'V'},
|
|
{"password", no_argument, NULL, 'W'},
|
|
{"expanded", no_argument, NULL, 'x'},
|
|
{"no-psqlrc", no_argument, NULL, 'X'},
|
|
{"help", no_argument, NULL, '?'},
|
|
};
|
|
|
|
int optindex;
|
|
|
|
#endif /* HAVE_GETOPT_LONG */
|
|
|
|
extern char *optarg;
|
|
extern int optind;
|
|
int c;
|
|
bool used_old_u_option = false;
|
|
|
|
memset(options, 0, sizeof *options);
|
|
|
|
#ifdef HAVE_GETOPT_LONG
|
|
while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
|
|
#else /* not HAVE_GETOPT_LONG */
|
|
|
|
/*
|
|
* Be sure to leave the '-' in here, so we can catch accidental long
|
|
* options.
|
|
*/
|
|
while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
|
|
#endif /* not HAVE_GETOPT_LONG */
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a':
|
|
SetVariable(pset.vars, "ECHO", "all");
|
|
break;
|
|
case 'A':
|
|
pset.popt.topt.format = PRINT_UNALIGNED;
|
|
break;
|
|
case 'c':
|
|
options->action_string = optarg;
|
|
if (optarg[0] == '\\')
|
|
{
|
|
options->action = ACT_SINGLE_SLASH;
|
|
options->action_string++;
|
|
}
|
|
else
|
|
options->action = ACT_SINGLE_QUERY;
|
|
break;
|
|
case 'd':
|
|
options->dbname = optarg;
|
|
break;
|
|
case 'e':
|
|
SetVariable(pset.vars, "ECHO", "queries");
|
|
break;
|
|
case 'E':
|
|
SetVariableBool(pset.vars, "ECHO_HIDDEN");
|
|
break;
|
|
case 'f':
|
|
options->action = ACT_FILE;
|
|
options->action_string = optarg;
|
|
break;
|
|
case 'F':
|
|
pset.popt.topt.fieldSep = xstrdup(optarg);
|
|
break;
|
|
case 'h':
|
|
options->host = optarg;
|
|
break;
|
|
case 'H':
|
|
pset.popt.topt.format = PRINT_HTML;
|
|
break;
|
|
case 'l':
|
|
options->action = ACT_LIST_DB;
|
|
break;
|
|
case 'k':
|
|
options->unixsocket = optarg;
|
|
break;
|
|
case 'n':
|
|
options->no_readline = true;
|
|
break;
|
|
case 'o':
|
|
setQFout(optarg);
|
|
break;
|
|
case 'p':
|
|
options->port = optarg;
|
|
break;
|
|
case 'P':
|
|
{
|
|
char *value;
|
|
char *equal_loc;
|
|
bool result;
|
|
|
|
value = xstrdup(optarg);
|
|
equal_loc = strchr(value, '=');
|
|
if (!equal_loc)
|
|
result = do_pset(value, NULL, &pset.popt, true);
|
|
else
|
|
{
|
|
*equal_loc = '\0';
|
|
result = do_pset(value, equal_loc + 1, &pset.popt, true);
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
fprintf(stderr, "%s: couldn't set printing parameter %s\n", pset.progname, value);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
free(value);
|
|
break;
|
|
}
|
|
case 'q':
|
|
SetVariableBool(pset.vars, "QUIET");
|
|
break;
|
|
case 'R':
|
|
pset.popt.topt.recordSep = xstrdup(optarg);
|
|
break;
|
|
case 's':
|
|
SetVariableBool(pset.vars, "SINGLESTEP");
|
|
break;
|
|
case 'S':
|
|
SetVariableBool(pset.vars, "SINGLELINE");
|
|
break;
|
|
case 't':
|
|
pset.popt.topt.tuples_only = true;
|
|
break;
|
|
case 'T':
|
|
pset.popt.topt.tableAttr = xstrdup(optarg);
|
|
break;
|
|
case 'u':
|
|
pset.getPassword = true;
|
|
options->username = "\001"; /* hopefully nobody has
|
|
* that username */
|
|
/* this option is out */
|
|
used_old_u_option = true;
|
|
break;
|
|
case 'U':
|
|
options->username = optarg;
|
|
break;
|
|
case 'v':
|
|
{
|
|
char *value;
|
|
char *equal_loc;
|
|
|
|
value = xstrdup(optarg);
|
|
equal_loc = strchr(value, '=');
|
|
if (!equal_loc)
|
|
{
|
|
if (!DeleteVariable(pset.vars, value))
|
|
{
|
|
fprintf(stderr, "%s: could not delete variable %s\n",
|
|
pset.progname, value);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*equal_loc = '\0';
|
|
if (!SetVariable(pset.vars, value, equal_loc + 1))
|
|
{
|
|
fprintf(stderr, "%s: could not set variable %s\n",
|
|
pset.progname, value);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
free(value);
|
|
break;
|
|
}
|
|
case 'V':
|
|
showVersion();
|
|
exit(EXIT_SUCCESS);
|
|
case 'W':
|
|
pset.getPassword = true;
|
|
break;
|
|
case 'x':
|
|
pset.popt.topt.expanded = true;
|
|
break;
|
|
case 'X':
|
|
options->no_psqlrc = true;
|
|
break;
|
|
case '?':
|
|
/* Actual help option given */
|
|
if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
|
|
{
|
|
usage();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
/* unknown option reported by getopt */
|
|
else
|
|
{
|
|
fputs("Try -? for help.\n", stderr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
#ifndef HAVE_GETOPT_LONG
|
|
case '-':
|
|
fprintf(stderr, "%s was compiled without support for long options.\n"
|
|
"Use -? for help on invocation options.\n", pset.progname);
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
#endif
|
|
default:
|
|
fputs("Try -? for help.\n", stderr);
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* if we still have arguments, use it as the database name and
|
|
* username
|
|
*/
|
|
while (argc - optind >= 1)
|
|
{
|
|
if (!options->dbname)
|
|
options->dbname = argv[optind];
|
|
else if (!options->username)
|
|
options->username = argv[optind];
|
|
else if (!QUIET())
|
|
fprintf(stderr, "%s: warning: extra option %s ignored\n",
|
|
pset.progname, argv[optind]);
|
|
|
|
optind++;
|
|
}
|
|
|
|
if (used_old_u_option && !QUIET())
|
|
fprintf(stderr, "%s: Warning: The -u option is deprecated. Use -U.\n", pset.progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Load .psqlrc file, if found.
|
|
*/
|
|
static void
|
|
process_psqlrc(void)
|
|
{
|
|
char *psqlrc;
|
|
char *home;
|
|
|
|
#ifdef WIN32
|
|
#define R_OK 0
|
|
#endif
|
|
|
|
/* Look for one in the home dir */
|
|
home = getenv("HOME");
|
|
|
|
if (home)
|
|
{
|
|
psqlrc = malloc(strlen(home) + 20);
|
|
if (!psqlrc)
|
|
{
|
|
fprintf(stderr, "%s: out of memory\n", pset.progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
sprintf(psqlrc, "%s/.psqlrc-" PG_VERSION, home);
|
|
if (access(psqlrc, R_OK) == 0)
|
|
process_file(psqlrc);
|
|
else
|
|
{
|
|
sprintf(psqlrc, "%s/.psqlrc", home);
|
|
if (access(psqlrc, R_OK) == 0)
|
|
process_file(psqlrc);
|
|
}
|
|
free(psqlrc);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* showVersion
|
|
*
|
|
* This output format is intended to match GNU standards.
|
|
*/
|
|
static void
|
|
showVersion(void)
|
|
{
|
|
puts("psql (PostgreSQL) " PG_VERSION);
|
|
|
|
#if defined(USE_READLINE) || defined (USE_HISTORY) || defined(MULTIBYTE)
|
|
fputs("contains ", stdout);
|
|
|
|
#ifdef USE_READLINE
|
|
fputs("readline", stdout);
|
|
#define _Feature
|
|
#endif
|
|
|
|
#ifdef USE_HISTORY
|
|
#ifdef _Feature
|
|
fputs(", ", stdout);
|
|
#else
|
|
#define _Feature
|
|
#endif
|
|
fputs("history", stdout);
|
|
#endif
|
|
|
|
#ifdef MULTIBYTE
|
|
#ifdef _Feature
|
|
fputs(", ", stdout);
|
|
#else
|
|
#define _Feature
|
|
#endif
|
|
fputs("multibyte", stdout);
|
|
#endif
|
|
|
|
#undef _Feature
|
|
|
|
puts(" support");
|
|
#endif
|
|
|
|
puts("Portions Copyright (c) 1996-2000, PostgreSQL, Inc");
|
|
puts("Portions Copyright (c) 1996 Regents of the University of California");
|
|
puts("Read the file COPYRIGHT or use the command \\copyright to see the");
|
|
puts("usage and distribution terms.");
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* printSSLInfo
|
|
*
|
|
* Prints information about the current SSL connection, if SSL is in use
|
|
*/
|
|
#ifdef USE_SSL
|
|
static void
|
|
printSSLInfo(void)
|
|
{
|
|
int sslbits = -1;
|
|
SSL *ssl;
|
|
|
|
ssl = PQgetssl(pset.db);
|
|
if (!ssl)
|
|
return; /* no SSL */
|
|
|
|
SSL_get_cipher_bits(ssl, &sslbits);
|
|
printf("SSL enabled connection. Chiper: %s, bits: %i\n\n",
|
|
SSL_get_cipher(ssl),sslbits);
|
|
}
|
|
#endif
|