pgpool2.git / summary / log / commit / refs
commit accb2b28ca2fb19b4dda9c0ab6b0dc6e995730cd
Author: Muhammad Usama <m.usama@gmail.com>
Date: Fri Mar 06 10:28:25 2015 +0000
Next in the series of overhauling the PCP library and utilities.
This list of some more prominent changes is as follows.
-- As currently pgpool-II has 12 PCP client utilities and almost 90% of the code
for these utilities was common, So this commit creates a single source file for
all the utilities, to make managing and maintenance of the utilities little easier.
New source file "src/tools/pcp/pcp_frontend_client.c" added by this commit is
now used for creating all PCP utilities.
-- Syntax is changed for all PCP utilities and PCP utilities now accepts long-options.
Also, almost all arguments to the utilities are assigned a default value which
is used if the particular argument is not supplied by the user.
-- The commit also solves the security issue existed in all PCP utilities,
which was due to the fact that all PCP commands accepts the password as an
argument which has a potential of being captured by 'ps' command.
Now PCP applications do not take password in an argument and it can be either
supplied by password prompt or utilities can read the password
from ". pcppass" file, which should be located in User's home directory
or can be specified by PCPPASSFILE environment variable,
The password file format is "hostname:port:username:password"
configure | 7 +
configure.ac | 2 +-
src/include/config.h.in | 3 +
src/include/pcp/libpcp_ext.h | 2 +
src/include/utils/fe_ports.h | 3 +
src/include/utils/pool_path.h | 9 +-
src/libs/pcp/Makefile.am | 9 +-
src/libs/pcp/Makefile.in | 35 +-
src/libs/pcp/pcp.c | 210 +++++-
src/pcp_con/pcp_worker.c | 12 +-
src/test/pgpool_setup | 19 +-
src/test/regression/tests/054.postgres_fdw/test.sh | 2 +-
src/tools/pcp/Makefile.am | 27 +-
src/tools/pcp/Makefile.in | 95 ++-
src/tools/pcp/pcp_attach_node.c | 140 ----
src/tools/pcp/pcp_detach_node.c | 152 ----
src/tools/pcp/pcp_frontend_client.c | 775 +++++++++++++++++++++
src/tools/pcp/pcp_node_count.c | 139 ----
src/tools/pcp/pcp_node_info.c | 166 -----
src/tools/pcp/pcp_pool_status.c | 150 ----
src/tools/pcp/pcp_proc_count.c | 144 ----
src/tools/pcp/pcp_proc_info.c | 232 ------
src/tools/pcp/pcp_promote_node.c | 153 ----
src/tools/pcp/pcp_recovery_node.c | 142 ----
src/tools/pcp/pcp_stop_pgpool.c | 144 ----
src/tools/pcp/pcp_systemdb_info.c | 168 -----
src/tools/pcp/pcp_watchdog_info.c | 176 -----
src/utils/pool_path.c | 83 ++-
src/utils/sprompt.c | 204 ++++++
29 files changed, 1402 insertions(+), 2001 deletions(-)
diff --git a/configure b/configure
index 6b5eb2fe8..67f90562a 100755
--- a/configure
+++ b/configure
@@ -12735,6 +12735,13 @@ fi
done
+ac_fn_c_check_header_mongrel "$LINENO" "termios.h" "ac_cv_header_termios_h" "$ac_includes_default"
+if test "x$ac_cv_header_termios_h" = xyes; then :
+
+$as_echo "#define HAVE_TERMIOS_H 1" >>confdefs.h
+
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
diff --git a/configure.ac b/configure.ac
index f599c4bb5..13fe7f2e4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,7 +75,7 @@ dnl Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h unistd.h getopt.h netinet/tcp.h netinet/in.h netdb.h sys/param.h sys/types.h sys/socket.h sys/un.h sys/time.h sys/sem.h sys/shm.h sys/select.h crypt.h sys/pstat.h)
-
+AC_CHECK_HEADER([termios.h], [AC_DEFINE(HAVE_TERMIOS_H,1,checking termios)])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
diff --git a/src/include/config.h.in b/src/include/config.h.in
index fe7fcdfef..d3efed4da 100644
--- a/src/include/config.h.in
+++ b/src/include/config.h.in
@@ -227,6 +227,9 @@
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
+/* checking termios */
+#undef HAVE_TERMIOS_H
+
/* Define to 1 if the system has the type `union semun'. */
#undef HAVE_UNION_SEMUN
diff --git a/src/include/pcp/libpcp_ext.h b/src/include/pcp/libpcp_ext.h
index c002a65e7..d83563266 100644
--- a/src/include/pcp/libpcp_ext.h
+++ b/src/include/pcp/libpcp_ext.h
@@ -297,6 +297,8 @@ extern void pcp_free_result(PCPConnInfo* pcpConn);
extern void pcp_free_connection(PCPConnInfo* pcpConn);
extern int pcp_result_slot_count(PCPResultInfo* res);
extern char *pcp_get_last_error(PCPConnInfo* pcpConn);
+
+extern int pcp_result_is_empty(PCPResultInfo* res);
/* ------------------------------
* pcp_error.c
* ------------------------------
diff --git a/src/include/utils/fe_ports.h b/src/include/utils/fe_ports.h
index fd83c7a5c..5eb18fa9f 100644
--- a/src/include/utils/fe_ports.h
+++ b/src/include/utils/fe_ports.h
@@ -32,7 +32,10 @@
#ifndef FE_PORTS
#define FE_PORTS
+#include "pool_type.h"
+
+extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
extern int _fe_error_level;
void *pg_malloc(size_t size);
diff --git a/src/include/utils/pool_path.h b/src/include/utils/pool_path.h
index 1348cc695..3919bd146 100644
--- a/src/include/utils/pool_path.h
+++ b/src/include/utils/pool_path.h
@@ -6,7 +6,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Portions Copyright (c) 2003-2008, PgPool Global Development Group
+ * Portions Copyright (c) 2003-2015, PgPool Global Development Group
* Portions Copyright (c) 2004, PostgreSQL Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
@@ -26,7 +26,7 @@
#ifndef POOL_PATH_H
#define POOL_PATH_H
-
+#include"pool_type.h"
/*
* MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence,
* maximum usable pathname length is one less).
@@ -48,5 +48,8 @@
extern void get_parent_directory(char *path);
extern void join_path_components(char *ret_path, const char *head, const char *tail);
extern void canonicalize_path(char *path);
-
+extern char *last_dir_separator(const char *filename);
+extern bool get_home_directory(char *buf, int bufsize);
+extern bool get_os_username(char *buf, int bufsize);
+
#endif /* POOL_PATH_H */
diff --git a/src/libs/pcp/Makefile.am b/src/libs/pcp/Makefile.am
index b1724e9b5..fe6db4944 100644
--- a/src/libs/pcp/Makefile.am
+++ b/src/libs/pcp/Makefile.am
@@ -2,9 +2,10 @@ AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@
lib_LTLIBRARIES = libpcp.la
libpcp_la_SOURCES = pcp.c \
- pcp_stream.c \
+ pcp_stream.c \
md5.c \
- strlcpy.c
+ ../../utils/pool_path.c \
+ ../../utils/strlcpy.c
include_HEADERS = ../../../src/include/pcp/pcp.h \
../../../src/include/pcp/libpcp_ext.h \
@@ -17,9 +18,5 @@ md5.h: ../../../src/include/auth/md5.h
rm -f $@ && ln -s $< .
pcp_stream.c: ../../../src/utils/pcp/pcp_stream.c
rm -f $@ && ln -s $< .
-pcp_error.c: ../../../src/utils/pcp/pcp_error.c
- rm -f $@ && ln -s $< .
-pcp_timeout.c: ../../../src/utils/pcp/pcp_timeout.c
- rm -f $@ && ln -s $< .
strlcpy.c: ../../../src/utils/strlcpy.c
rm -f $@ && ln -s $< .
diff --git a/src/libs/pcp/Makefile.in b/src/libs/pcp/Makefile.in
index 83479204b..0bb1b573b 100644
--- a/src/libs/pcp/Makefile.in
+++ b/src/libs/pcp/Makefile.in
@@ -127,7 +127,9 @@ am__uninstall_files_from_dir = { \
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libpcp_la_LIBADD =
-am_libpcp_la_OBJECTS = pcp.lo pcp_stream.lo md5.lo strlcpy.lo
+am__dirstamp = $(am__leading_dot)dirstamp
+am_libpcp_la_OBJECTS = pcp.lo pcp_stream.lo md5.lo \
+ ../../utils/pool_path.lo ../../utils/strlcpy.lo
libpcp_la_OBJECTS = $(am_libpcp_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -325,9 +327,10 @@ top_srcdir = @top_srcdir@
AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@
lib_LTLIBRARIES = libpcp.la
libpcp_la_SOURCES = pcp.c \
- pcp_stream.c \
+ pcp_stream.c \
md5.c \
- strlcpy.c
+ ../../utils/pool_path.c \
+ ../../utils/strlcpy.c
include_HEADERS = ../../../src/include/pcp/pcp.h \
../../../src/include/pcp/libpcp_ext.h \
@@ -403,20 +406,33 @@ clean-libLTLIBRARIES:
echo rm -f $${locs}; \
rm -f $${locs}; \
}
+../../utils/$(am__dirstamp):
+ @$(MKDIR_P) ../../utils
+ @: > ../../utils/$(am__dirstamp)
+../../utils/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ../../utils/$(DEPDIR)
+ @: > ../../utils/$(DEPDIR)/$(am__dirstamp)
+../../utils/pool_path.lo: ../../utils/$(am__dirstamp) \
+ ../../utils/$(DEPDIR)/$(am__dirstamp)
+../../utils/strlcpy.lo: ../../utils/$(am__dirstamp) \
+ ../../utils/$(DEPDIR)/$(am__dirstamp)
libpcp.la: $(libpcp_la_OBJECTS) $(libpcp_la_DEPENDENCIES) $(EXTRA_libpcp_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libpcp_la_OBJECTS) $(libpcp_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
+ -rm -f ../../utils/*.$(OBJEXT)
+ -rm -f ../../utils/*.lo
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@../../utils/$(DEPDIR)/pool_path.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../utils/$(DEPDIR)/strlcpy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_stream.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -447,6 +463,7 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
+ -rm -rf ../../utils/.libs ../../utils/_libs
install-includeHEADERS: $(include_HEADERS)
@$(NORMAL_INSTALL)
@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
@@ -584,6 +601,8 @@ clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f ../../utils/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ../../utils/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -594,7 +613,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
- -rm -rf ./$(DEPDIR)
+ -rm -rf ../../utils/$(DEPDIR) ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -640,7 +659,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -rf ./$(DEPDIR)
+ -rm -rf ../../utils/$(DEPDIR) ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -684,10 +703,6 @@ md5.h: ../../../src/include/auth/md5.h
rm -f $@ && ln -s $< .
pcp_stream.c: ../../../src/utils/pcp/pcp_stream.c
rm -f $@ && ln -s $< .
-pcp_error.c: ../../../src/utils/pcp/pcp_error.c
- rm -f $@ && ln -s $< .
-pcp_timeout.c: ../../../src/utils/pcp/pcp_timeout.c
- rm -f $@ && ln -s $< .
strlcpy.c: ../../../src/utils/strlcpy.c
rm -f $@ && ln -s $< .
diff --git a/src/libs/pcp/pcp.c b/src/libs/pcp/pcp.c
index eb90894a5..cbd75bd2e 100644
--- a/src/libs/pcp/pcp.c
+++ b/src/libs/pcp/pcp.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
@@ -40,10 +41,14 @@
#include "pool.h"
#include "pcp/pcp.h"
#include "pcp/pcp_stream.h"
+#include "utils/pool_path.h"
#include "utils/palloc.h"
#include "utils/pool_process_reporting.h"
#include "auth/md5.h"
+#define PCPPASSFILE ".pcppass"
+#define DefaultHost "localhost"
+
static int pcp_authorize(PCPConnInfo* pcpConn, char *username, char *password);
@@ -74,6 +79,11 @@ static void setResultSlotCount(PCPConnInfo* pcpConn, unsigned int slotCount);
static void free_systemdb_info(struct PCPConnInfo* pcpConn, void *ptr);
static void free_processInfo(struct PCPConnInfo* pcpConn, void* ptr);
static int PCPFlush(PCPConnInfo* pcpConn);
+
+static bool getPoolPassFilename(char *pgpassfile);
+static char *PasswordFromFile(PCPConnInfo* pcpConn, char *hostname, char *port, char *username);
+static char *pwdfMatchesString(char *buf, char *token);
+
/* --------------------------------
* pcp_connect - open connection to pgpool using given arguments
*
@@ -91,6 +101,8 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde
struct sockaddr_in addr;
struct sockaddr_un unix_addr;
struct hostent *hp;
+ char *password_fron_file = NULL;
+ char os_user[256];
PCPConnInfo* pcpConn = palloc0(sizeof(PCPConnInfo));
int fd;
int on = 1;
@@ -120,6 +132,7 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde
if (hostname == NULL || *hostname == '\0')
{
path = UNIX_DOMAIN_PATH;
+ hostname = path;
}
else
{
@@ -200,6 +213,24 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde
}
pcpConn->connState = PCP_CONNECTION_CONNECTED;
+ /*
+ * If username is not provided. Use the os user name
+ * and do not complain if it (getting os user name) gets failed
+ */
+ if (username == NULL && get_os_username(os_user, sizeof(os_user)))
+ username = os_user;
+
+ /*
+ * If password is not provided. lookup in pcppass file
+ */
+ if (password == NULL || *password == '\0')
+ {
+ char port_str[100];
+ snprintf(port_str, sizeof(port_str), "%d",port);
+ password_fron_file = PasswordFromFile(pcpConn,(hostname == UNIX_DOMAIN_PATH)?DefaultHost:hostname, port_str, username);
+ password = password_fron_file;
+ }
+
if (pcp_authorize(pcpConn,username, password) < 0)
{
pcp_close(pcpConn->pcpConn);
@@ -209,6 +240,9 @@ pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfde
else
pcpConn->connState = PCP_CONNECTION_OK;
+ if(password_fron_file)
+ pfree(password_fron_file);
+
return pcpConn;
}
@@ -244,7 +278,13 @@ pcp_authorize(PCPConnInfo* pcpConn, char *username, char *password)
char md5[MD5_PASSWD_LEN+1];
PCPResultInfo* pcpRes;
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_CONNECTED)
+ if (password == NULL)
+ password = "";
+
+ if (username == NULL)
+ username = "";
+
+ if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_CONNECTED)
{
pcp_internal_error(pcpConn,
"ERROR: PCP authorization failed. invalid connection state.");
@@ -333,7 +373,7 @@ static PCPResultInfo* process_pcp_response(PCPConnInfo* pcpConn, char sentMsg)
}
if(pcpConn->Pfdebug)
- fprintf(pcpConn->Pfdebug, "DEBUG: recv: tos=\"%c\", len=%d, data=%s\n", toc, rsize, buf);
+ fprintf(pcpConn->Pfdebug, "DEBUG: recv: tos=\"%c\", len=%d\n", toc, rsize);
switch (toc) {
case 'r': /* Authentication Response */
@@ -1656,6 +1696,18 @@ int pcp_result_slot_count(PCPResultInfo* res)
return 0;
}
+/* Returns 1 if ResultInfo has no data. 0 otherwise */
+int pcp_result_is_empty(PCPResultInfo* res)
+{
+ if (res)
+ {
+ if (res->resultSlots <= 1 && res->resultSlot[0].isint == 0 && res->resultSlot[0].datalen <= 0)
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
void *pcp_get_binary_data(const PCPResultInfo *res, unsigned int slotno)
{
if(res && slotno < res->resultSlots && !res->resultSlot[slotno].isint)
@@ -1726,3 +1778,157 @@ char *pcp_get_last_error(PCPConnInfo* pcpConn)
return NULL;
}
+/*
+ * get the password file name which could be either pointed by PCPPASSFILE
+ * environment variable or resides in user home directory.
+ */
+static bool
+getPoolPassFilename(char *pgpassfile)
+{
+ char *passfile_env;
+
+ if ((passfile_env = getenv("PCPPASSFILE")) != NULL)
+ {
+ /* use the literal path from the environment, if set */
+ strlcpy(pgpassfile, passfile_env, MAXPGPATH);
+ }
+ else
+ {
+ char homedir[MAXPGPATH];
+ if (!get_home_directory(homedir, sizeof(homedir)))
+ return false;
+ snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PCPPASSFILE);
+ }
+ return true;
+}
+
+/*
+ * Get a password from the password file. Return value is malloc'd.
+ * format = hostname:port:username:password
+ */
+static char *
+PasswordFromFile(PCPConnInfo* pcpConn, char *hostname, char *port, char *username)
+{
+ FILE *fp;
+ char pgpassfile[MAXPGPATH];
+ struct stat stat_buf;
+#define LINELEN NAMEDATALEN*5
+ char buf[LINELEN];
+
+ if (username == NULL || strlen(username) == 0)
+ return NULL;
+
+ if (hostname == NULL)
+ hostname = DefaultHost;
+
+ if (!getPoolPassFilename(pgpassfile))
+ return NULL;
+
+ /* If password file cannot be opened, ignore it. */
+ if (stat(pgpassfile, &stat_buf) != 0)
+ return NULL;
+
+ if (!S_ISREG(stat_buf.st_mode))
+ {
+ if(pcpConn->Pfdebug)
+ fprintf(pcpConn->Pfdebug, "WARNING: password file \"%s\" is not a plain file\n",pgpassfile);
+ return NULL;
+ }
+
+ /* If password file is insecure, alert the user and ignore it. */
+ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+ {
+ if(pcpConn->Pfdebug)
+ fprintf(pcpConn->Pfdebug, "WARNING: password file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n",
+ pgpassfile);
+ return NULL;
+ }
+
+ fp = fopen(pgpassfile, "r");
+ if (fp == NULL)
+ return NULL;
+
+ while (!feof(fp) && !ferror(fp))
+ {
+ char *t = buf,
+ *ret,
+ *p1,
+ *p2;
+ int len;
+
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ break;
+
+ len = strlen(buf);
+ if (len == 0)
+ continue;
+
+ /* Remove trailing newline */
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = 0;
+
+ if ((t = pwdfMatchesString(t, hostname)) == NULL ||
+ (t = pwdfMatchesString(t, port)) == NULL ||
+ (t = pwdfMatchesString(t, username)) == NULL)
+ continue;
+ ret = pstrdup(t);
+ fclose(fp);
+
+ /* De-escape password. */
+ for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
+ {
+ if (*p1 == '\\' && p1[1] != '\0')
+ ++p1;
+ *p2 = *p1;
+ }
+ *p2 = '\0';
+
+ return ret;
+ }
+
+ fclose(fp);
+ return NULL;
+
+#undef LINELEN
+}
+
+/*
+ * Helper function for PasswordFromFile borrowed from PG
+ * returns a pointer to the next token or NULL if the current
+ * token doesn't match
+ */
+static char *
+pwdfMatchesString(char *buf, char *token)
+{
+ char *tbuf,
+ *ttok;
+ bool bslash = false;
+
+ if (buf == NULL || token == NULL)
+ return NULL;
+ tbuf = buf;
+ ttok = token;
+ if (tbuf[0] == '*' && tbuf[1] == ':')
+ return tbuf + 2;
+ while (*tbuf != 0)
+ {
+ if (*tbuf == '\\' && !bslash)
+ {
+ tbuf++;
+ bslash = true;
+ }
+ if (*tbuf == ':' && *ttok == 0 && !bslash)
+ return tbuf + 1;
+ bslash = false;
+ if (*ttok == 0)
+ return NULL;
+ if (*tbuf == *ttok)
+ {
+ tbuf++;
+ ttok++;
+ }
+ else
+ return NULL;
+ }
+ return NULL;
+}
diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c
index 7cd1317ef..54f1938bb 100644
--- a/src/pcp_con/pcp_worker.c
+++ b/src/pcp_con/pcp_worker.c
@@ -414,7 +414,7 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
index = (char *) memchr(buf, '\0', MAX_USER_PASSWD_LEN);
if (index == NULL)
{
- ereport(ERROR,
+ ereport(FATAL,
(errmsg("failed to authenticate PCP user"),
errdetail("error while reading authentication packet")));
return 0;
@@ -424,7 +424,7 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
fp = fopen(passwd_file, "r");
if (fp == NULL)
{
- ereport(ERROR,
+ ereport(FATAL,
(errmsg("failed to authenticate PCP user"),
errdetail("could not open %s. reason: %s", passwd_file, strerror(errno))));
return 0;
@@ -445,7 +445,7 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
if (++i > MAX_USER_PASSWD_LEN)
{
fclose(fp);
- ereport(ERROR,
+ ereport(FATAL,
(errmsg("failed to authenticate PCP user"),
errdetail("username read from file \"%s\" is larger than maximum allowed username length [%d]", passwd_file, MAX_USER_PASSWD_LEN)));
return 0;
@@ -465,7 +465,7 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
if (++i > MAX_USER_PASSWD_LEN)
{
fclose(fp);
- ereport(ERROR,
+ ereport(FATAL,
(errmsg("failed to authenticate PCP user"),
errdetail("password read from file \"%s\" is larger than maximum allowed password length [%d]", passwd_file, MAX_USER_PASSWD_LEN)));
return 0;
@@ -490,6 +490,10 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len)
}
}
fclose(fp);
+ ereport(FATAL,
+ (errmsg("authentication failed for user \"%s\"",packet_username),
+ errdetail("username and/or password does not match")));
+
return 0;
}
diff --git a/src/test/pgpool_setup b/src/test/pgpool_setup
index db58f7d96..1890f0754 100755
--- a/src/test/pgpool_setup
+++ b/src/test/pgpool_setup
@@ -91,6 +91,7 @@ PGPOOL_REMOTE_START_SCRIPT=pgpool_remote_start
STARTALL=$BASEDIR/startall
# Shutdown script name. This will be generated in this script.
SHUTDOWNALL=$BASEDIR/shutdownall
+PCP_PASS_FILE=$BASEDIR/pcppass
# pgpool reload script name. This will be generated in this script.
PGPOOL_RELOAD=$BASEDIR/pgpool_reload
@@ -188,7 +189,7 @@ cluster0=$mydir/data0
cluster1=$mydir/data1
cluster2=$mydir/data2
PCP_PORT=__PCPPORT__
-pcp_super_user=__PCPSUPERUSER__
+export PCPPASSFILE=__PCPPASSFILE__
date >> $log
echo "failed_node_id $failed_node_id failed_host_name $failed_host_name failed_port $failed_port failed_db_cluster $failed_db_cluster new_master_id $new_master_id old_master_id $old_master_id new_master_host_name $new_master_host_name old_primary_node_id $old_primary_node_id new_master_port_number $new_master_port_number new_master_db_cluster $new_master_db_cluster" >> $log
@@ -199,7 +200,7 @@ then
$pg_ctl -w -m f -D $failed_db_cluster stop >> $log 2>&1
sleep 10
# recovery the node
- pcp_recovery_node localhost $PCP_PORT $pcp_super_user $pcp_super_user $failed_node_id >> $log 2>&1
+ pcp_recovery_node -w -h localhost -p $PCP_PORT -n $failed_node_id >> $log 2>&1
else
echo "$failed_db_cluster is not running. skipping follow master command." >> $log
fi
@@ -208,10 +209,11 @@ EOF
#-------------------------------------------
# replace some variables in the script
#-------------------------------------------
+
/bin/ed $FOLLOW_MASTER_SCRIPT <<EOF
/__MYDIR__/s@__MYDIR__@$BASEDIR@
/__PGBIN__/s@__PGBIN__@$PGBIN@
-/__PCPSUPERUSER__/s/__PCPSUPERUSER__/$WHOAMI/
+/__PCPPASSFILE__/s@__PCPPASSFILE__@$PCP_PASS_FILE@
/__PCPPORT__/s/__PCPPORT__/$PCP_PORT/
w
q
@@ -702,6 +704,12 @@ echo "port = $PGPOOL_PORT" >> $CONF
PCP_PORT=`expr $PGPOOL_PORT + 1`
echo "pcp_port = $PCP_PORT" >> $CONF
+#-------------------------------------------
+# create password file for pcp
+#-------------------------------------------
+echo "localhost:${PCP_PORT}:${WHOAMI}:${WHOAMI}" >> $PCP_PASS_FILE
+chmod 0600 $PCP_PASS_FILE
+
test ! -d run && mkdir run
echo "pid_file_name = '$BASEDIR/run/pgpool.pid'" >> $CONF
test ! -d log && mkdir log
@@ -772,13 +780,13 @@ EOF
wait_for_pgpool_reload $NUMCLUSTERS
$PSQL -p $PGPOOL_PORT -c "show pool_nodes" test
-
+export PCPPASSFILE=$PCP_PASS_FILE
# recovery data1 and so on
n=1
while [ $n -lt $NUMCLUSTERS ]
do
echo -n "recovery node $n..."
- $PGPOOL_INSTALL_DIR/bin/pcp_recovery_node localhost $PCP_PORT $WHOAMI $WHOAMI $n
+ $PGPOOL_INSTALL_DIR/bin/pcp_recovery_node -w -h localhost -p $PCP_PORT -n $n
echo "done."
n=`expr $n + 1`
if [ $n -lt $NUMCLUSTERS ];then
@@ -849,6 +857,7 @@ fi
echo "export PGPOOL_PORT=$PGPOOL_PORT" > bashrc.ports
echo "export PCP_PORT=$PCP_PORT" >> bashrc.ports
+echo "export PCPPASSFILE=$PCP_PASS_FILE" >> bashrc.ports
chmod 755 bashrc.ports
echo
diff --git a/src/test/regression/tests/054.postgres_fdw/test.sh b/src/test/regression/tests/054.postgres_fdw/test.sh
index dfa977d77..2923b8aa5 100755
--- a/src/test/regression/tests/054.postgres_fdw/test.sh
+++ b/src/test/regression/tests/054.postgres_fdw/test.sh
@@ -43,7 +43,7 @@ EOF
# detach node #1 so that pgpool does not access
# postgres_fdw. Otherwise it will go into an inifinite loop.
-$PGPOOL_INSTALL_DIR/bin/pcp_detach_node localhost $PCP_PORT $WHOAMI $WHOAMI 1
+$PGPOOL_INSTALL_DIR/bin/pcp_detach_node -w -h localhost -p $PCP_PORT -n 1
if [ $? != 0 ];then
echo "pcp_detach_node failed"
diff --git a/src/tools/pcp/Makefile.am b/src/tools/pcp/Makefile.am
index 0df4ad318..b63a96920 100644
--- a/src/tools/pcp/Makefile.am
+++ b/src/tools/pcp/Makefile.am
@@ -13,28 +13,31 @@ bin_PROGRAMS = pcp_stop_pgpool \
pcp_promote_node \
pcp_pool_status \
pcp_watchdog_info
-pcp_stop_pgpool_SOURCES = pcp_stop_pgpool.c ../fe_memutils.c
+
+client_sources = pcp_frontend_client.c ../fe_memutils.c ../../utils/sprompt.c ../../utils/pool_path.c
+
+pcp_stop_pgpool_SOURCES = $(client_sources)
pcp_stop_pgpool_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_node_count_SOURCES = pcp_node_count.c ../fe_memutils.c
+pcp_node_count_SOURCES = $(client_sources)
pcp_node_count_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_node_info_SOURCES = pcp_node_info.c ../fe_memutils.c
+pcp_node_info_SOURCES = $(client_sources)
pcp_node_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_proc_count_SOURCES = pcp_proc_count.c ../fe_memutils.c
+pcp_proc_count_SOURCES = $(client_sources)
pcp_proc_count_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_proc_info_SOURCES = pcp_proc_info.c ../fe_memutils.c
+pcp_proc_info_SOURCES = $(client_sources)
pcp_proc_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_systemdb_info_SOURCES = pcp_systemdb_info.c ../fe_memutils.c
+pcp_systemdb_info_SOURCES = $(client_sources)
pcp_systemdb_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_detach_node_SOURCES = pcp_detach_node.c ../fe_memutils.c
+pcp_detach_node_SOURCES = $(client_sources)
pcp_detach_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_attach_node_SOURCES = pcp_attach_node.c ../fe_memutils.c
+pcp_attach_node_SOURCES = $(client_sources)
pcp_attach_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_recovery_node_SOURCES = pcp_recovery_node.c ../fe_memutils.c
+pcp_recovery_node_SOURCES = $(client_sources)
pcp_recovery_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_pool_status_SOURCES = pcp_pool_status.c ../fe_memutils.c
+pcp_pool_status_SOURCES = $(client_sources)
pcp_pool_status_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_promote_node_SOURCES = pcp_promote_node.c ../fe_memutils.c
+pcp_promote_node_SOURCES = $(client_sources)
pcp_promote_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_watchdog_info_SOURCES = pcp_watchdog_info.c ../fe_memutils.c
+pcp_watchdog_info_SOURCES = $(client_sources)
pcp_watchdog_info_LDADD = $(libs_dir)/pcp/libpcp.la
diff --git a/src/tools/pcp/Makefile.in b/src/tools/pcp/Makefile.in
index 74a211864..2362217bb 100644
--- a/src/tools/pcp/Makefile.in
+++ b/src/tools/pcp/Makefile.in
@@ -104,56 +104,46 @@ CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am__dirstamp = $(am__leading_dot)dirstamp
-am_pcp_attach_node_OBJECTS = pcp_attach_node.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am__objects_1 = pcp_frontend_client.$(OBJEXT) ../fe_memutils.$(OBJEXT) \
+ ../../utils/sprompt.$(OBJEXT) ../../utils/pool_path.$(OBJEXT)
+am_pcp_attach_node_OBJECTS = $(am__objects_1)
pcp_attach_node_OBJECTS = $(am_pcp_attach_node_OBJECTS)
pcp_attach_node_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
-am_pcp_detach_node_OBJECTS = pcp_detach_node.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_detach_node_OBJECTS = $(am__objects_1)
pcp_detach_node_OBJECTS = $(am_pcp_detach_node_OBJECTS)
pcp_detach_node_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_node_count_OBJECTS = pcp_node_count.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_node_count_OBJECTS = $(am__objects_1)
pcp_node_count_OBJECTS = $(am_pcp_node_count_OBJECTS)
pcp_node_count_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_node_info_OBJECTS = pcp_node_info.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_node_info_OBJECTS = $(am__objects_1)
pcp_node_info_OBJECTS = $(am_pcp_node_info_OBJECTS)
pcp_node_info_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_pool_status_OBJECTS = pcp_pool_status.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_pool_status_OBJECTS = $(am__objects_1)
pcp_pool_status_OBJECTS = $(am_pcp_pool_status_OBJECTS)
pcp_pool_status_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_proc_count_OBJECTS = pcp_proc_count.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_proc_count_OBJECTS = $(am__objects_1)
pcp_proc_count_OBJECTS = $(am_pcp_proc_count_OBJECTS)
pcp_proc_count_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_proc_info_OBJECTS = pcp_proc_info.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_proc_info_OBJECTS = $(am__objects_1)
pcp_proc_info_OBJECTS = $(am_pcp_proc_info_OBJECTS)
pcp_proc_info_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_promote_node_OBJECTS = pcp_promote_node.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_promote_node_OBJECTS = $(am__objects_1)
pcp_promote_node_OBJECTS = $(am_pcp_promote_node_OBJECTS)
pcp_promote_node_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_recovery_node_OBJECTS = pcp_recovery_node.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_recovery_node_OBJECTS = $(am__objects_1)
pcp_recovery_node_OBJECTS = $(am_pcp_recovery_node_OBJECTS)
pcp_recovery_node_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_stop_pgpool_OBJECTS = pcp_stop_pgpool.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_stop_pgpool_OBJECTS = $(am__objects_1)
pcp_stop_pgpool_OBJECTS = $(am_pcp_stop_pgpool_OBJECTS)
pcp_stop_pgpool_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_systemdb_info_OBJECTS = pcp_systemdb_info.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_systemdb_info_OBJECTS = $(am__objects_1)
pcp_systemdb_info_OBJECTS = $(am_pcp_systemdb_info_OBJECTS)
pcp_systemdb_info_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
-am_pcp_watchdog_info_OBJECTS = pcp_watchdog_info.$(OBJEXT) \
- ../fe_memutils.$(OBJEXT)
+am_pcp_watchdog_info_OBJECTS = $(am__objects_1)
pcp_watchdog_info_OBJECTS = $(am_pcp_watchdog_info_OBJECTS)
pcp_watchdog_info_DEPENDENCIES = $(libs_dir)/pcp/libpcp.la
AM_V_P = $(am__v_P_@AM_V@)
@@ -356,29 +346,30 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
libs_dir = $(top_srcdir)/src/libs
AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@
-pcp_stop_pgpool_SOURCES = pcp_stop_pgpool.c ../fe_memutils.c
+client_sources = pcp_frontend_client.c ../fe_memutils.c ../../utils/sprompt.c ../../utils/pool_path.c
+pcp_stop_pgpool_SOURCES = $(client_sources)
pcp_stop_pgpool_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_node_count_SOURCES = pcp_node_count.c ../fe_memutils.c
+pcp_node_count_SOURCES = $(client_sources)
pcp_node_count_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_node_info_SOURCES = pcp_node_info.c ../fe_memutils.c
+pcp_node_info_SOURCES = $(client_sources)
pcp_node_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_proc_count_SOURCES = pcp_proc_count.c ../fe_memutils.c
+pcp_proc_count_SOURCES = $(client_sources)
pcp_proc_count_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_proc_info_SOURCES = pcp_proc_info.c ../fe_memutils.c
+pcp_proc_info_SOURCES = $(client_sources)
pcp_proc_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_systemdb_info_SOURCES = pcp_systemdb_info.c ../fe_memutils.c
+pcp_systemdb_info_SOURCES = $(client_sources)
pcp_systemdb_info_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_detach_node_SOURCES = pcp_detach_node.c ../fe_memutils.c
+pcp_detach_node_SOURCES = $(client_sources)
pcp_detach_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_attach_node_SOURCES = pcp_attach_node.c ../fe_memutils.c
+pcp_attach_node_SOURCES = $(client_sources)
pcp_attach_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_recovery_node_SOURCES = pcp_recovery_node.c ../fe_memutils.c
+pcp_recovery_node_SOURCES = $(client_sources)
pcp_recovery_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_pool_status_SOURCES = pcp_pool_status.c ../fe_memutils.c
+pcp_pool_status_SOURCES = $(client_sources)
pcp_pool_status_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_promote_node_SOURCES = pcp_promote_node.c ../fe_memutils.c
+pcp_promote_node_SOURCES = $(client_sources)
pcp_promote_node_LDADD = $(libs_dir)/pcp/libpcp.la
-pcp_watchdog_info_SOURCES = pcp_watchdog_info.c ../fe_memutils.c
+pcp_watchdog_info_SOURCES = $(client_sources)
pcp_watchdog_info_LDADD = $(libs_dir)/pcp/libpcp.la
all: all-am
@@ -471,6 +462,16 @@ clean-binPROGRAMS:
@: > ../$(DEPDIR)/$(am__dirstamp)
../fe_memutils.$(OBJEXT): ../$(am__dirstamp) \
../$(DEPDIR)/$(am__dirstamp)
+../../utils/$(am__dirstamp):
+ @$(MKDIR_P) ../../utils
+ @: > ../../utils/$(am__dirstamp)
+../../utils/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ../../utils/$(DEPDIR)
+ @: > ../../utils/$(DEPDIR)/$(am__dirstamp)
+../../utils/sprompt.$(OBJEXT): ../../utils/$(am__dirstamp) \
+ ../../utils/$(DEPDIR)/$(am__dirstamp)
+../../utils/pool_path.$(OBJEXT): ../../utils/$(am__dirstamp) \
+ ../../utils/$(DEPDIR)/$(am__dirstamp)
pcp_attach_node$(EXEEXT): $(pcp_attach_node_OBJECTS) $(pcp_attach_node_DEPENDENCIES) $(EXTRA_pcp_attach_node_DEPENDENCIES)
@rm -f pcp_attach_node$(EXEEXT)
@@ -523,23 +524,15 @@ pcp_watchdog_info$(EXEEXT): $(pcp_watchdog_info_OBJECTS) $(pcp_watchdog_info_DEP
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f ../*.$(OBJEXT)
+ -rm -f ../../utils/*.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@../$(DEPDIR)/fe_memutils.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_attach_node.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_detach_node.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_node_count.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_node_info.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_pool_status.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_proc_count.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_proc_info.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_promote_node.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_recovery_node.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_stop_pgpool.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_systemdb_info.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_watchdog_info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../utils/$(DEPDIR)/pool_path.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../utils/$(DEPDIR)/sprompt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_frontend_client.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -688,6 +681,8 @@ distclean-generic:
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-rm -f ../$(DEPDIR)/$(am__dirstamp)
-rm -f ../$(am__dirstamp)
+ -rm -f ../../utils/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ../../utils/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -697,7 +692,7 @@ clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
- -rm -rf ../$(DEPDIR) ./$(DEPDIR)
+ -rm -rf ../$(DEPDIR) ../../utils/$(DEPDIR) ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -743,7 +738,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -rf ../$(DEPDIR) ./$(DEPDIR)
+ -rm -rf ../$(DEPDIR) ../../utils/$(DEPDIR) ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/src/tools/pcp/pcp_attach_node.c b/src/tools/pcp/pcp_attach_node.c
deleted file mode 100644
index 55686aec8..000000000
--- a/src/tools/pcp/pcp_attach_node.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "attach node" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int nodeID;
- int ch;
- int optindex;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- nodeID = atoi(argv[4]);
- if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_attach_node(pcpConn,nodeID);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_attach_node - attach a node from pgpool-II\n\n");
- fprintf(stderr, "Usage: pcp_attach_node [-d] hostname port# username password nodeID\n");
- fprintf(stderr, "Usage: pcp_attach_node -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " nodeID : ID of a node to be attached\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_detach_node.c b/src/tools/pcp/pcp_detach_node.c
deleted file mode 100644
index 5aca3d990..000000000
--- a/src/tools/pcp/pcp_detach_node.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2010 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "detach node" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int nodeID;
- int ch;
- int optindex;
- bool gracefully = false;
- bool debug = 0;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"gracefully", no_argument, NULL, 'g'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hdg", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'g':
- gracefully = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- nodeID = atoi(argv[4]);
- if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- if (gracefully)
- pcpResInfo = pcp_detach_node_gracefully(pcpConn,nodeID);
- else
- pcpResInfo = pcp_detach_node(pcpConn,nodeID);
-
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_detach_node - detach a node from pgpool-II\n\n");
- fprintf(stderr, "Usage: pcp_detach_node [-d][-g] hostname port# username password nodeID\n");
- fprintf(stderr, "Usage: pcp_detach_node -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " -g, --gracefully : detach gracefully(optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " nodeID : ID of a node to be detached\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
-
diff --git a/src/tools/pcp/pcp_frontend_client.c b/src/tools/pcp/pcp_frontend_client.c
new file mode 100644
index 000000000..bee9b7e0b
--- /dev/null
+++ b/src/tools/pcp/pcp_frontend_client.c
@@ -0,0 +1,775 @@
+/*
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2015 PgPool Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * PCP client program to execute pcp commands.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "utils/fe_ports.h"
+#include "utils/pool_path.h"
+#include "pcp/pcp.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "utils/getopt_long.h"
+#endif
+
+const char* progname = NULL;
+const char * get_progname(const char *argv0);
+char *last_dir_separator(const char *filename);
+
+static void usage(void);
+static inline bool app_require_nodeID(void);
+static void output_ststemdb_info_result(PCPResultInfo* pcpResInfo, bool verbose);
+static void output_watchdog_info_result(PCPResultInfo* pcpResInfo, bool verbose);
+static void output_procinfo_result(PCPResultInfo* pcpResInfo, bool all, bool verbose);
+static void output_proccount_result(PCPResultInfo* pcpResInfo, bool verbose);
+static void output_poolstatus_result(PCPResultInfo* pcpResInfo, bool verbose);
+static void output_nodeinfo_result(PCPResultInfo* pcpResInfo, bool verbose);
+static void output_nodecount_result(PCPResultInfo* pcpResInfo, bool verbose);
+
+typedef enum
+{
+ PCP_ATTACH_NODE,
+ PCP_DETACH_NODE,
+ PCP_NODE_COUNT,
+ PCP_NODE_INFO,
+ PCP_POOL_STATUS,
+ PCP_PROC_COUNT,
+ PCP_PROC_INFO,
+ PCP_PROMOTE_NODE,
+ PCP_RECOVERY_NODE,
+ PCP_STOP_PGPOOL,
+ PCP_SYSTEMDB_INFO,
+ PCP_WATCHDOG_INFO,
+ UNKNOWN,
+} PCP_UTILITIES;
+
+struct AppTypes
+{
+ const char *app_name;
+ PCP_UTILITIES app_type;
+ const char* allowed_options;
+ const char* description;
+};
+
+struct AppTypes AllAppTypes[] =
+ {
+ {"pcp_attach_node", PCP_ATTACH_NODE,"n:h:p:U:wWvd","attach a node from pgpool-II"},
+ {"pcp_detach_node", PCP_DETACH_NODE,"n:h:p:U:gwWvd","detach a node from pgpool-II"},
+ {"pcp_node_count", PCP_NODE_COUNT,"h:p:U:wWvd","display the total number of nodes under pgpool-II's control"},
+ {"pcp_node_info", PCP_NODE_INFO,"n:h:p:U:wWvd", "display a pgpool-II node's information"},
+ {"pcp_pool_status", PCP_POOL_STATUS,"h:p:U:wWvd", "display pgpool configuration and status"},
+ {"pcp_proc_count", PCP_PROC_COUNT,"h:p:U:wWvd", "display the list of pgpool-II child process PIDs"},
+ {"pcp_proc_info", PCP_PROC_INFO,"h:p:P:U:awWvd","display a pgpool-II child process' information"},
+ {"pcp_promote_node", PCP_PROMOTE_NODE,"n:h:p:U:gwWvd", "promote a node as new master from pgpool-II"},
+ {"pcp_recovery_node", PCP_RECOVERY_NODE,"n:h:p:U:wWvd","recover a node"},
+ {"pcp_stop_pgpool", PCP_STOP_PGPOOL,"m:h:p:U:wWvd", "terminate pgpool-II"},
+ {"pcp_systemdb_info", PCP_SYSTEMDB_INFO,"h:p:U:wWvd", "display the pgpool-II systemDB information"},
+ {"pcp_watchdog_info", PCP_WATCHDOG_INFO,"n:h:p:U:wWvd", "display a pgpool-II watchdog's information"},
+ {NULL, UNKNOWN,NULL,NULL},
+ };
+struct AppTypes* current_app_type;
+
+int
+main(int argc, char **argv)
+{
+ char* host = NULL;
+ int port = 9898;
+ char* user = NULL;
+ char* pass = NULL;
+ int nodeID = -1;
+ int processID = 0;
+ int ch;
+ char shutdown_mode = 's';
+ int optindex;
+ int i;
+ bool all = false;
+ bool debug = false;
+ bool need_password = true;
+ bool gracefully = false;
+ bool verbose = false;
+ PCPConnInfo* pcpConn;
+ PCPResultInfo* pcpResInfo;
+
+ /* here we put all the allowed long options for all utilities */
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, '?'},
+ {"debug", no_argument, NULL, 'd'},
+ {"version", no_argument, NULL, 'V'},
+ {"host", required_argument, NULL, 'h'},
+ {"port", required_argument, NULL, 'p'},
+ {"process-id", required_argument, NULL, 'P'},
+ {"username", required_argument, NULL, 'U'},
+ {"no-password", no_argument, NULL, 'w'},
+ {"password", no_argument, NULL, 'W'},
+ {"mode", required_argument, NULL, 'm'},
+ {"gracefully", no_argument, NULL, 'g'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"all", no_argument, NULL, 'a'},
+ {"node-id", required_argument, NULL, 'n'},
+ {"watchdog-id", required_argument, NULL, 'n'},
+ {NULL, 0, NULL, 0}
+ };
+
+ /* Identify the utility app */
+ progname = get_progname(argv[0]);
+ for( i =0; ;i++)
+ {
+ current_app_type = &AllAppTypes[i];
+ if(current_app_type->app_type == UNKNOWN)
+ break;
+ if (strcmp(current_app_type->app_name, progname) == 0)
+ break;
+ }
+
+ if(current_app_type->app_type == UNKNOWN)
+ {
+ fprintf(stderr, "%s is a invalid PCP utility\n",progname);
+ exit(1);
+ }
+
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+ {
+ usage();
+ exit(0);
+ }
+ else if (strcmp(argv[1], "-V") == 0
+ || strcmp(argv[1], "--version") == 0)
+ {
+ fprintf(stderr, "%s (%s) %s\n",progname,PACKAGE, VERSION);
+ exit(0);
+ }
+ }
+
+ while ((ch = getopt_long(argc, argv, current_app_type->allowed_options, long_options, &optindex)) != -1) {
+ switch (ch)
+ {
+ case 'd':
+ debug = true;
+ break;
+
+ case 'a':
+ all = true;
+ break;
+
+ case 'w':
+ need_password = false;
+ break;
+
+ case 'W':
+ need_password = true;
+ break;
+
+ case 'g':
+ gracefully = true;
+ break;
+
+ case 'm':
+ if (current_app_type->app_type == PCP_STOP_PGPOOL)
+ {
+ if (strcmp(optarg, "s") == 0 || strcmp(optarg, "smart") == 0)
+ shutdown_mode = 's';
+ else if (strcmp(optarg, "f") == 0 || strcmp(optarg, "fast") == 0)
+ shutdown_mode = 'f';
+ else if (strcmp(optarg, "i") == 0 || strcmp(optarg, "immediate") == 0)
+ shutdown_mode = 'i';
+ else
+ {
+ fprintf(stderr, "%s: Invalid shutdown mode \"%s\", must be either \"smart\" \"immediate\" or \"fast\" \n",progname,optarg);
+ exit(1);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Invalid argument \"%s\", Try \"%s --help\" for more information.\n",optarg,progname);
+ exit(1);
+ }
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'n':
+ nodeID = atoi(optarg);
+ if (current_app_type->app_type == PCP_WATCHDOG_INFO)
+ {
+ if (nodeID < 0 || nodeID > MAX_WATCHDOG_NUM)
+ {
+ fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_WATCHDOG_NUM);
+ exit(0);
+ }
+ }
+ else
+ {
+ if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
+ {
+ fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS);
+ exit(0);
+ }
+ }
+ break;
+
+ case 'p':
+ port = atoi(optarg);
+ if (port <= 1024 || port > 65535)
+ {
+ fprintf(stderr, "%s: Invalid port number \"%s\", must be between 1024 and 65535\n",progname,optarg);
+ exit(0);
+ }
+ break;
+
+ case 'P': /* PID */
+ processID = atoi(optarg);
+ if (processID <= 0 )
+ {
+ fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg);
+ exit(0);
+ }
+ break;
+
+ case 'h':
+ host = strdup(optarg);
+ break;
+
+ case 'U':
+ user = strdup(optarg);
+ break;
+
+ case '?':
+ default:
+ /*
+ * getopt_long whould already have emitted a complaint
+ */
+ fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname);
+ exit(1);
+ }
+ }
+
+ /*
+ * if we still have arguments, use it
+ */
+ while (argc - optind >= 1)
+ {
+ if (current_app_type->app_type == PCP_PROC_INFO && processID <= 0)
+ {
+ processID = atoi(argv[optind]);
+ if (processID <= 0 )
+ {
+ fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg);
+ exit(0);
+ }
+ }
+ else if (current_app_type->app_type == PCP_WATCHDOG_INFO && nodeID < 0)
+ {
+ nodeID = atoi(argv[optind]);
+ if (nodeID < 0 || nodeID > MAX_WATCHDOG_NUM)
+ {
+ fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_WATCHDOG_NUM);
+ exit(0);
+ }
+ }
+ else if (app_require_nodeID() && nodeID < 0)
+ {
+ nodeID = atoi(argv[optind]);
+ if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
+ {
+ fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS);
+ exit(0);
+ }
+ }
+ else
+ fprintf(stderr, "%s: Warning: extra command-line argument \"%s\" ignored\n",
+ progname, argv[optind]);
+
+ optind++;
+ }
+
+ if(nodeID < 0)
+ {
+ if (app_require_nodeID())
+ {
+ fprintf(stderr, "%s: missing node-id\n",progname);
+ fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname);
+ exit(1);
+ }
+ else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
+ {
+ nodeID = 0;
+ }
+ }
+
+ /* Get a new password if appropriate */
+ if (need_password)
+ {
+ pass = simple_prompt("Password: ", 100, false);
+ need_password = false;
+ }
+
+ pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
+ if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
+ {
+ fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
+ exit(1);
+ }
+
+ /*
+ * Okay the connection is successful not call the actual PCP function
+ */
+ if (current_app_type->app_type == PCP_ATTACH_NODE)
+ {
+ pcpResInfo = pcp_attach_node(pcpConn,nodeID);
+ }
+
+ else if (current_app_type->app_type == PCP_DETACH_NODE)
+ {
+ if (gracefully)
+ pcpResInfo = pcp_detach_node_gracefully(pcpConn,nodeID);
+ else
+ pcpResInfo = pcp_detach_node(pcpConn,nodeID);
+ }
+
+ else if (current_app_type->app_type == PCP_NODE_COUNT)
+ {
+ pcpResInfo = pcp_node_count(pcpConn);
+ }
+
+ else if (current_app_type->app_type == PCP_NODE_INFO)
+ {
+ pcpResInfo = pcp_node_info(pcpConn,nodeID);
+ }
+
+ else if (current_app_type->app_type == PCP_POOL_STATUS)
+ {
+ pcpResInfo = pcp_pool_status(pcpConn);
+ }
+
+ else if (current_app_type->app_type == PCP_PROC_COUNT)
+ {
+ pcpResInfo = pcp_process_count(pcpConn);
+ }
+
+ else if (current_app_type->app_type == PCP_PROC_INFO)
+ {
+ pcpResInfo = pcp_process_info(pcpConn, processID);
+ }
+
+ else if (current_app_type->app_type == PCP_PROMOTE_NODE)
+ {
+ if (gracefully)
+ pcpResInfo = pcp_promote_node_gracefully(pcpConn,nodeID);
+ else
+ pcpResInfo = pcp_promote_node(pcpConn,nodeID);
+ }
+
+ else if (current_app_type->app_type == PCP_RECOVERY_NODE)
+ {
+ pcpResInfo = pcp_recovery_node(pcpConn, nodeID);
+ }
+
+ else if (current_app_type->app_type == PCP_STOP_PGPOOL)
+ {
+ pcpResInfo = pcp_terminate_pgpool(pcpConn, shutdown_mode);
+ }
+
+ else if (current_app_type->app_type == PCP_SYSTEMDB_INFO)
+ {
+ pcpResInfo = pcp_systemdb_info(pcpConn);
+ }
+
+ else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
+ {
+ pcpResInfo = pcp_watchdog_info(pcpConn,nodeID);
+ }
+
+ else
+ {
+ /* should never happen */
+ fprintf(stderr,"%s: Invalid pcp process\n",progname);
+ goto DISCONNECT_AND_EXIT;
+ }
+
+ if(pcpResInfo == NULL || PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
+ {
+ fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
+ goto DISCONNECT_AND_EXIT;
+ }
+
+ if (pcp_result_is_empty(pcpResInfo))
+ {
+ fprintf(stdout,"%s -- Command Successful\n",progname);
+ }
+ else
+ {
+ if (current_app_type->app_type == PCP_NODE_COUNT)
+ output_nodecount_result(pcpResInfo, verbose);
+
+ if (current_app_type->app_type == PCP_NODE_INFO)
+ output_nodeinfo_result(pcpResInfo, verbose);
+
+ if (current_app_type->app_type == PCP_POOL_STATUS)
+ output_poolstatus_result(pcpResInfo, verbose);
+
+ if (current_app_type->app_type == PCP_PROC_COUNT)
+ output_proccount_result(pcpResInfo, verbose);
+
+ if (current_app_type->app_type == PCP_PROC_INFO)
+ output_procinfo_result(pcpResInfo, all, verbose);
+
+ else if (current_app_type->app_type == PCP_SYSTEMDB_INFO)
+ output_ststemdb_info_result(pcpResInfo, verbose);
+
+ else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
+ output_watchdog_info_result(pcpResInfo, verbose);
+ }
+
+DISCONNECT_AND_EXIT:
+
+ pcp_disconnect(pcpConn);
+ pcp_free_connection(pcpConn);
+
+ return 0;
+}
+
+static void
+output_nodecount_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ if(verbose)
+ {
+ printf("Node Count\n");
+ printf("____________\n");
+ printf(" %d\n", pcp_get_int_data(pcpResInfo, 0));
+ }
+ else
+ printf("%d\n", pcp_get_int_data(pcpResInfo, 0));
+}
+
+static void
+output_nodeinfo_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ BackendInfo *backend_info = (BackendInfo *) pcp_get_binary_data(pcpResInfo,0);
+
+ if (verbose)
+ {
+ printf("Hostname: %s\nPort : %d\nStatus : %d\nWeight : %f\n",
+ backend_info->backend_hostname,
+ backend_info->backend_port,
+ backend_info->backend_status,
+ backend_info->backend_weight/RAND_MAX);
+ } else {
+ printf("%s %d %d %f\n",
+ backend_info->backend_hostname,
+ backend_info->backend_port,
+ backend_info->backend_status,
+ backend_info->backend_weight/RAND_MAX);
+ }
+}
+
+static void
+output_poolstatus_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ POOL_REPORT_CONFIG *status;
+ int i;
+ int array_size = pcp_result_slot_count(pcpResInfo);
+
+ if(verbose)
+ {
+ for (i=0; i < array_size; i++)
+ {
+ status = (POOL_REPORT_CONFIG *)pcp_get_binary_data(pcpResInfo, i);
+ printf("Name [%3d]:\t%s\n",i,status?status->name:"NULL");
+ printf("Value: \t%s\n",status?status->value:"NULL");
+ printf("Description:\t%s\n\n",status?status->desc:"NULL");
+ }
+ }
+ else
+ {
+ for (i=0; i < array_size; i++) {
+ status = (POOL_REPORT_CONFIG *)pcp_get_binary_data(pcpResInfo, i);
+ if(status == NULL)
+ {
+ printf("****Data at %d slot is NULL\n",i);
+ continue;
+ }
+ printf("name : %s\nvalue: %s\ndesc : %s\n\n", status->name, status->value, status->desc);
+ }
+ }
+}
+
+static void
+output_proccount_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ int i;
+ int process_count = pcp_get_data_length(pcpResInfo, 0) / sizeof(int);
+ int *process_list = (int *)pcp_get_binary_data(pcpResInfo, 0);
+
+ if (verbose)
+ {
+ printf("No \t | \t PID\n");
+ printf("_____________________\n");
+ for (i = 0; i < process_count; i++)
+ printf("%d \t | \t %d\n", i,process_list[i]);
+ printf("\nTotal Processes:%d\n",process_count);
+ }
+ else
+ {
+ for (i = 0; i < process_count; i++)
+ printf("%d ", process_list[i]);
+ printf("\n");
+ }
+}
+
+static void
+output_procinfo_result(PCPResultInfo* pcpResInfo, bool all, bool verbose)
+{
+ bool printed = false;
+ int i;
+ char * frmt;
+ char strcreatetime[128];
+ char strstarttime[128];
+ int array_size = pcp_result_slot_count(pcpResInfo);
+ if (verbose)
+ {
+ if (all)
+ frmt = "Database : %s\n"
+ "Username : %s\n"
+ "Start time : %s\n"
+ "Creation time: %s\n"
+ "Major : %d\n"
+ "Minor : %d\n"
+ "Counter : %d\n"
+ "Backend PID : %d\n"
+ "Connected : %d\n"
+ "PID : %d\n"
+ "Backend ID : %d\n";
+ else
+ frmt = "Database : %s\n"
+ "Username : %s\n"
+ "Start time : %s\n"
+ "Creation time: %s\n"
+ "Major : %d\n"
+ "Minor : %d\n"
+ "Counter : %d\n"
+ "Backend PID : %d\n"
+ "Connected : %d\n";
+ }
+ else
+ {
+ if (all)
+ frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
+ else
+ frmt = "%s %s %s %s %d %d %d %d %d\n";
+ }
+
+ for (i = 0; i < array_size; i++)
+ {
+
+ ProcessInfo *process_info = (ProcessInfo*) pcp_get_binary_data(pcpResInfo, i);
+ if(process_info == NULL)
+ break;
+ if ((!all) && (process_info->connection_info->database[0] == '\0'))
+ continue;
+ printed = true;
+ *strcreatetime = *strstarttime = '\0';
+
+ if (process_info->start_time)
+ strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
+ if (process_info->connection_info->create_time)
+ strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
+
+ printf(frmt,
+ process_info->connection_info->database,
+ process_info->connection_info->user,
+ strstarttime,
+ strcreatetime,
+ process_info->connection_info->major,
+ process_info->connection_info->minor,
+ process_info->connection_info->counter,
+ process_info->connection_info->pid,
+ process_info->connection_info->connected,
+ process_info->pid,
+ process_info->connection_info->backend_id);
+ }
+ if(printed == false)
+ printf("No process information available\n\n");
+}
+
+static void
+output_ststemdb_info_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ int i,j;
+ SystemDBInfo* systemdb_info = (SystemDBInfo *)pcp_get_binary_data(pcpResInfo, 0);
+ printf("%s %d %s %s %s %s %d %d\n",
+ systemdb_info->hostname,
+ systemdb_info->port,
+ systemdb_info->user,
+ systemdb_info->password[0] == '\0' ? "''" : systemdb_info->password,
+ systemdb_info->schema_name,
+ systemdb_info->database_name,
+ systemdb_info->dist_def_num,
+ systemdb_info->system_db_status);
+
+ for (i = 0; i < systemdb_info->dist_def_num; i++)
+ {
+ DistDefInfo *ddi = &systemdb_info->dist_def_slot[i];
+
+ printf("%s %s %s %s %d ",
+ ddi->dbname,
+ ddi->schema_name,
+ ddi->table_name,
+ ddi->dist_key_col_name,
+ ddi->col_num);
+
+ for (j = 0; j < ddi->col_num; j++)
+ printf("%s ", ddi->col_list[j]);
+
+ for (j = 0; j < ddi->col_num; j++)
+ printf("%s ", ddi->type_list[j]);
+
+ printf("%s\n", ddi->dist_def_func);
+ }
+}
+
+static void
+output_watchdog_info_result(PCPResultInfo* pcpResInfo, bool verbose)
+{
+ WdInfo *watchdog_info = (WdInfo *)pcp_get_binary_data(pcpResInfo,0);
+ if (verbose)
+ {
+ printf("Hostname : %s\nPgpool port : %d\nWatchdog port: %d\nStatus : %d\n",
+ watchdog_info->hostname,
+ watchdog_info->pgpool_port,
+ watchdog_info->wd_port,
+ watchdog_info->status);
+ }
+ else
+ {
+ printf("%s %d %d %d\n",
+ watchdog_info->hostname,
+ watchdog_info->pgpool_port,
+ watchdog_info->wd_port,
+ watchdog_info->status);
+ }
+}
+
+/* returns true if the current application requires node id argument */
+static inline bool
+app_require_nodeID(void)
+{
+ return(current_app_type->app_type == PCP_ATTACH_NODE ||
+ current_app_type->app_type == PCP_DETACH_NODE ||
+ current_app_type->app_type == PCP_NODE_INFO ||
+ current_app_type->app_type == PCP_PROMOTE_NODE ||
+ current_app_type->app_type == PCP_RECOVERY_NODE);
+}
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s - %s\n",progname,current_app_type->description);
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "%s [OPTION...] %s\n",progname,
+ app_require_nodeID()?"[node-id]":
+ (current_app_type->app_type == PCP_WATCHDOG_INFO)?"[watchdog-id]":
+ (current_app_type->app_type == PCP_PROC_INFO)?"[process-id]":"");
+
+ fprintf(stderr, "Options:\n");
+ /*
+ * print the command options
+ */
+ fprintf(stderr, " -U, --username=NAME username for PCP authentication\n");
+ fprintf(stderr, " -h, --host=HOSTNAME pgpool-II host\n");
+ fprintf(stderr, " -p, --port=PORT PCP port number\n");
+ fprintf(stderr, " -w, --no-password never prompt for password\n");
+ fprintf(stderr, " -W, --password force password prompt (should happen automatically)\n");
+ /*
+ * Now the options not available for all utilities
+ */
+ if (app_require_nodeID())
+ {
+ fprintf(stderr, " -n, --node-id=NODEID ID of a backend node\n");
+ }
+
+ if (current_app_type->app_type == PCP_STOP_PGPOOL)
+ {
+ fprintf(stderr, " -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n");
+ }
+ if (current_app_type->app_type == PCP_PROMOTE_NODE ||
+ current_app_type->app_type == PCP_DETACH_NODE)
+ {
+ fprintf(stderr, " -g, --gracefully promote gracefully(optional)\n");
+ }
+
+ if (current_app_type->app_type == PCP_WATCHDOG_INFO)
+ {
+ fprintf(stderr, " -n, --watchdog-id=ID ID of a other pgpool to get information for\n");
+ fprintf(stderr, " If omitted then get one's self information\n");
+ }
+ if (current_app_type->app_type == PCP_PROC_INFO)
+ {
+ fprintf(stderr, " -P, --process-id=PID PID of the child process to get information for (optional)\n");
+ fprintf(stderr, " -a, --all display all child processes and their available connection slots\n");
+ }
+
+ fprintf(stderr, " -d, --debug enable debug message (optional)\n");
+ fprintf(stderr, " -v, --verbose output verbose messages\n");
+ fprintf(stderr, " -?, --help print this help\n\n");
+}
+
+
+/*
+ * Extracts the actual name of the program as called -
+ * stripped of .exe suffix if any
+ */
+const char *
+get_progname(const char *argv0)
+{
+ const char *nodir_name;
+ char *progname;
+
+ nodir_name = last_dir_separator(argv0);
+ if (nodir_name)
+ nodir_name++;
+ else
+ nodir_name = argv0;
+
+ /*
+ * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
+ * called only once.
+ */
+ progname = strdup(nodir_name);
+ if (progname == NULL)
+ {
+ fprintf(stderr, "%s: out of memory\n", nodir_name);
+ exit(1); /* This could exit the postmaster */
+ }
+
+ return progname;
+}
+
diff --git a/src/tools/pcp/pcp_node_count.c b/src/tools/pcp/pcp_node_count.c
deleted file mode 100644
index 514c4c2ff..000000000
--- a/src/tools/pcp/pcp_node_count.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "node count" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int node_count;
- int ch;
- int optindex;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
- bool debug = false;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 4)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_node_count(pcpConn);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- node_count = pcp_get_int_data(pcpResInfo, 0);
- printf("%d\n", node_count);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_node_count - display the total number of nodes under pgpool-II's control\n\n");
- fprintf(stderr, "Usage: pcp_node_count [-d] hostname port# username password\n");
- fprintf(stderr, "Usage: pcp_node_count -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
-
diff --git a/src/tools/pcp/pcp_node_info.c b/src/tools/pcp/pcp_node_info.c
deleted file mode 100644
index bddcdce3a..000000000
--- a/src/tools/pcp/pcp_node_info.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "node info" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int nodeID;
- BackendInfo *backend_info;
- int ch;
- int optindex;
- bool verbose = false;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {"verbose", no_argument, NULL, 'v'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hdv", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'v':
- verbose = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- nodeID = atoi(argv[4]);
- if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_node_info(pcpConn,nodeID);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- backend_info = (BackendInfo *) pcp_get_binary_data(pcpResInfo,0);
-
- if (verbose)
- {
- printf("Hostname: %s\nPort : %d\nStatus : %d\nWeight : %f\n",
- backend_info->backend_hostname,
- backend_info->backend_port,
- backend_info->backend_status,
- backend_info->backend_weight/RAND_MAX);
- } else {
- printf("%s %d %d %f\n",
- backend_info->backend_hostname,
- backend_info->backend_port,
- backend_info->backend_status,
- backend_info->backend_weight/RAND_MAX);
- }
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_node_info - display a pgpool-II node's information\n\n");
- fprintf(stderr, "Usage: pcp_node_info [-d] hostname port# username password nodeID\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " nodeID : ID of a node to get information for\n\n");
- fprintf(stderr, "Usage: pcp_node_info [options]\n");
- fprintf(stderr, " Options available are:\n");
- fprintf(stderr, " -h, --help : print this help\n");
- fprintf(stderr, " -v, --verbose : display one line per information with a header\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
-
diff --git a/src/tools/pcp/pcp_pool_status.c b/src/tools/pcp/pcp_pool_status.c
deleted file mode 100644
index 55facdf35..000000000
--- a/src/tools/pcp/pcp_pool_status.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2011 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "pool status" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- POOL_REPORT_CONFIG *status;
- int ch;
- int i;
- int optindex;
- int array_size = 0;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 4)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_pool_status(pcpConn);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- array_size = pcp_result_slot_count(pcpResInfo);
-
- for (i=0; i<array_size; i++) {
- status = (POOL_REPORT_CONFIG *)pcp_get_binary_data(pcpResInfo, i);
- if(status == NULL)
- {
- printf("****Data at %d slot is NULL\n",i);
- continue;
- }
- printf("name : %s\nvalue: %s\ndesc : %s\n\n", status->name, status->value, status->desc);
- }
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_pool_status - display pgpool configuration and status\n\n");
- fprintf(stderr, "Usage: pcp_pool_status [-d] hostname port# username password\n");
- fprintf(stderr, "Usage: pcp_pool_status -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_proc_count.c b/src/tools/pcp/pcp_proc_count.c
deleted file mode 100644
index fa915da93..000000000
--- a/src/tools/pcp/pcp_proc_count.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "process count" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int process_count;
- int *process_list = NULL;
- int ch,i;
- int optindex;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 4)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_process_count(pcpConn);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- process_count = pcp_get_data_length(pcpResInfo, 0) / sizeof(int);
- process_list = (int *)pcp_get_binary_data(pcpResInfo, 0);
-
-
- for (i = 0; i < process_count; i++)
- printf("%d ", process_list[i]);
- printf("\n");
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_proc_count - display the list of pgpool-II child process PIDs\n\n");
- fprintf(stderr, "Usage: pcp_proc_count hostname port# username password\n");
- fprintf(stderr, "Usage: pcp_node_info -h\n\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_proc_info.c b/src/tools/pcp/pcp_proc_info.c
deleted file mode 100644
index 2692ce2ce..000000000
--- a/src/tools/pcp/pcp_proc_info.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "process info" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-#include <time.h>
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int processID;
- ProcessInfo *process_info;
- int array_size;
- int ch;
- int optindex;
- char * frmt;
- bool verbose = false;
- bool all = false;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {"verbose", no_argument, NULL, 'v'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hdva", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'v':
- verbose = true;
- break;
-
- case 'a':
- all = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (verbose)
- {
- if (all)
- frmt = "Database : %s\n"
- "Username : %s\n"
- "Start time : %s\n"
- "Creation time: %s\n"
- "Major : %d\n"
- "Minor : %d\n"
- "Counter : %d\n"
- "Backend PID : %d\n"
- "Connected : %d\n"
- "PID : %d\n"
- "Backend ID : %d\n";
- else
- frmt = "Database : %s\n"
- "Username : %s\n"
- "Start time : %s\n"
- "Creation time: %s\n"
- "Major : %d\n"
- "Minor : %d\n"
- "Counter : %d\n"
- "Backend PID : %d\n"
- "Connected : %d\n";
- }
- else
- {
- if (all)
- frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
- else
- frmt = "%s %s %s %s %d %d %d %d %d\n";
- }
-
- if (!(argc == 4 || argc == 5))
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- if (argc == 5) {
-
- processID = atoi(argv[4]);
- if (processID < 0)
- myexit(NULL);
- }
- else {
- processID = 0;
- }
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_process_info(pcpConn, processID);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
-
- array_size = pcp_result_slot_count(pcpResInfo);
- int i;
- char strcreatetime[128];
- char strstarttime[128];
-
- for (i = 0; i < array_size; i++)
- {
-
- process_info = (ProcessInfo*) pcp_get_binary_data(pcpResInfo, i);
- if(process_info == NULL)
- break;
- if ((!all) && (process_info->connection_info->database[0] == '\0'))
- continue;
-
- *strcreatetime = *strstarttime = '\0';
-
- if (process_info->start_time)
- strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
- if (process_info->connection_info->create_time)
- strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
-
- printf(frmt,
- process_info->connection_info->database,
- process_info->connection_info->user,
- strstarttime,
- strcreatetime,
- process_info->connection_info->major,
- process_info->connection_info->minor,
- process_info->connection_info->counter,
- process_info->connection_info->pid,
- process_info->connection_info->connected,
- process_info->pid,
- process_info->connection_info->backend_id);
- }
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_proc_info - display a pgpool-II child process' information\n\n");
- fprintf(stderr, "Usage: pcp_proc_info [-d] hostname port# username password [PID]\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " PID : if given, PID of the only child process to get information for\n\n");
- fprintf(stderr, "Usage: pcp_proc_info [options]\n");
- fprintf(stderr, " Options available are:\n");
- fprintf(stderr, " -h, --help : print this help\n");
- fprintf(stderr, " -v, --verbose : display one line per information with a header\n");
- fprintf(stderr, " -a, --all : display all child processes and their available connection slots.\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
diff --git a/src/tools/pcp/pcp_promote_node.c b/src/tools/pcp/pcp_promote_node.c
deleted file mode 100644
index 1fef4e0a2..000000000
--- a/src/tools/pcp/pcp_promote_node.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2011 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "promote node" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int nodeID;
- int ch;
- int optindex;
- bool gracefully = false;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"gracefully", no_argument, NULL, 'g'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hdg", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'g':
- gracefully = true;
- break;
-
- case 'h':
- case '?':
- default:
- usage();
- exit(0);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- nodeID = atoi(argv[4]);
- if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- if (gracefully)
- pcpResInfo = pcp_promote_node_gracefully(pcpConn,nodeID);
- else
- pcpResInfo = pcp_promote_node(pcpConn,nodeID);
-
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_promote_node - promote a node as new master from pgpool-II\n\n");
- fprintf(stderr, "Usage: pcp_promote_node [-d][-g] hostname port# username password nodeID\n");
- fprintf(stderr, "Usage: pcp_promote_node -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " -g, --gracefully : promote gracefully(optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " nodeID : ID of a node to be promoted\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_recovery_node.c b/src/tools/pcp/pcp_recovery_node.c
deleted file mode 100644
index 90c37e56e..000000000
--- a/src/tools/pcp/pcp_recovery_node.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "attach node" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int nodeID;
- int ch;
- int optindex;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- usage();
- exit(0);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- nodeID = atoi(argv[4]);
- if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_recovery_node(pcpConn, nodeID);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_recovery_node - recovery a node\n\n");
- fprintf(stderr, "Usage: pcp_recovery_node [-d] hostname port# username password nodeID\n");
- fprintf(stderr, "Usage: pcp_recovery_node -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " nodeID : ID of a node to recover\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_stop_pgpool.c b/src/tools/pcp/pcp_stop_pgpool.c
deleted file mode 100644
index 5d5b8a24d..000000000
--- a/src/tools/pcp/pcp_stop_pgpool.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2013 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "stop pgpool" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- char mode;
- int ch;
- int optindex;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- myexit(NULL);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 5)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- if (strlen(argv[4]) != 1)
- myexit(NULL);
-
- mode = argv[4][0];
- if (mode != 's' && mode != 'f' && mode != 'i')
- myexit(NULL);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_terminate_pgpool(pcpConn, mode);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_stop_pgpool - terminate pgpool-II\n\n");
- fprintf(stderr, "Usage: pcp_stop_pgpool [-d] hostname port# username password mode\n");
- fprintf(stderr, "Usage: pcp_stop_pgpool -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " mode : shutdown mode\n");
- fprintf(stderr, " s - smart shutdown f - fast shutdown i - immediate shutdown\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
-
diff --git a/src/tools/pcp/pcp_systemdb_info.c b/src/tools/pcp/pcp_systemdb_info.c
deleted file mode 100644
index 91b8a4267..000000000
--- a/src/tools/pcp/pcp_systemdb_info.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2008 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "systemDB info" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- SystemDBInfo *systemdb_info;
- int i, j;
- int ch;
- int optindex;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'h':
- case '?':
- default:
- usage();
- exit(0);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 4)
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_systemdb_info(pcpConn);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- systemdb_info = (SystemDBInfo *)pcp_get_binary_data(pcpResInfo, 0);
- printf("%s %d %s %s %s %s %d %d\n",
- systemdb_info->hostname,
- systemdb_info->port,
- systemdb_info->user,
- systemdb_info->password[0] == '\0' ? "''" : systemdb_info->password,
- systemdb_info->schema_name,
- systemdb_info->database_name,
- systemdb_info->dist_def_num,
- systemdb_info->system_db_status);
-
- for (i = 0; i < systemdb_info->dist_def_num; i++)
- {
- DistDefInfo *ddi = &systemdb_info->dist_def_slot[i];
-
- printf("%s %s %s %s %d ",
- ddi->dbname,
- ddi->schema_name,
- ddi->table_name,
- ddi->dist_key_col_name,
- ddi->col_num);
-
- for (j = 0; j < ddi->col_num; j++)
- printf("%s ", ddi->col_list[j]);
-
- for (j = 0; j < ddi->col_num; j++)
- printf("%s ", ddi->type_list[j]);
-
- printf("%s\n", ddi->dist_def_func);
- }
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
-
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_systemdb_info - display the pgpool-II systemDB information\n\n");
- fprintf(stderr, "Usage: pcp_systemdb_info [-d] hostname port# username password\n");
- fprintf(stderr, "Usage: pcp_systemdb_info -h\n\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " -h, --help : print this help\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
diff --git a/src/tools/pcp/pcp_watchdog_info.c b/src/tools/pcp/pcp_watchdog_info.c
deleted file mode 100644
index f1ae138bc..000000000
--- a/src/tools/pcp/pcp_watchdog_info.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * $Header$
- *
- * pgpool: a language independent connection pool server for PostgreSQL
- * written by Tatsuo Ishii
- *
- * Copyright (c) 2003-2013 PgPool Global Development Group
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of the
- * author not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. The author makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * Client program to send "watchdog info" command.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "utils/getopt_long.h"
-#endif
-
-#include "pcp/pcp.h"
-
-static void usage(void);
-static void myexit(PCPConnInfo* pcpConn);
-
-int
-main(int argc, char **argv)
-{
- char host[MAX_DB_HOST_NAMELEN];
- int port;
- char user[MAX_USER_PASSWD_LEN];
- char pass[MAX_USER_PASSWD_LEN];
- int wd_index;
- WdInfo *watchdog_info;
- int ch;
- int optindex;
- bool verbose = false;
- bool debug = false;
- PCPConnInfo* pcpConn;
- PCPResultInfo* pcpResInfo;
-
-
- static struct option long_options[] = {
- {"debug", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {"verbose", no_argument, NULL, 'v'},
- {NULL, 0, NULL, 0}
- };
-
- while ((ch = getopt_long(argc, argv, "hdv", long_options, &optindex)) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
-
- case 'v':
- verbose = true;
- break;
-
- case 'h':
- case '?':
- default:
- usage();
- exit(0);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (!(argc == 4 || argc == 5))
- myexit(NULL);
-
- if (strlen(argv[0]) >= MAX_DB_HOST_NAMELEN)
- myexit(NULL);
- strcpy(host, argv[0]);
-
- port = atoi(argv[1]);
- if (port <= 1024 || port > 65535)
- myexit(NULL);
-
- if (strlen(argv[2]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(user, argv[2]);
-
- if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
- myexit(NULL);
- strcpy(pass, argv[3]);
-
- if (argc == 5)
- {
- wd_index = atoi(argv[4]);
- if (wd_index < 0 || wd_index > MAX_WATCHDOG_NUM)
- myexit(NULL);
- wd_index++;
- }
- else
- {
- wd_index = 0;
- }
-
- pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
- if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
- myexit(pcpConn);
-
- pcpResInfo = pcp_watchdog_info(pcpConn,wd_index);
- if(PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
- myexit(pcpConn);
-
- watchdog_info = (WdInfo *)pcp_get_binary_data(pcpResInfo,0);
- if (verbose)
- {
- printf("Hostname : %s\nPgpool port : %d\nWatchdog port: %d\nStatus : %d\n",
- watchdog_info->hostname,
- watchdog_info->pgpool_port,
- watchdog_info->wd_port,
- watchdog_info->status);
- }
- else
- {
- printf("%s %d %d %d\n",
- watchdog_info->hostname,
- watchdog_info->pgpool_port,
- watchdog_info->wd_port,
- watchdog_info->status);
- }
-
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- return 0;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "pcp_watchdog_info - display a pgpool-II watchdog's information\n\n");
- fprintf(stderr, "Usage: pcp_watchdog_info [-d] hostname port# username password [watchdogID]\n");
- fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
- fprintf(stderr, " hostname : pgpool-II hostname\n");
- fprintf(stderr, " port# : PCP port number\n");
- fprintf(stderr, " username : username for PCP authentication\n");
- fprintf(stderr, " password : password for PCP authentication\n");
- fprintf(stderr, " watchdogID : ID of a other pgpool to get information for\n");
- fprintf(stderr, " If omitted then get one's self information\n\n");
- fprintf(stderr, "Usage: pcp_watchdog_info [options]\n");
- fprintf(stderr, " Options available are:\n");
- fprintf(stderr, " -h, --help : print this help\n");
- fprintf(stderr, " -v, --verbose : display one line per information with a header\n");
-}
-
-static void
-myexit(PCPConnInfo* pcpConn)
-{
- if (pcpConn == NULL)
- {
- usage();
- }
- else
- {
- fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
- pcp_disconnect(pcpConn);
- pcp_free_connection(pcpConn);
- }
- exit(-1);
-}
diff --git a/src/utils/pool_path.c b/src/utils/pool_path.c
index 46ab446e6..b1d88e479 100644
--- a/src/utils/pool_path.c
+++ b/src/utils/pool_path.c
@@ -28,10 +28,13 @@
#include "utils/pool_path.h"
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
static void trim_directory(char *path);
static void trim_trailing_separator(char *path);
-
+static int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
+ size_t buflen, struct passwd ** result);
/*
* get_parent_directory
*
@@ -43,6 +46,67 @@ void get_parent_directory(char *path)
trim_directory(path);
}
+/*
+ * Obtain user's home directory, return in given buffer
+ */
+bool
+get_home_directory(char *buf, int bufsize)
+{
+ char pwdbuf[BUFSIZ];
+ struct passwd pwdstr;
+ struct passwd *pwd = NULL;
+
+ if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+ return false;
+ strlcpy(buf, pwd->pw_dir, bufsize);
+ return true;
+}
+
+/*
+ * Obtain user name, return in given buffer
+ */
+bool
+get_os_username(char *buf, int bufsize)
+{
+ char pwdbuf[BUFSIZ];
+ struct passwd pwdstr;
+ struct passwd *pwd = NULL;
+
+ if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+ return false;
+ strlcpy(buf, pwd->pw_name, bufsize);
+ return true;
+}
+
+/*
+ * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
+ * behaviour, if it is not available or required.
+ */
+static int
+pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
+ size_t buflen, struct passwd ** result)
+{
+#if defined(HAVE_GETPWUID_R)
+
+#ifdef GETPWUID_R_5ARG
+ /* POSIX version */
+ getpwuid_r(uid, resultbuf, buffer, buflen, result);
+#else
+
+ /*
+ * Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
+ * getpwuid_r(uid, resultbuf, buffer, buflen)
+ */
+ *result = getpwuid_r(uid, resultbuf, buffer, buflen);
+#endif
+#else
+
+ /* no getpwuid_r() available, just use getpwuid() */
+ *result = getpwuid(uid);
+#endif
+
+ return (*result == NULL) ? -1 : 0;
+}
/*
* trim_directory
@@ -176,6 +240,23 @@ void canonicalize_path(char *path)
}
}
+/*
+ * last_dir_separator
+ *
+ * Find the location of the last directory separator, return
+ * NULL if not found.
+ */
+char *
+last_dir_separator(const char *filename)
+{
+ const char *p,
+ *ret = NULL;
+
+ for (p = filename; *p; p++)
+ if (IS_DIR_SEP(*p))
+ ret = p;
+ return (char *) ret;
+}
/*
* trim_trailing_separator
diff --git a/src/utils/sprompt.c b/src/utils/sprompt.c
new file mode 100644
index 000000000..94e06960d
--- /dev/null
+++ b/src/utils/sprompt.c
@@ -0,0 +1,204 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * This file was imported from PostgreSQL source code.
+ * See below for the copyright and description.
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2015 PgPool Global Development Group
+ *
+ */
+/*-------------------------------------------------------------------------
+ *
+ * sprompt.c
+ * simple_prompt() routine
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/sprompt.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/*
+ * simple_prompt
+ *
+ * Generalized function especially intended for reading in usernames and
+ * password interactively. Reads from /dev/tty or stdin/stderr.
+ *
+ * prompt: The prompt to print
+ * maxlen: How many characters to accept
+ * echo: Set to false if you want to hide what is entered (for passwords)
+ *
+ * Returns a malloc()'ed string with the input (w/o trailing newline).
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "pool_type.h"
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
+extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
+
+char *
+simple_prompt(const char *prompt, int maxlen, bool echo)
+{
+ int length;
+ char *destination;
+ FILE *termin,
+ *termout;
+
+#ifdef HAVE_TERMIOS_H
+ struct termios t_orig,
+ t;
+#else
+#ifdef WIN32
+ HANDLE t = NULL;
+ LPDWORD t_orig = NULL;
+#endif
+#endif
+
+ destination = (char *) malloc(maxlen + 1);
+ if (!destination)
+ return NULL;
+
+#ifdef WIN32
+
+ /*
+ * A Windows console has an "input code page" and an "output code page";
+ * these usually match each other, but they rarely match the "Windows ANSI
+ * code page" defined at system boot and expected of "char *" arguments to
+ * Windows API functions. The Microsoft CRT write() implementation
+ * automatically converts text between these code pages when writing to a
+ * console. To identify such file descriptors, it calls GetConsoleMode()
+ * on the underlying HANDLE, which in turn requires GENERIC_READ access on
+ * the HANDLE. Opening termout in mode "w+" allows that detection to
+ * succeed. Otherwise, write() would not recognize the descriptor as a
+ * console, and non-ASCII characters would display incorrectly.
+ *
+ * XXX fgets() still receives text in the console's input code page. This
+ * makes non-ASCII credentials unportable.
+ */
+ termin = fopen("CONIN$", "r");
+ termout = fopen("CONOUT$", "w+");
+#else
+
+ /*
+ * Do not try to collapse these into one "w+" mode file. Doesn't work on
+ * some platforms (eg, HPUX 10.20).
+ */
+ termin = fopen("/dev/tty", "r");
+ termout = fopen("/dev/tty", "w");
+#endif
+ if (!termin || !termout
+#ifdef WIN32
+
+ /*
+ * Direct console I/O does not work from the MSYS 1.0.10 console. Writes
+ * reach nowhere user-visible; reads block indefinitely. XXX This affects
+ * most Windows terminal environments, including rxvt, mintty, Cygwin
+ * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test.
+ */
+ || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
+#endif
+ )
+ {
+ if (termin)
+ fclose(termin);
+ if (termout)
+ fclose(termout);
+ termin = stdin;
+ termout = stderr;
+ }
+
+#ifdef HAVE_TERMIOS_H
+ if (!echo)
+ {
+ tcgetattr(fileno(termin), &t);
+ t_orig = t;
+ t.c_lflag &= ~ECHO;
+ tcsetattr(fileno(termin), TCSAFLUSH, &t);
+ }
+#else
+#ifdef WIN32
+ if (!echo)
+ {
+ /* get a new handle to turn echo off */
+ t_orig = (LPDWORD) malloc(sizeof(DWORD));
+ t = GetStdHandle(STD_INPUT_HANDLE);
+
+ /* save the old configuration first */
+ GetConsoleMode(t, t_orig);
+
+ /* set to the new mode */
+ SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
+ }
+#endif
+#endif
+
+ if (prompt)
+ {
+ fputs(prompt, termout);
+ fflush(termout);
+ }
+
+ if (fgets(destination, maxlen + 1, termin) == NULL)
+ destination[0] = '\0';
+
+ length = strlen(destination);
+ if (length > 0 && destination[length - 1] != '\n')
+ {
+ /* eat rest of the line */
+ char buf[128];
+ int buflen;
+
+ do
+ {
+ if (fgets(buf, sizeof(buf), termin) == NULL)
+ break;
+ buflen = strlen(buf);
+ } while (buflen > 0 && buf[buflen - 1] != '\n');
+ }
+
+ if (length > 0 && destination[length - 1] == '\n')
+ /* remove trailing newline */
+ destination[length - 1] = '\0';
+
+#ifdef HAVE_TERMIOS_H
+ if (!echo)
+ {
+ tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
+ fputs("\n", termout);
+ fflush(termout);
+ }
+#else
+#ifdef WIN32
+ if (!echo)
+ {
+ /* reset to the original console mode */
+ SetConsoleMode(t, *t_orig);
+ fputs("\n", termout);
+ fflush(termout);
+ free(t_orig);
+ }
+#endif
+#endif
+
+ if (termin != stdin)
+ {
+ fclose(termin);
+ fclose(termout);
+ }
+
+ return destination;
+}
[parent: dccdd265ebaa]