370 lines
8.1 KiB
C++
370 lines
8.1 KiB
C++
/*-------------------------------------------------------------------------
|
|
*
|
|
* utils.c
|
|
*
|
|
* Utility module of Postgres-XC configuration and operation tool.
|
|
*
|
|
* Copyright (c) 2013 Postgres-XC Development Group
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
/*
|
|
* Variable useful tools/small routines.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
|
|
#include "../../src/interfaces/libpq/libpq-fe.h"
|
|
#include "utils.h"
|
|
#include "pgxc_ctl.h"
|
|
#include "pgxc_ctl_log.h"
|
|
#include "do_shell.h"
|
|
#include "config.h"
|
|
#include "variables.h"
|
|
#include "varnames.h"
|
|
|
|
static int Malloc_ed = 0;
|
|
static int Strdup_ed = 0;
|
|
static int Freed = 0;
|
|
|
|
void* Malloc(size_t size)
|
|
{
|
|
void* rv = malloc(size);
|
|
|
|
Malloc_ed++;
|
|
if (rv == NULL) {
|
|
elog(PANIC, "PANIC: No more memory. See core file for details.\n");
|
|
abort();
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
char** addToList(char** List, char* val)
|
|
{
|
|
char** rv;
|
|
int ii;
|
|
|
|
for (ii = 0; List[ii]; ii++)
|
|
;
|
|
rv = Realloc(List, sizeof(char*) * ii);
|
|
rv[ii - 1] = NULL;
|
|
return rv;
|
|
}
|
|
|
|
void* Malloc0(size_t size)
|
|
{
|
|
void* rv = malloc(size);
|
|
|
|
Malloc_ed++;
|
|
if (rv == NULL) {
|
|
elog(PANIC, "PANIC: No more memory. See core file for details.\n");
|
|
abort();
|
|
}
|
|
memset(rv, 0, size);
|
|
return (rv);
|
|
}
|
|
|
|
void* Realloc(void* ptr, size_t size)
|
|
{
|
|
void* rv = realloc(ptr, size);
|
|
|
|
if (rv == NULL) {
|
|
elog(PANIC, "PANIC: No more memory. See core file for details.\n");
|
|
abort();
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void Free(void* ptr)
|
|
{
|
|
Freed++;
|
|
if (ptr)
|
|
free(ptr);
|
|
}
|
|
|
|
/*
|
|
* If flag is TRUE and chdir fails, then exit(1)
|
|
*/
|
|
int Chdir(char* path, int flag)
|
|
{
|
|
if (chdir(path)) {
|
|
elog(ERROR,
|
|
"ERROR: Could not change work directory to \"%s\". %s%s\n",
|
|
path,
|
|
flag == TRUE ? "Exiting. " : "",
|
|
strerror(errno));
|
|
if (flag == TRUE)
|
|
exit(1);
|
|
else
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
FILE* Fopen(char* path, char* mode)
|
|
{
|
|
FILE* rv = NULL;
|
|
|
|
if ((rv = fopen(path, mode)) == NULL)
|
|
elog(ERROR, "ERROR: Could not open the file \"%s\" in \"%s\", %s\n", path, mode, strerror(errno));
|
|
return (rv);
|
|
}
|
|
|
|
char* Strdup(const char* s)
|
|
{
|
|
char* rv = NULL;
|
|
|
|
Strdup_ed++;
|
|
rv = strdup(s);
|
|
if (rv == NULL) {
|
|
elog(PANIC, "PANIC: No more memory. See core file for details.\n");
|
|
abort();
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void appendFiles(FILE* f, char** fileList)
|
|
{
|
|
FILE* src = NULL;
|
|
int ii;
|
|
char buf[MAXLINE + 1];
|
|
|
|
if (fileList)
|
|
for (ii = 0; fileList[ii]; ii++) {
|
|
if (!is_none(fileList[ii])) {
|
|
if ((src = fopen(fileList[ii], "r")) == 0) {
|
|
elog(ERROR, "ERROR: could not open file %s for read, %s\n", fileList[ii], strerror(errno));
|
|
continue;
|
|
}
|
|
while (fgets(buf, MAXLINE, src))
|
|
fputs(buf, f);
|
|
fclose(src);
|
|
}
|
|
}
|
|
}
|
|
|
|
FILE* prepareLocalStdin(char* buf, int len, char** fileList)
|
|
{
|
|
FILE* f = NULL;
|
|
if ((f = fopen(createLocalFileName(STDIN, buf, len), "w")) == NULL) {
|
|
elog(ERROR, "ERROR: could not open file %s for write, %s\n", buf, strerror(errno));
|
|
return (NULL);
|
|
}
|
|
appendFiles(f, fileList);
|
|
return (f);
|
|
}
|
|
|
|
char* timeStampString(char* buf, int len)
|
|
{
|
|
time_t nowTime;
|
|
struct tm nowTm;
|
|
|
|
nowTime = time(NULL);
|
|
localtime_r(&nowTime, &nowTm);
|
|
|
|
snprintf(buf,
|
|
len,
|
|
"%04d%02d%02d_%02d:%02d:%02d",
|
|
nowTm.tm_year + 1900,
|
|
nowTm.tm_mon + 1,
|
|
nowTm.tm_mday,
|
|
nowTm.tm_hour,
|
|
nowTm.tm_min,
|
|
nowTm.tm_sec);
|
|
return (buf);
|
|
}
|
|
|
|
char** makeActualNodeList(char** nodeList)
|
|
{
|
|
char** actualNodeList;
|
|
int ii, jj;
|
|
|
|
for (ii = 0, jj = 0; nodeList[ii]; ii++) {
|
|
if (!is_none(nodeList[ii]))
|
|
jj++;
|
|
}
|
|
actualNodeList = Malloc0(sizeof(char*) * (jj + 1));
|
|
for (ii = 0, jj = 0; nodeList[ii]; ii++) {
|
|
if (!is_none(nodeList[ii])) {
|
|
actualNodeList[jj] = Strdup(nodeList[ii]);
|
|
jj++;
|
|
}
|
|
}
|
|
return actualNodeList;
|
|
}
|
|
|
|
int gtmProxyIdx(char* gtmProxyName)
|
|
{
|
|
int ii;
|
|
|
|
for (ii = 0; aval(VAR_gtmProxyNames)[ii]; ii++) {
|
|
if (strcmp(aval(VAR_gtmProxyNames)[ii], gtmProxyName) == 0)
|
|
return ii;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int coordIdx(char* coordName)
|
|
{
|
|
int ii;
|
|
|
|
if (is_none(coordName))
|
|
return -1;
|
|
for (ii = 0; aval(VAR_coordNames)[ii]; ii++) {
|
|
if (strcmp(aval(VAR_coordNames)[ii], coordName) == 0)
|
|
return ii;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int datanodeIdx(char* datanodeName)
|
|
{
|
|
int ii;
|
|
|
|
if (is_none(datanodeName))
|
|
return -1;
|
|
for (ii = 0; aval(VAR_datanodeNames)[ii]; ii++) {
|
|
if (strcmp(aval(VAR_datanodeNames)[ii], datanodeName) == 0)
|
|
return ii;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int getEffectiveGtmProxyIdxFromServerName(char* serverName)
|
|
{
|
|
int ii;
|
|
|
|
if (serverName == NULL)
|
|
return (-1);
|
|
for (ii = 0; aval(VAR_gtmProxyNames)[ii]; ii++) {
|
|
if (strcmp(aval(VAR_gtmProxyServers)[ii], serverName) == 0)
|
|
return ii;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Please note that this function deeply depend upon
|
|
* the environment.
|
|
*
|
|
* It works find with CentOS/Ubuntu/ReadHat Linux but
|
|
* may need another tweak for other operation systems
|
|
* such as Solaris, FreeBSD, MacOS.
|
|
*/
|
|
pid_t get_prog_pid(char* host, char* progname, char* dir)
|
|
{
|
|
char cmd[MAXLINE + 1];
|
|
char pid_s[MAXLINE + 1];
|
|
int ii;
|
|
FILE* wkf = NULL;
|
|
char* token = NULL;
|
|
char* line = NULL;
|
|
|
|
snprintf(cmd,
|
|
MAXLINE,
|
|
"ssh %s@%s "
|
|
"\"ps -f -C %s | grep %s\"",
|
|
sval(VAR_pgxcUser),
|
|
host,
|
|
progname,
|
|
dir);
|
|
wkf = popen(cmd, "r");
|
|
if (wkf == NULL) {
|
|
elog(ERROR,
|
|
"ERROR: cannot obtain pid value of the remote postmaster, host \"%s\" dir \"%s\", %s\n",
|
|
host,
|
|
dir,
|
|
strerror(errno));
|
|
return (-1);
|
|
}
|
|
fgets(pid_s, MAXLINE, wkf);
|
|
fclose(wkf);
|
|
/* Get the second token */
|
|
line = pid_s;
|
|
if ((line = get_word(line, &token)) == NULL)
|
|
return 0;
|
|
get_word(line, &token);
|
|
if (token == NULL)
|
|
return 0;
|
|
for (ii = 0; token[ii]; ii++)
|
|
if (token[ii] < '0' || token[ii] > '9')
|
|
return 0;
|
|
return (atoi(token));
|
|
}
|
|
|
|
int pingNode(char* host, char* port)
|
|
{
|
|
PGPing status;
|
|
char conninfo[MAXLINE + 1];
|
|
char editBuf[MAXPATH + 1];
|
|
|
|
conninfo[0] = 0;
|
|
if (host) {
|
|
snprintf(editBuf, MAXPATH, "host = '%s' ", host);
|
|
strncat(conninfo, editBuf, MAXLINE);
|
|
}
|
|
if (port) {
|
|
snprintf(editBuf, MAXPATH, "port = %d ", atoi(port));
|
|
strncat(conninfo, editBuf, MAXLINE);
|
|
}
|
|
if (conninfo[0]) {
|
|
status = PQping(conninfo);
|
|
if (status == PQPING_OK)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
void trimNl(char* s)
|
|
{
|
|
for (; *s && *s != '\n'; s++)
|
|
;
|
|
*s = 0;
|
|
}
|
|
|
|
char* getChPidList(char* host, pid_t ppid)
|
|
{
|
|
FILE* wkf = NULL;
|
|
char cmd[MAXLINE + 1];
|
|
char line[MAXLINE + 1];
|
|
char* rv = Malloc(MAXLINE + 1);
|
|
|
|
rv[0] = 0;
|
|
snprintf(cmd, MAXLINE, "ssh %s@%s pgrep -P %d", sval(VAR_pgxcUser), host, ppid);
|
|
wkf = popen(cmd, "r");
|
|
if (wkf == NULL)
|
|
return NULL;
|
|
while (fgets(line, MAXLINE, wkf)) {
|
|
trimNl(line);
|
|
strncat(rv, line, MAXLINE);
|
|
strncat(rv, " ", MAXLINE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
char* getIpAddress(char* hostName)
|
|
{
|
|
char command[MAXLINE + 1];
|
|
char* ipAddr = NULL;
|
|
FILE* f = NULL;
|
|
|
|
snprintf(command, MAXLINE, "ping -c1 %s | head -n 1 | sed 's/^[^(]*(\\([^)]*\\).*$/\\1/'", hostName);
|
|
if ((f = popen(command, "r")) == NULL) {
|
|
elog(ERROR, "ERROR: could not open the command, \"%s\", %s\n", command, strerror(errno));
|
|
return NULL;
|
|
}
|
|
ipAddr = Malloc(MAXTOKEN + 1);
|
|
fgets(ipAddr, MAXTOKEN, f);
|
|
fclose(f);
|
|
trimNl(ipAddr);
|
|
return ipAddr;
|
|
}
|