pgpool2.git / summary / log / commit / refs

commit    666d71f69c7521b8ebefa96fd6735858aac739fa
Author:   Tatsuo Ishii <ishii@postgresql.org>
Date:     Tue Mar 13 14:33:43 2012 +0000

    Add watchdog feature.


Makefile.am | 4 +- Makefile.in | 6 +- configure | 3 +- main.c | 5 +- pgpool.conf.sample | 35 + pool_config.c | 1646 +++++++++++++++++++++++++--------------- pool_config.h | 19 + pool_config.l | 225 ++++++ watchdog/Makefile.am | 15 + watchdog/Makefile.in | 492 ++++++++++++ watchdog/test/stab.c | 266 +++++++ watchdog/test/test.c | 85 +++ watchdog/test/wd_child_t.c | 87 +++ watchdog/test/wd_lifecheck_t.c | 87 +++ watchdog/test/wd_packet_t.c | 87 +++ watchdog/test/wd_ping_t.c | 20 + watchdog/watchdog.c | 125 +++ watchdog/watchdog.h | 112 +++ watchdog/wd_child.c | 199 +++++ watchdog/wd_ext.h | 67 ++ watchdog/wd_if.c | 144 ++++ watchdog/wd_init.c | 79 ++ watchdog/wd_lifecheck.c | 216 ++++++ watchdog/wd_list.c | 169 +++++ watchdog/wd_packet.c | 630 +++++++++++++++ watchdog/wd_ping.c | 228 ++++++ 26 files changed, 4423 insertions(+), 628 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3394cf367..57e59a4c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,7 +46,7 @@ AM_CPPFLAGS = -D_GNU_SOURCE -I @PGSQL_INCLUDE_DIR@ # suggested by libtoolize ACLOCAL_AMFLAGS = -I m4 -pgpool_LDADD = -L@PGSQL_LIB_DIR@ -lpq parser/libsql-parser.a pcp/libpcp.la parser/nodes.o +pgpool_LDADD = -L@PGSQL_LIB_DIR@ -lpq parser/libsql-parser.a pcp/libpcp.la parser/nodes.o watchdog/lib-watchdog.a -lpthread if enable_rpath pgpool_LDFLAGS = -rpath @PGSQL_LIB_DIR@ -rpath $(libdir) else @@ -128,4 +128,4 @@ EXTRA_DIST = pgpool.8.in sample/pgpool.pam \ redhat/pgpool.init redhat/pgpool.sysconfig redhat/pgpool.conf.sample.patch -SUBDIRS = parser pcp +SUBDIRS = parser pcp watchdog diff --git a/Makefile.in b/Makefile.in index 3bbdefdff..1ca5533b5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,7 +87,7 @@ am_pgpool_OBJECTS = main.$(OBJEXT) child.$(OBJEXT) pool_auth.$(OBJEXT) \ getopt_long.$(OBJEXT) pgpool_OBJECTS = $(am_pgpool_OBJECTS) pgpool_DEPENDENCIES = parser/libsql-parser.a pcp/libpcp.la \ - parser/nodes.o + parser/nodes.o watchdog/lib-watchdog.a pgpool_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(pgpool_LDFLAGS) \ $(LDFLAGS) -o $@ @@ -353,7 +353,7 @@ AM_CPPFLAGS = -D_GNU_SOURCE -I @PGSQL_INCLUDE_DIR@ # suggested by libtoolize ACLOCAL_AMFLAGS = -I m4 -pgpool_LDADD = -L@PGSQL_LIB_DIR@ -lpq parser/libsql-parser.a pcp/libpcp.la parser/nodes.o +pgpool_LDADD = -L@PGSQL_LIB_DIR@ -lpq parser/libsql-parser.a pcp/libpcp.la parser/nodes.o watchdog/lib-watchdog.a -lpthread @enable_rpath_FALSE@pgpool_LDFLAGS = @enable_rpath_TRUE@pgpool_LDFLAGS = -rpath @PGSQL_LIB_DIR@ -rpath $(libdir) AM_YFLAGS = -d @@ -425,7 +425,7 @@ EXTRA_DIST = pgpool.8.in sample/pgpool.pam \ test/timestamp/parse_schedule test/timestamp/run-test \ redhat/pgpool.init redhat/pgpool.sysconfig redhat/pgpool.conf.sample.patch -SUBDIRS = parser pcp +SUBDIRS = parser pcp watchdog all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive diff --git a/configure b/configure index 758246e31..de112aa65 100755 --- a/configure +++ b/configure @@ -13566,7 +13566,7 @@ $as_echo "$enable_table_lock" >&6; } ac_config_headers="$ac_config_headers config.h" -ac_config_files="$ac_config_files Makefile parser/Makefile pcp/Makefile" +ac_config_files="$ac_config_files Makefile parser/Makefile pcp/Makefile watchdog/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -14543,6 +14543,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "parser/Makefile") CONFIG_FILES="$CONFIG_FILES parser/Makefile" ;; "pcp/Makefile") CONFIG_FILES="$CONFIG_FILES pcp/Makefile" ;; + "watchdog/Makefile") CONFIG_FILES="$CONFIG_FILES watchdog/Makefile" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/main.c b/main.c index d97af2b37..43fd0af80 100644 --- a/main.c +++ b/main.c @@ -60,7 +60,7 @@ #include "parser/pool_string.h" #include "pool_passwd.h" #include "pool_memqcache.h" - +#include "watchdog/wd_ext.h" /* * Process pending signal actions. */ @@ -413,6 +413,9 @@ int main(int argc, char **argv) /* set signal masks */ poolinitmask(); + /* start watchdog */ + wd_main(1); + if (not_detach) write_pid_file(); else diff --git a/pgpool.conf.sample b/pgpool.conf.sample index fb600ae2e..f3268ef5a 100644 --- a/pgpool.conf.sample +++ b/pgpool.conf.sample @@ -416,6 +416,41 @@ client_idle_limit_in_recovery = 0 # -1 means immediate disconnection +#------------------------------------------------------------------------------ +# WATCHDOG +#------------------------------------------------------------------------------ +trusted_servers = '' + # trusted server list which are used + # to confirm network connection + # (hostA,hostB,hostC,...) +delegate_IP = '' + # delegate IP address +wd_port = 9000 + # port number for watchdog service +wd_interval = 10; + # lifecheck interval (sec) > 0 +ping_path = '/bin' + # ping command path +ifconfig_path = '/sbin' + # ifconfig command path +if_up_cmd = 'ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0' + # startup delegate IP command +if_down_cmd = 'ifconfig eth0:0 down' + # shutdown delegate IP command +wd_life_point = 3 + # lifecheck retry times +# Other pgpool Connection Settings + +#other_pgpool_hostname0 = 'host0' + # Host name or IP address to connect to for other pgpool 0 +#other_pgpool_port0 = 5432 + # Port number for othet pgpool 0 +#other_wd_port0 = 9000 + # Port number for othet watchdog 0 +#other_pgpool_hostname1 = 'host1' +#other_pgpool_port1 = 5432 +#other_wd_port1 = 9000 + #------------------------------------------------------------------------------ # OTHERS #------------------------------------------------------------------------------ diff --git a/pool_config.c b/pool_config.c index 1e83da887..ce7f51970 100644 --- a/pool_config.c +++ b/pool_config.c @@ -1,67 +1,112 @@ -/* A lexical scanner generated by flex*/ -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ +#line 3 "pool_config.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ +/* begin standard C headers. */ #include <stdio.h> -#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ +#ifndef FLEXINT_H +#define FLEXINT_H -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) #endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) #endif +#endif /* ! FLEXINT_H */ #ifdef __cplusplus -#include <stdlib.h> - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ -#if __STDC__ +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) -#define YY_USE_PROTOS #define YY_USE_CONST -#endif /* __STDC__ */ +#endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - /* Returned upon end-of-file. */ #define YY_NULL 0 @@ -76,80 +121,70 @@ * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ -#define BEGIN yy_start = 1 + 2 * +#define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ -#define YY_START ((yy_start - 1) / 2) +#define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) +#define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ +#ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 +#endif +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif extern int yyleng; + extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) -#define unput(c) yyunput( c, yytext_ptr ) +#define unput(c) yyunput( c, (yytext_ptr) ) -/* Some routines like yy_flex_realloc() are emitted as static but are - not called by all lexers. This generates warnings in some compilers, - notably GCC. Arrange to suppress these. */ -#ifdef __GNUC__ -#define YY_MAY_BE_UNUSED __attribute__((unused)) -#else -#define YY_MAY_BE_UNUSED +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; #endif -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; @@ -186,12 +221,16 @@ struct yy_buffer_state */ int yy_at_bol; + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; + #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process @@ -205,28 +244,38 @@ struct yy_buffer_state * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ -static YY_BUFFER_STATE yy_current_buffer = 0; +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". + * + * Returns the top of the stack, or NULL. */ -#define YY_CURRENT_BUFFER yy_current_buffer +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; - static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ +static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches @@ -234,69 +283,95 @@ static int yy_start = 0; /* start state number */ */ static int yy_did_buffer_switch_on_eof; -void yyrestart YY_PROTO(( FILE *input_file )); +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )) YY_MAY_BE_UNUSED; -static void yy_flex_free YY_PROTO(( void * )); +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) +/* Begin user sect3 */ -#define yywrap() 1 +#define yywrap(n) 1 #define YY_SKIP_YYWRAP + typedef unsigned char YY_CHAR; + FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + extern char *yytext; #define yytext_ptr yytext -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; + (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 11 #define YY_END_OF_BUFFER 12 -static yyconst short int yy_accept[38] = +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[38] = { 0, 0, 0, 12, 10, 2, 1, 10, 10, 10, 8, 7, 7, 9, 4, 2, 0, 3, 0, 5, 0, @@ -304,7 +379,7 @@ static yyconst short int yy_accept[38] = 5, 0, 0, 8, 7, 6, 0 } ; -static yyconst int yy_ec[256] = +static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, @@ -336,13 +411,13 @@ static yyconst int yy_ec[256] = 15, 15, 15, 15, 15 } ; -static yyconst int yy_meta[19] = +static yyconst flex_int32_t yy_meta[19] = { 0, 1, 1, 2, 1, 1, 1, 3, 3, 3, 4, 4, 1, 5, 4, 3, 1, 3, 3 } ; -static yyconst short int yy_base[45] = +static yyconst flex_int16_t yy_base[45] = { 0, 0, 0, 61, 86, 58, 86, 55, 14, 23, 43, 10, 46, 86, 28, 47, 40, 86, 16, 86, 22, @@ -351,7 +426,7 @@ static yyconst short int yy_base[45] = 70, 75, 77, 80 } ; -static yyconst short int yy_def[45] = +static yyconst flex_int16_t yy_def[45] = { 0, 37, 1, 37, 37, 37, 37, 38, 39, 37, 40, 9, 9, 37, 41, 37, 38, 37, 39, 37, 42, @@ -360,7 +435,7 @@ static yyconst short int yy_def[45] = 37, 37, 37, 37 } ; -static yyconst short int yy_nxt[105] = +static yyconst flex_int16_t yy_nxt[105] = { 0, 4, 5, 6, 7, 8, 9, 9, 10, 4, 11, 12, 13, 14, 14, 14, 4, 14, 14, 19, 23, @@ -376,7 +451,7 @@ static yyconst short int yy_nxt[105] = 37, 37, 37, 37 } ; -static yyconst short int yy_chk[105] = +static yyconst flex_int16_t yy_chk[105] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 11, @@ -395,6 +470,9 @@ static yyconst short int yy_chk[105] = static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; +extern int yy_flex_debug; +int yy_flex_debug = 0; + /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ @@ -404,7 +482,6 @@ static char *yy_last_accepting_cpos; #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "pool_config.l" -#define INITIAL 0 /* -*-pgsql-c-*- */ /* * @@ -464,9 +541,52 @@ static char *extract_string(char *value, POOL_TOKEN token); static char **extract_string_tokens(char *str, char *delim, int *n); static void clear_host_entry(int slot); -#define YY_NEVER_INTERACTIVE 1 -#define YY_NO_UNPUT 1 -#line 470 "pool_config.c" +#line 545 "pool_config.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -474,65 +594,28 @@ static void clear_host_entry(int slot); #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); +extern "C" int yywrap (void ); #else -extern int yywrap YY_PROTO(( void )); +extern int yywrap (void ); #endif #endif -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - #ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); +static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif +#ifdef __cplusplus +static int yyinput (void ); #else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 +static int input (void ); #endif -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif #endif /* Amount of stuff to slurp up with each read. */ @@ -541,12 +624,11 @@ YY_MALLOC_DECL #endif /* Copy whatever the last rule matched to the standard output. */ - #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -554,9 +636,10 @@ YY_MALLOC_DECL */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ - int c = '*', n; \ + int c = '*'; \ + unsigned n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -566,9 +649,22 @@ YY_MALLOC_DECL YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - @@ -589,12 +685,18 @@ YY_MALLOC_DECL #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif +/* end tables serialization structures and prototypes */ + /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. @@ -611,27 +713,29 @@ YY_MALLOC_DECL #define YY_RULE_SETUP \ YY_USER_ACTION +/** The main scanner function which does all the work. + */ YY_DECL - { +{ register yy_state_type yy_current_state; - register char *yy_cp = NULL, *yy_bp = NULL; + register char *yy_cp, *yy_bp; register int yy_act; - + #line 85 "pool_config.l" -#line 624 "pool_config.c" +#line 728 "pool_config.c" - if ( yy_init ) + if ( !(yy_init) ) { - yy_init = 0; + (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif - if ( ! yy_start ) - yy_start = 1; /* first start state */ + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; @@ -639,34 +743,36 @@ YY_DECL if ( ! yyout ) yyout = stdout; - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } - yy_load_buffer_state(); + yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { - yy_cp = yy_c_buf_p; + yy_cp = (yy_c_buf_p); /* Support of yytext. */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; - yy_current_state = yy_start; + yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { @@ -677,33 +783,28 @@ yy_match: yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 86 ); + while ( yy_current_state != 37 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } YY_DO_BEFORE_ACTION; - do_action: /* This label is used only to access EOF actions. */ - switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: +/* rule 1 can match eol */ YY_RULE_SETUP #line 87 "pool_config.l" Lineno++; return POOL_EOL; @@ -714,8 +815,8 @@ YY_RULE_SETUP /* eat whitespace */ YY_BREAK case 3: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp -= 1; +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +(yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP #line 89 "pool_config.l" @@ -761,33 +862,33 @@ YY_RULE_SETUP #line 100 "pool_config.l" ECHO; YY_BREAK -#line 765 "pool_config.c" +#line 866 "pool_config.c" case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our + * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position @@ -797,13 +898,13 @@ case YY_STATE_EOF(INITIAL): * end-of-buffer state). Contrast this with the test * in input(). */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have @@ -816,30 +917,31 @@ case YY_STATE_EOF(INITIAL): yy_next_state = yy_try_NUL_trans( yy_current_state ); - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; + yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { - yy_cp = yy_c_buf_p; + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } - else switch ( yy_get_next_buffer() ) + else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { - yy_did_buffer_switch_on_eof = 0; + (yy_did_buffer_switch_on_eof) = 0; - if ( yywrap() ) + if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up @@ -850,7 +952,7 @@ case YY_STATE_EOF(INITIAL): * YY_NULL, it'll still work - another * YY_NULL will get returned. */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; @@ -858,30 +960,30 @@ case YY_STATE_EOF(INITIAL): else { - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; @@ -892,8 +994,7 @@ case YY_STATE_EOF(INITIAL): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ - } /* end of yylex */ - +} /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * @@ -902,21 +1003,20 @@ case YY_STATE_EOF(INITIAL): * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); - if ( yy_current_buffer->yy_fill_buffer == 0 ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. @@ -936,34 +1036,30 @@ static int yy_get_next_buffer() /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); + (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { @@ -976,8 +1072,7 @@ static int yy_get_next_buffer() b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ @@ -987,35 +1082,35 @@ static int yy_get_next_buffer() YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - num_to_read = yy_current_buffer->yy_buf_size - + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; -#endif + } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); - yy_current_buffer->yy_n_chars = yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - if ( yy_n_chars == 0 ) + if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); + yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } @@ -1023,32 +1118,39 @@ static int yy_get_next_buffer() else ret_val = EOB_ACT_CONTINUE_SCAN; - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; - } - +} /* yy_get_previous_state - get the state just before the EOB char was reached */ -static yy_state_type yy_get_previous_state() - { + static yy_state_type yy_get_previous_state (void) +{ register yy_state_type yy_current_state; register char *yy_cp; + + yy_current_state = (yy_start); - yy_current_state = yy_start; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { @@ -1060,30 +1162,23 @@ static yy_state_type yy_get_previous_state() } return yy_current_state; - } - +} /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; + register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { @@ -1095,81 +1190,36 @@ yy_state_type yy_current_state; yy_is_jam = (yy_current_state == 37); return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - +} #ifndef YY_NO_INPUT #ifdef __cplusplus -static int yyinput() + static int yyinput (void) #else -static int input() + static int input (void) #endif - { - int c; - *yy_c_buf_p = yy_hold_char; +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ - *yy_c_buf_p = '\0'; + *(yy_c_buf_p) = '\0'; else { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); - switch ( yy_get_next_buffer() ) + switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() @@ -1183,16 +1233,16 @@ static int input() */ /* Reset buffer status. */ - yyrestart( yyin ); + yyrestart(yyin ); - /* fall through */ + /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { - if ( yywrap() ) + if ( yywrap( ) ) return EOF; - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); @@ -1202,90 +1252,92 @@ static int input() } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; + (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); return c; - } -#endif /* YY_NO_INPUT */ - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); +} +#endif /* ifndef YY_NO_INPUT */ - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); } + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) return; - if ( yy_current_buffer ) + if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - yy_current_buffer = new_buffer; - yy_load_buffer_state(); + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } + (yy_did_buffer_switch_on_eof) = 1; +} +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); @@ -1294,75 +1346,71 @@ int size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; - yy_init_buffer( b, file ); + yy_init_buffer(b,file ); return b; - } - +} -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - + yyfree((void *) b->yy_ch_buf ); + yyfree((void *) b ); +} -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) - { - yy_flush_buffer( b ); +{ + int oerrno = errno; + + yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif + b->yy_is_interactive = 0; + + errno = oerrno; +} - { - if ( ! b ) +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; b->yy_n_chars = 0; @@ -1379,29 +1427,125 @@ YY_BUFFER_STATE b; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; - if ( b == yy_current_buffer ) - yy_load_buffer_state(); + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; } + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); @@ -1415,56 +1559,51 @@ yy_size_t size; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; - yy_switch_to_buffer( b ); + yy_switch_to_buffer(b ); return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif +} +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; - + /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - b = yy_scan_buffer( buf, n ); + b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); @@ -1474,148 +1613,196 @@ int len; b->yy_is_our_buffer = 1; return b; - } +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 #endif +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; +/* Redefine yyless() so it works in section 3 code. */ - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); +/* Accessor methods (get/set functions) to struct members. */ - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} - yy_start_stack[yy_start_stack_ptr++] = YY_START; +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} - BEGIN(new_state); - } -#endif +/** Get the current token. + * + */ +char *yyget_text (void) +{ + return yytext; +} -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif +int yyget_debug (void) +{ + return yy_flex_debug; +} -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; #else -static void yy_fatal_error( msg ) -char msg[]; + yyin = (FILE *) 0; + yyout = (FILE *) 0; #endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } -/* Redefine yyless() so it works in section 3 code. */ + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + return 0; +} -/* Internal utility routines. */ +/* + * Internal utility routines. + */ #ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; - } +} #endif #ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { +static int yy_flex_strlen (yyconst char * s ) +{ register int n; for ( n = 0; s[n]; ++n ) ; return n; - } +} #endif - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { +void *yyalloc (yy_size_t size ) +{ return (void *) malloc( size ); - } +} -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { +void *yyrealloc (void * ptr, yy_size_t size ) +{ /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -1624,28 +1811,19 @@ yy_size_t size; * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); - } +} -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif #line 100 "pool_config.l" + int pool_init_config(void) { int res; @@ -1677,6 +1855,17 @@ int pool_init_config(void) } #endif + /* + * add for watchdog + */ + pool_config->other_wd = malloc(sizeof(WdDesc)); + if (pool_config->other_wd == NULL) + { + pool_error("failed to allocate pool_config->cwother_wd"); + return -1; + } + memset(pool_config->other_wd,0,sizeof(WdDesc)); + /* set hardcoded default values */ pool_config->listen_addresses = "localhost"; pool_config->port = 9999; @@ -1763,6 +1952,20 @@ int pool_init_config(void) pool_config->lists_patterns = NULL; pool_config->pattc = 0; pool_config->current_pattern_size = 0; + /* + * add for watchdog + */ + pool_config->trusted_servers = NULL; + pool_config->delegate_IP = NULL; + pool_config->wd_port = 9000; + pool_config->other_wd->num_wd = 0; + pool_config->wd_interval = 10; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_life_point = 3; + pool_config->memory_cache_enabled = 0; pool_config->memqcache_method = "shmem"; @@ -3389,6 +3592,206 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } pool_config->lobj_lock_table = str; } + /* + * add for watchdog + */ + else if (!strncmp(key, "other_pgpool_hostname", 21) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + char *str; + + slot = atoi(key + 21) ; + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_hostname out of range", key); + fclose(fd); + return(-1); + } + + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + strlcpy(WD_INFO(slot).hostname, str, WD_MAX_HOST_NAMELEN); + } + + else if (!strncmp(key, "other_pgpool_port", 17) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + + slot = atoi(key + 17); + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_port out of range", key); + fclose(fd); + return(-1); + } + + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + WD_INFO(slot).pgpool_port = atoi(yytext); + } + + else if (!strncmp(key, "other_pgpool_wd_port", 20) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + + slot = atoi(key + 20); + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_wd_port out of range", key); + fclose(fd); + return(-1); + } + + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + { + WD_INFO(slot).wd_port = atoi(yytext); + WD_INFO(slot).status = WD_INIT; + pool_config->other_wd->num_wd = slot+1; + } + } + else if (!strcmp(key, "trusted_servers") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->trusted_servers = str; + } + else if (!strcmp(key, "delegate_IP") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->delegate_IP = str; + } + else if (!strcmp(key, "wd_interval") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + int v = atoi(yytext); + + if (token != POOL_INTEGER || v <= 0) + { + pool_error("pool_config: %s must be higher than 1 numeric value", key); + fclose(fd); + return(-1); + } + pool_config->wd_interval = v; + } + else if (!strcmp(key, "ping_path") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->ping_path = str; + } + else if (!strcmp(key, "ifconfig_path") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->ifconfig_path = str; + } + else if (!strcmp(key, "if_up_cmd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->if_up_cmd = str; + } + else if (!strcmp(key, "if_down_cmd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->if_down_cmd = str; + } + else if (!strcmp(key, "wd_life_point") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + int v = atoi(yytext); + + if (token != POOL_INTEGER || v <= 0) + { + pool_error("pool_config: %s must be higher than 1 numeric value", key); + fclose(fd); + return(-1); + } + pool_config->wd_life_point = v; + } + else if (!strcmp(key, "ssl") && CHECK_CONTEXT(INIT_CONFIG, context)) { @@ -4107,3 +4510,4 @@ char *pool_flag_to_str(unsigned short flag) snprintf(buf, sizeof(buf), "DISALLOW_TO_FAILOVER"); return buf; } + diff --git a/pool_config.h b/pool_config.h index a118bfd51..f9eeb4ba5 100644 --- a/pool_config.h +++ b/pool_config.h @@ -26,6 +26,11 @@ #ifndef POOL_CONFIG_H #define POOL_CONFIG_H +/* + * watchdog + */ +#include "watchdog/watchdog.h" + /* * Master/slave sub mode */ @@ -205,6 +210,20 @@ typedef struct { RegPattern *lists_memqcache_table_patterns; /* Precompiled regex patterns for black/white lists */ int memqcache_table_pattc; /* number of regexp pattern */ int current_memqcache_table_pattern_size; /* size of the regex pattern array */ + + /* + * add for watchdog + */ + int wd_port; /* watchdog port */ + WdDesc * other_wd; /* watchdog lists */ + char * trusted_servers; /* icmp reachable server list (A,B,C) */ + char * delegate_IP; /* delegate IP address */ + int wd_interval; /* lifecheck interval (sec) */ + char * ping_path; /* path to ping command */ + char * ifconfig_path; /* path to ifconfig command */ + char * if_up_cmd; /* ifup command */ + char * if_down_cmd; /* ifdown command */ + int wd_life_point; /* life point (retry times at lifecheck) */ } POOL_CONFIG; typedef enum { diff --git a/pool_config.l b/pool_config.l index aaf3c301d..63e2b706b 100644 --- a/pool_config.l +++ b/pool_config.l @@ -130,6 +130,17 @@ int pool_init_config(void) } #endif + /* + * add for watchdog + */ + pool_config->other_wd = malloc(sizeof(WdDesc)); + if (pool_config->other_wd == NULL) + { + pool_error("failed to allocate pool_config->cwother_wd"); + return -1; + } + memset(pool_config->other_wd,0,sizeof(WdDesc)); + /* set hardcoded default values */ pool_config->listen_addresses = "localhost"; pool_config->port = 9999; @@ -216,6 +227,20 @@ int pool_init_config(void) pool_config->lists_patterns = NULL; pool_config->pattc = 0; pool_config->current_pattern_size = 0; + /* + * add for watchdog + */ + pool_config->trusted_servers = NULL; + pool_config->delegate_IP = NULL; + pool_config->wd_port = 9000; + pool_config->other_wd->num_wd = 0; + pool_config->wd_interval = 10; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_life_point = 3; + pool_config->memory_cache_enabled = 0; pool_config->memqcache_method = "shmem"; @@ -1842,6 +1867,206 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } pool_config->lobj_lock_table = str; } + /* + * add for watchdog + */ + else if (!strncmp(key, "other_pgpool_hostname", 21) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + char *str; + + slot = atoi(key + 21) ; + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_hostname out of range", key); + fclose(fd); + return(-1); + } + + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + strlcpy(WD_INFO(slot).hostname, str, WD_MAX_HOST_NAMELEN); + } + + else if (!strncmp(key, "other_pgpool_port", 17) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + + slot = atoi(key + 17); + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_port out of range", key); + fclose(fd); + return(-1); + } + + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + WD_INFO(slot).pgpool_port = atoi(yytext); + } + + else if (!strncmp(key, "other_pgpool_wd_port", 20) && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) && + mypid == getpid()) /* this parameter must be modified by parent pid */ + { + int slot; + + slot = atoi(key + 20); + if (slot < 0 || slot >= MAX_CONNECTION_SLOTS) + { + pool_error("pool_config: pgpool number %s for other_pgpool_wd_port out of range", key); + fclose(fd); + return(-1); + } + + if (context == INIT_CONFIG || (context == RELOAD_CONFIG )) + { + WD_INFO(slot).wd_port = atoi(yytext); + WD_INFO(slot).status = WD_INIT; + pool_config->other_wd->num_wd = slot+1; + } + } + else if (!strcmp(key, "trusted_servers") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->trusted_servers = str; + } + else if (!strcmp(key, "delegate_IP") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->delegate_IP = str; + } + else if (!strcmp(key, "wd_interval") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + int v = atoi(yytext); + + if (token != POOL_INTEGER || v <= 0) + { + pool_error("pool_config: %s must be higher than 1 numeric value", key); + fclose(fd); + return(-1); + } + pool_config->wd_interval = v; + } + else if (!strcmp(key, "ping_path") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->ping_path = str; + } + else if (!strcmp(key, "ifconfig_path") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->ifconfig_path = str; + } + else if (!strcmp(key, "if_up_cmd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->if_up_cmd = str; + } + else if (!strcmp(key, "if_down_cmd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->if_down_cmd = str; + } + else if (!strcmp(key, "wd_life_point") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + int v = atoi(yytext); + + if (token != POOL_INTEGER || v <= 0) + { + pool_error("pool_config: %s must be higher than 1 numeric value", key); + fclose(fd); + return(-1); + } + pool_config->wd_life_point = v; + } + else if (!strcmp(key, "ssl") && CHECK_CONTEXT(INIT_CONFIG, context)) { diff --git a/watchdog/Makefile.am b/watchdog/Makefile.am new file mode 100644 index 000000000..707f1961f --- /dev/null +++ b/watchdog/Makefile.am @@ -0,0 +1,15 @@ +noinst_LIBRARIES = lib-watchdog.a + +lib_watchdog_a_SOURCES = \ + watchdog.c \ + watchdog.h \ + wd_child.c \ + wd_ext.h \ + wd_if.c \ + wd_init.c \ + wd_lifecheck.c \ + wd_list.c \ + wd_packet.c \ + wd_ping.c + +AM_CPPFLAGS = -D_GNU_SOURCE -I .. -I @PGSQL_INCLUDE_DIR@ diff --git a/watchdog/Makefile.in b/watchdog/Makefile.in new file mode 100644 index 000000000..2ddc1ac15 --- /dev/null +++ b/watchdog/Makefile.in @@ -0,0 +1,492 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = watchdog +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/c-compiler.m4 \ + $(top_srcdir)/c-library.m4 $(top_srcdir)/general.m4 \ + $(top_srcdir)/ac_func_accept_argtypes.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +lib_watchdog_a_AR = $(AR) $(ARFLAGS) +lib_watchdog_a_LIBADD = +am_lib_watchdog_a_OBJECTS = watchdog.$(OBJEXT) wd_child.$(OBJEXT) \ + wd_if.$(OBJEXT) wd_init.$(OBJEXT) wd_lifecheck.$(OBJEXT) \ + wd_list.$(OBJEXT) wd_packet.$(OBJEXT) wd_ping.$(OBJEXT) +lib_watchdog_a_OBJECTS = $(am_lib_watchdog_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(lib_watchdog_a_SOURCES) +DIST_SOURCES = $(lib_watchdog_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PGCONFIG = @PGCONFIG@ +PGSQL_INCLUDE_DIR = @PGSQL_INCLUDE_DIR@ +PGSQL_LIB_DIR = @PGSQL_LIB_DIR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = lib-watchdog.a +lib_watchdog_a_SOURCES = \ + watchdog.c \ + watchdog.h \ + wd_child.c \ + wd_ext.h \ + wd_if.c \ + wd_init.c \ + wd_lifecheck.c \ + wd_list.c \ + wd_packet.c \ + wd_ping.c + +AM_CPPFLAGS = -D_GNU_SOURCE -I .. -I @PGSQL_INCLUDE_DIR@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu watchdog/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu watchdog/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +lib-watchdog.a: $(lib_watchdog_a_OBJECTS) $(lib_watchdog_a_DEPENDENCIES) + -rm -f lib-watchdog.a + $(lib_watchdog_a_AR) lib-watchdog.a $(lib_watchdog_a_OBJECTS) $(lib_watchdog_a_LIBADD) + $(RANLIB) lib-watchdog.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchdog.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_child.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_if.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_init.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_lifecheck.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_ping.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +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) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/watchdog/test/stab.c b/watchdog/test/stab.c new file mode 100644 index 000000000..0ad42c394 --- /dev/null +++ b/watchdog/test/stab.c @@ -0,0 +1,266 @@ +#include <stdio.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <wait.h> + +#include "pool.h" +#include "pool_config.h" + +#define MAXSTRFTIME 128 + +int debug = 0; + + +static char *nowsec(void); +static void child_wait(int signo); + +void pool_error(const char *fmt,...) +{ + va_list ap; +#ifdef HAVE_ASPRINTF + char *fmt2; + int len; +#endif + +#ifdef HAVE_SIGPROCMASK + sigset_t oldmask; +#else + int oldmask; +#endif + /* Write error message to syslog */ + if (pool_config->logsyslog == 1) { + va_start(ap, fmt); + vsyslog(pool_config->syslog_facility | LOG_ERR, fmt, ap); + va_end(ap); + return; + } + + POOL_SETMASK2(&BlockSig, &oldmask); + + if (pool_config->print_timestamp) +#ifdef HAVE_ASPRINTF + len = asprintf(&fmt2, "%s ERROR: pid %d: %s\n", nowsec(), (int)getpid(), fmt); + else + len = asprintf(&fmt2, "ERROR: pid %d: %s\n", (int)getpid(), fmt); + + if (len >= 0 && fmt2) + { + va_start(ap, fmt); + vfprintf(stderr, fmt2, ap); + va_end(ap); + fflush(stderr); + free(fmt2); + } +#else + fprintf(stderr, "%s ERROR: pid %d: ", nowsec(), (int)getpid()); + else + fprintf(stderr, "ERROR: pid %d: ", (int)getpid()); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +#endif + + POOL_SETMASK(&oldmask); +} + +void pool_debug(const char *fmt,...) +{ + va_list ap; +#ifdef HAVE_ASPRINTF + char *fmt2; + int len; +#endif + +#ifdef HAVE_SIGPROCMASK + sigset_t oldmask; +#else + int oldmask; +#endif + + if (1) + { + if (!debug) + return; + } + else + { + if (pool_config->debug_level <= 0) + return; + } + /* Write debug message to syslog */ + if (pool_config->logsyslog == 1) { + va_start(ap, fmt); + vsyslog(pool_config->syslog_facility | LOG_DEBUG, fmt, ap); + va_end(ap); + return; + } + + POOL_SETMASK2(&BlockSig, &oldmask); + + if (pool_config->print_timestamp) +#ifdef HAVE_ASPRINTF + len = asprintf(&fmt2, "%s DEBUG: pid %d: %s\n", nowsec(), (int)getpid(), fmt); + else + len = asprintf(&fmt2, "DEBUG: pid %d: %s\n", (int)getpid(), fmt); + + if (len >= 0 && fmt2) + { + va_start(ap, fmt); + vfprintf(stderr, fmt2, ap); + va_end(ap); + fflush(stderr); + free(fmt2); + } +#else + fprintf(stderr, "%s DEBUG: pid %d: ", nowsec(), (int)getpid()); + else + fprintf(stderr, "DEBUG: pid %d: ", (int)getpid()); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +#endif + + POOL_SETMASK(&oldmask); +} + +void pool_log(const char *fmt,...) +{ + va_list ap; +#ifdef HAVE_ASPRINTF + char *fmt2; + int len; +#endif + +#ifdef HAVE_SIGPROCMASK + sigset_t oldmask; +#else + int oldmask; +#endif + /* Write log message to syslog */ + if (pool_config->logsyslog == 1) { + va_start(ap, fmt); + vsyslog(pool_config->syslog_facility | LOG_NOTICE, fmt, ap); + va_end(ap); + return; + } + + POOL_SETMASK2(&BlockSig, &oldmask); + + if (pool_config->print_timestamp) +#ifdef HAVE_ASPRINTF + len = asprintf(&fmt2, "%s LOG: pid %d: %s\n", nowsec(), (int)getpid(), fmt); + else + len = asprintf(&fmt2, "LOG: pid %d: %s\n", (int)getpid(), fmt); + + if (len >= 0 && fmt2) + { + va_start(ap, fmt); + vfprintf(stderr, fmt2, ap); + va_end(ap); + fflush(stderr); + free(fmt2); + } +#else + fprintf(stderr, "%s LOG: pid %d: ", nowsec(), (int)getpid()); + else + fprintf(stderr, "LOG: pid %d: ", (int)getpid()); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +#endif + + POOL_SETMASK(&oldmask); +} + +static char *nowsec(void) +{ + static char strbuf[MAXSTRFTIME]; + time_t now = time(NULL); + + strftime(strbuf, MAXSTRFTIME, "%Y-%m-%d %H:%M:%S", localtime(&now)); + return strbuf; +} + +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) + { + while (--n != 0) + { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return (s - src - 1); /* count does not include NUL */ +} + +static void +child_wait(int signo) +{ + pid_t pid = 0; + + do { + int ret; + pid = waitpid(-1,&ret,WNOHANG); + } while(pid > 0); +} + +void +wd_exit(int exit_signo) +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, NULL); + + wd_notice_server_down(); + + pool_shmem_exit(1); + + kill (0, exit_signo); + + child_wait(0); + + exit(0); +} + +int pool_memset_system_db_info (SystemDBInfo *info) +{ + return 0; +} + +int +pool_query_cache_table_exists(void) +{ + return 0; +} + diff --git a/watchdog/test/test.c b/watchdog/test/test.c new file mode 100644 index 000000000..56440be43 --- /dev/null +++ b/watchdog/test/test.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +pid_t mypid; + +static void wdlist_dump(void); +extern void wd_exit(int exit_signo); + +int +main(int argc, char * argv[]) +{ + int rtn; + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, wd_exit); + signal(SIGQUIT, wd_exit); + signal(SIGTERM, wd_exit); + signal(SIGPIPE, SIG_IGN); + + mypid = getpid(); + rtn = pool_init_config(); + + pool_config->recovery_user = "mitani"; + pool_config->trusted_servers = "paris"; + pool_config->delegate_IP = "192.168.100.99"; + pool_config->pgpool2_hostname = "vm1"; + pool_config->port = 5432; + pool_config->wd_port = 9999; + pool_config->other_wd->num_wd = 2; + strcpy(pool_config->other_wd->wd_info[0].hostname ,"vm2"); + pool_config->other_wd->wd_info[0].pgpool_port = 5432; + pool_config->other_wd->wd_info[0].wd_port = 9999; + pool_config->other_wd->wd_info[0].status = WD_INIT; + strcpy(pool_config->other_wd->wd_info[1].hostname ,"paris"); + pool_config->other_wd->wd_info[1].pgpool_port = 5432; + pool_config->other_wd->wd_info[1].wd_port = 9999; + pool_config->other_wd->wd_info[1].status = WD_INIT; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_interval = 3; + pool_config->wd_life_point = 1; + + wd_main(3); + + for (;;) + { + wdlist_dump(); + sleep(5); + } + wd_exit(15); + +} + + +static void +wdlist_dump(void) +{ + int i; + WdInfo * p = WD_List; + + i = 0; + while (p->status != WD_END) + { + printf("%d:s[%d] ts[%d] tu[%d] h[%s] pp[%d] wp[%d]\n", + i,p->status, + p->tv.tv_sec, p->tv.tv_usec, + p->hostname, + p->pgpool_port, + p->wd_port); + p++; + i++; + } +} diff --git a/watchdog/test/wd_child_t.c b/watchdog/test/wd_child_t.c new file mode 100644 index 000000000..b9e69e847 --- /dev/null +++ b/watchdog/test/wd_child_t.c @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +pid_t mypid; +WdInfo * WD_List = NULL; /* watchdog server list */ + +static void wdlist_dump(void); +extern void wd_exit(int exit_signo); + +int +main(int argc, char * argv[]) +{ + int rtn; + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, wd_exit); + signal(SIGQUIT, wd_exit); + signal(SIGTERM, wd_exit); + signal(SIGPIPE, SIG_IGN); + + mypid = getpid(); + rtn = pool_init_config(); + + pool_config->recovery_user = "mitani"; + pool_config->trusted_servers = "paris"; + pool_config->delegate_IP = "192.168.100.99"; + pool_config->pgpool2_hostname = "vm1"; + pool_config->port = 5432; + pool_config->wd_port = 9999; + pool_config->other_wd->num_wd = 2; + strcpy(pool_config->other_wd->wd_info[0].hostname ,"vm2"); + pool_config->other_wd->wd_info[0].pgpool_port = 5432; + pool_config->other_wd->wd_info[0].wd_port = 9999; + pool_config->other_wd->wd_info[0].status = WD_INIT; + strcpy(pool_config->other_wd->wd_info[1].hostname ,"paris"); + pool_config->other_wd->wd_info[1].pgpool_port = 5432; + pool_config->other_wd->wd_info[1].wd_port = 9999; + pool_config->other_wd->wd_info[1].status = WD_INIT; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_interval = 3; + pool_config->wd_life_point = 1; + + wd_init(); + + wd_child(1); + + for (;;) + { + wdlist_dump(); + sleep(5); + } + +} + + +static void +wdlist_dump(void) +{ + int i; + WdInfo * p = WD_List; + + i = 0; + while (p->status != WD_END) + { + printf("%d:s[%d] ts[%d] tu[%d] h[%s] pp[%d] wp[%d]\n", + i,p->status, + p->tv.tv_sec, p->tv.tv_usec, + p->hostname, + p->pgpool_port, + p->wd_port); + p++; + i++; + } +} diff --git a/watchdog/test/wd_lifecheck_t.c b/watchdog/test/wd_lifecheck_t.c new file mode 100644 index 000000000..e1628287d --- /dev/null +++ b/watchdog/test/wd_lifecheck_t.c @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +pid_t mypid; +WdInfo * WD_List = NULL; /* watchdog server list */ + +static void wdlist_dump(void); +extern void wd_exit(int exit_signo); + +int +main(int argc, char * argv[]) +{ + int rtn; + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, wd_exit); + signal(SIGQUIT, wd_exit); + signal(SIGTERM, wd_exit); + signal(SIGPIPE, SIG_IGN); + + mypid = getpid(); + rtn = pool_init_config(); + + pool_config->recovery_user = "mitani"; + pool_config->trusted_servers = "paris"; + pool_config->delegate_IP = "192.168.100.99"; + pool_config->pgpool2_hostname = "vm1"; + pool_config->port = 5432; + pool_config->wd_port = 9999; + pool_config->other_wd->num_wd = 2; + strcpy(pool_config->other_wd->wd_info[0].hostname ,"vm2"); + pool_config->other_wd->wd_info[0].pgpool_port = 5432; + pool_config->other_wd->wd_info[0].wd_port = 9999; + pool_config->other_wd->wd_info[0].status = WD_INIT; + strcpy(pool_config->other_wd->wd_info[1].hostname ,"paris"); + pool_config->other_wd->wd_info[1].pgpool_port = 5432; + pool_config->other_wd->wd_info[1].wd_port = 9999; + pool_config->other_wd->wd_info[1].status = WD_INIT; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_interval = 3; + pool_config->wd_life_point = 1; + + wd_init(); + + for (;;) + { + wdlist_dump(); + wd_lifecheck(); + sleep(pool_config->wd_interval); + } + wd_exit(15); + +} + + +static void +wdlist_dump(void) +{ + int i; + WdInfo * p = WD_List; + + i = 0; + while (p->status != WD_END) + { + printf("%d:s[%d] ts[%d] tu[%d] h[%s] pp[%d] wp[%d]\n", + i,p->status, + p->tv.tv_sec, p->tv.tv_usec, + p->hostname, + p->pgpool_port, + p->wd_port); + p++; + i++; + } +} diff --git a/watchdog/test/wd_packet_t.c b/watchdog/test/wd_packet_t.c new file mode 100644 index 000000000..0740a117e --- /dev/null +++ b/watchdog/test/wd_packet_t.c @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +pid_t mypid; +WdInfo * WD_List = NULL; /* watchdog server list */ + +static void wdlist_dump(void); +extern void wd_exit(int exit_signo); + +int +main(int argc, char * argv[]) +{ + int rtn; + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, wd_exit); + signal(SIGQUIT, wd_exit); + signal(SIGTERM, wd_exit); + signal(SIGPIPE, SIG_IGN); + + mypid = getpid(); + rtn = pool_init_config(); + + pool_config->recovery_user = "mitani"; + pool_config->trusted_servers = "paris"; + pool_config->delegate_IP = "192.168.100.99"; + pool_config->pgpool2_hostname = "vm1"; + pool_config->port = 5432; + pool_config->wd_port = 9999; + pool_config->other_wd->num_wd = 2; + strcpy(pool_config->other_wd->wd_info[0].hostname ,"vm2"); + pool_config->other_wd->wd_info[0].pgpool_port = 5432; + pool_config->other_wd->wd_info[0].wd_port = 9999; + pool_config->other_wd->wd_info[0].status = WD_INIT; + strcpy(pool_config->other_wd->wd_info[1].hostname ,"paris"); + pool_config->other_wd->wd_info[1].pgpool_port = 5432; + pool_config->other_wd->wd_info[1].wd_port = 9999; + pool_config->other_wd->wd_info[1].status = WD_INIT; + pool_config->ping_path = "/bin"; + pool_config->ifconfig_path = "/sbin"; + pool_config->if_up_cmd = "ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0"; + pool_config->if_down_cmd = "ifconfig eth0:0 down"; + pool_config->wd_interval = 3; + pool_config->wd_life_point = 1; + + wd_init(); + + for (;;) + { + wdlist_dump(); + sleep(5); + wd_lifecheck(); + } + wd_exit(15); + +} + + +static void +wdlist_dump(void) +{ + int i; + WdInfo * p = WD_List; + + i = 0; + while (p->status != WD_END) + { + printf("%d:s[%d] ts[%d] tu[%d] h[%s] pp[%d] wp[%d]\n", + i,p->status, + p->tv.tv_sec, p->tv.tv_usec, + p->hostname, + p->pgpool_port, + p->wd_port); + p++; + i++; + } +} diff --git a/watchdog/test/wd_ping_t.c b/watchdog/test/wd_ping_t.c new file mode 100644 index 000000000..0b90178f9 --- /dev/null +++ b/watchdog/test/wd_ping_t.c @@ -0,0 +1,20 @@ +#include <stdio.h> +#include "watchdog.h" + +extern int wd_is_upper_ok(char * server_list); + +int +main(int argc,char * argv[]) +{ + int rtn; + rtn = wd_is_upper_ok(argv[1]); + if (rtn == WD_OK) + { + printf("%s is ok",argv[1]); + } + else + { + printf("%s is ng",argv[1]); + } + return 0; +} diff --git a/watchdog/watchdog.c b/watchdog/watchdog.c new file mode 100644 index 000000000..fee2cad31 --- /dev/null +++ b/watchdog/watchdog.c @@ -0,0 +1,125 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <wait.h> +#include <ctype.h> +#include <sys/un.h> +#include <unistd.h> +#include <sys/wait.h> +#include <errno.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +WdInfo * WD_List = NULL; /* watchdog server list */ + +int wd_main(int fork_wait_time); +static void child_wait(int signo); +static void wd_exit(int exit_status); + +static void +child_wait(int signo) +{ + pid_t pid = 0; + + do { + int ret; + pid = waitpid(-1,&ret,WNOHANG); + } while(pid > 0); +} + +static void +wd_exit(int exit_signo) +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, NULL); + + wd_notice_server_down(); + + kill (0, exit_signo); + + child_wait(0); + + exit(0); +} + +int +wd_main(int fork_wait_time) +{ + int status = WD_INIT; + pid_t pgid = 0; + pid_t pid = 0; + + /* initialize */ + status = wd_init(); + if (status < 0) + { + return WD_NG; + } + + /* launch child process */ + status = wd_child(1); + if (status != WD_OK) + { + return WD_NG; + } + + pgid = getpgid(0); + pid = fork(); + if (pid != 0) + { + return WD_OK; + } + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, wd_exit); + signal(SIGQUIT, wd_exit); + signal(SIGTERM, wd_exit); + signal(SIGPIPE, SIG_IGN); + setpgid(0,pgid); + + if (fork_wait_time > 0) { + sleep(fork_wait_time); + } + + /* watchdog loop */ + for (;;) + { + /* pgpool life check */ + wd_lifecheck(); + sleep(pool_config->wd_interval); + } +} diff --git a/watchdog/watchdog.h b/watchdog/watchdog.h new file mode 100644 index 000000000..38cce57ef --- /dev/null +++ b/watchdog/watchdog.h @@ -0,0 +1,112 @@ +/* -*-pgsql-c-*- */ +/* + * + * $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. + * + * watchdog.h.: watchdog definition header file + * + */ + +#ifndef WATCHDOG_H +#define WATCHDOG_H + +#include <sys/time.h> +#include "libpq-fe.h" + +#define WD_MAX_HOST_NAMELEN (128) +#define MAX_WATCHDOG_NUM (128) +#define WD_SEND_TIMEOUT (1) + +#define WD_INFO(wd_id) (pool_config->other_wd->wd_info[(wd_id)]) + +#define WD_NG (0) +#define WD_OK (1) + +/* + * packet number of watchdog negotiation + */ +typedef enum { + WD_INVALID = 0, /* invalid packet no */ + WD_ADD_REQ, /* add request into the watchdog list */ + WD_ADD_ACCEPT, /* accept the add request */ + WD_ADD_REJECT, /* reject the add request */ + WD_STAND_FOR_MASTER, /* announce candidacy */ + WD_VOTE_YOU, /* agree to the candidacy */ + WD_MASTER_EXIST, /* disagree to the candidacy */ + WD_DECLARE_NEW_MASTER, /* announce assumption */ + WD_SERVER_DOWN, /* announce server down */ + WD_READY /* answer to the announce */ +} WD_PACKET_NO; + +/* + * watchdog status + */ +typedef enum { + WD_END = 0, + WD_INIT, + WD_NORMAL, + WD_MASTER, + WD_DOWN +}WD_STATUS; + +/* + * watchdog list + */ +typedef struct { + WD_STATUS status; /* status */ + struct timeval tv; /* startup time value */ + char hostname[WD_MAX_HOST_NAMELEN]; /* host name */ + int pgpool_port; /* pgpool port */ + int wd_port; /* watchdog port */ + int life; /* life point */ +}WdInfo; + +typedef struct { + int num_wd; /* number of watchdogs */ + WdInfo wd_info[MAX_WATCHDOG_NUM]; +} WdDesc; + +/* + * negotiation paket + */ +typedef struct { + WD_PACKET_NO packet_no; /* packet number */ + WdInfo wd_info; /* watchdog information */ +} WdPacket; + +/* + * thread argument for watchdog negotiation + */ +typedef struct { + int sock; /* socket */ + WdInfo * target; /* target watchdog information */ + WdPacket * packet; /* packet data */ +} WdPacketThreadArg; + +/* + * thread argument for lifecheck of pgpool + */ +typedef struct { + PGconn * conn; /* PGconn */ + int retry; /* retry times */ +} WdPgpoolThreadArg; + +extern WdInfo * WD_List; + +#endif /* WATCHDOG_H */ diff --git a/watchdog/wd_child.c b/watchdog/wd_child.c new file mode 100644 index 000000000..b976986fd --- /dev/null +++ b/watchdog/wd_child.c @@ -0,0 +1,199 @@ +/* -*-pgsql-c-*- */ +/* + * $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. + * + * child.c: child process main + * + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/time.h> +#include "watchdog.h" +#include "wd_ext.h" + +int wd_child(int fork_wait_time); +static void child_exit(int exit_signo); +static int send_response(int sock, WdPacket * recv_pack); + +int +wd_child(int fork_wait_time) +{ + int sock; + int fd; + int rtn; + pid_t pgid = 0; + pid_t pid = 0; + + pgid = getpgid(0); + pid = fork(); + if (pid != 0) + { + return WD_OK; + } + + signal(SIGTERM, child_exit); + signal(SIGINT, child_exit); + signal(SIGQUIT, child_exit); + signal(SIGCHLD, child_exit); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, SIG_IGN); + setpgid(0,pgid); + + if (fork_wait_time > 0) + { + sleep(fork_wait_time); + } + if (WD_List == NULL) + { + /* memory allocate is not ready */ + child_exit(15); + } + sock = wd_create_recv_socket(WD_List->wd_port); + if (sock < 0) + { + /* socket create failed */ + child_exit(15); + } + /* child loop */ + for(;;) + { + WdPacket buf; + fd = wd_accept(sock); + if (fd < 0) + { + continue; + } + rtn = wd_recv_packet(fd, &buf); + if (rtn == WD_OK) + { + send_response(fd,&buf); + } + close(fd); + } +} + +static void +child_exit(int exit_signo) +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, NULL); + + exit(0); +} + +static int +send_response(int sock, WdPacket * recv_pack) +{ + int rtn = WD_NG; + WdInfo * p; + WdPacket send_packet; + struct timeval tv; + + if (recv_pack == NULL) + { + return rtn; + } + memset(&send_packet, 0, sizeof(WdPacket)); + p = &(recv_pack->wd_info); + + /* set response packet no */ + switch (recv_pack->packet_no) + { + case WD_ADD_REQ: + p = &(recv_pack->wd_info); + if (wd_set_wd_list(p->hostname,p->pgpool_port, p->wd_port, &(p->tv), p->status) > 0) + { + send_packet.packet_no = WD_ADD_ACCEPT; + } + else + { + send_packet.packet_no = WD_ADD_REJECT; + } + memcpy(&(send_packet.wd_info), WD_List, sizeof(WdInfo)); + break; + case WD_STAND_FOR_MASTER: + p = &(recv_pack->wd_info); + wd_set_wd_list(p->hostname,p->pgpool_port, p->wd_port, &(p->tv), p->status); + /* check exist master */ + if ((p = wd_is_exist_master()) != NULL) + { + /* vote against the candidate */ + send_packet.packet_no = WD_MASTER_EXIST; + memcpy(&(send_packet.wd_info), p, sizeof(WdInfo)); + } + else + { + if (WD_List->tv.tv_sec <= p->tv.tv_sec ) + { + memcpy(&tv,&(p->tv),sizeof(struct timeval)); + tv.tv_sec += 1; + wd_set_myself(&tv, WD_NORMAL); + } + /* vote for the candidate */ + send_packet.packet_no = WD_VOTE_YOU; + memcpy(&(send_packet.wd_info), WD_List, sizeof(WdInfo)); + } + break; + case WD_DECLARE_NEW_MASTER: + p = &(recv_pack->wd_info); + wd_set_wd_list(p->hostname,p->pgpool_port, p->wd_port, &(p->tv), p->status); + if (WD_List->status == WD_MASTER) + { + /* resign master server */ + wd_IP_down(); + wd_set_myself(NULL, WD_NORMAL); + } + send_packet.packet_no = WD_READY; + memcpy(&(send_packet.wd_info), WD_List, sizeof(WdInfo)); + break; + case WD_SERVER_DOWN: + p = &(recv_pack->wd_info); + wd_set_wd_list(p->hostname,p->pgpool_port, p->wd_port, &(p->tv), WD_DOWN); + send_packet.packet_no = WD_READY; + memcpy(&(send_packet.wd_info), WD_List, sizeof(WdInfo)); + if (wd_am_I_oldest() == WD_OK) + { + wd_escalation(); + } + break; + defalt: + send_packet.packet_no = WD_INVALID; + memcpy(&(send_packet.wd_info), WD_List, sizeof(WdInfo)); + break; + } + + /* send response packet */ + rtn = wd_send_packet(sock, &send_packet); + return rtn; +} diff --git a/watchdog/wd_ext.h b/watchdog/wd_ext.h new file mode 100644 index 000000000..6c8114e05 --- /dev/null +++ b/watchdog/wd_ext.h @@ -0,0 +1,67 @@ +/* -*-pgsql-c-*- */ +/* + * + * $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. + * + * wd_ext.h.: watchdog extern definition header file + * + */ + +#ifndef WD_EXT_H +#define WD_EXT_H +/* watchdog.c */ +extern int wd_main(int fork_wait_time); + +/* wd_child.c */ +extern int wd_child(int fork_wait_time); + +/* wd_init.c */ +extern int wd_init(void); + +/* wd_list.c */ +extern int wd_set_wd_list(char * hostname, int pgpool_port, int wd_port, struct timeval * tv, int status); +extern int wd_add_wd_list(WdDesc * other_wd); +extern int wd_set_wd_info(WdInfo * info); +extern WdInfo * wd_is_exist_master(void); +extern int wd_am_I_oldest(void); +extern int wd_set_myself(struct timeval * tv, int status); + +/* wd_packet.c */ +extern int wd_startup(void); +extern int wd_declare(void); +extern int wd_stand_for_master(void); +extern int wd_notice_server_down(void); +extern int wd_create_send_socket(char * hostname, int port); +extern int wd_create_recv_socket(int port); +extern int wd_accept(int sock); +extern int wd_send_packet(int sock, WdPacket * snd_pack); +extern int wd_recv_packet(int sock, WdPacket * buf); +extern int wd_escalation(void); + +/* wd_ping.c */ +extern int wd_is_upper_ok(char * server_list); + +/* wd_if.c */ +extern int wd_IP_up(void); +extern int wd_IP_down(void); + +/* wd_lifecheck.c */ +extern int wd_lifecheck(void); + +#endif /* WD_EXT_H */ diff --git a/watchdog/wd_if.c b/watchdog/wd_if.c new file mode 100644 index 000000000..9e349ab97 --- /dev/null +++ b/watchdog/wd_if.c @@ -0,0 +1,144 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <errno.h> +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" + +int wd_IP_up(void); +int wd_IP_down(void); +static int exec_ifconfig(char * command); + +int +wd_IP_up(void) +{ + int rtn; + rtn = exec_ifconfig(pool_config->if_up_cmd); + return rtn; +} +int +wd_IP_down(void) +{ + int rtn; + rtn = exec_ifconfig(pool_config->if_down_cmd); + return rtn; +} + +static int +exec_ifconfig(char * command) +{ + int pfd[2]; + int status; + char * args[24]; + int pid, i = 0; + char ifconfig_path[128]; + char buf[256]; + char *bp, *ep; + + sprintf(ifconfig_path,"%s/ifconfig",pool_config->ifconfig_path); + if (pipe(pfd) == -1) + { + pool_error("pipe open error:%s",strerror(errno)); + return WD_NG; + } + memset(buf,0,sizeof(buf)); + strncpy(buf,command,sizeof(buf)); + bp = buf; + while (*bp == ' ') + { + bp ++; + } + while (*bp != '\0') + { + ep = strchr(bp,' '); + if (ep != NULL) + { + *ep = '\0'; + } + if (!strncmp(bp,"$_IP_$",5)) + { + args[i++] = pool_config->delegate_IP; + } + else + { + args[i++] = bp; + } + if (ep != NULL) + { + bp = ep +1; + while (*bp == ' ') + { + bp ++; + } + } + else + { + break; + } + } + args[i++] = NULL; + + pid = fork(); + if (pid == 0) + { + close(STDOUT_FILENO); + dup2(pfd[1], STDOUT_FILENO); + close(pfd[0]); + status = execv(ifconfig_path,args); + exit(0); + } + else + { + close(pfd[1]); + for (;;) + { + int result; + result = wait(&status); + if (result < 0) + { + if (errno == EINTR) + continue; + return WD_NG; + } + + if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) + return WD_NG; + else + break; + } + close(pfd[0]); + } + return WD_OK; +} + + diff --git a/watchdog/wd_init.c b/watchdog/wd_init.c new file mode 100644 index 000000000..43494eca2 --- /dev/null +++ b/watchdog/wd_init.c @@ -0,0 +1,79 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/time.h> +#include <unistd.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +int wd_init(void); + +int +wd_init(void) +{ + struct timeval tv; + + /* set startup time */ + gettimeofday(&tv, NULL); + + /* allocate watchdog list */ + if (WD_List == NULL) + { + WD_List = pool_shared_memory_create(sizeof(WdInfo) * MAX_WATCHDOG_NUM); + if (WD_List == NULL) + { + pool_error("failed to allocate watchdog list"); + return WD_NG; + } + memset(WD_List, 0, sizeof(WdInfo) * MAX_WATCHDOG_NUM); + } + /* set myself to watchdog list */ + wd_set_wd_list(pool_config->pgpool2_hostname, pool_config->port, pool_config->wd_port, &tv, WD_NORMAL); + /* set other pgpools to watchdog list */ + wd_add_wd_list(pool_config->other_wd); + + /* check upper connection */ + if (wd_is_upper_ok(pool_config->trusted_servers) != WD_OK) + { + pool_error("failed to connect trusted server"); + return WD_NG; + } + + /* send startup packet */ + wd_startup(); + + /* check existence of master pgpool */ + if (wd_is_exist_master() == NULL ) + { + /* escalate to delegate_IP holder */ + wd_escalation(); + } + + return WD_OK; +} diff --git a/watchdog/wd_lifecheck.c b/watchdog/wd_lifecheck.c new file mode 100644 index 000000000..220fda66e --- /dev/null +++ b/watchdog/wd_lifecheck.c @@ -0,0 +1,216 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ +#include <pthread.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <netdb.h> +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +#include "libpq-fe.h" + +int wd_lifecheck(void); +static void * ping_pgpool(void * arg); +static PGconn * create_conn(char * hostname, int port); +static int pgpool_down(WdInfo * pool); + +int +wd_lifecheck(void) +{ + WdInfo * p = WD_List; + pthread_attr_t attr; + int rc; + int i,cnt; + struct timeval tv; + pthread_t thread[MAX_WATCHDOG_NUM]; + WdPgpoolThreadArg thread_arg[MAX_WATCHDOG_NUM]; + + /* set startup time */ + gettimeofday(&tv, NULL); + + /* check upper connection */ + if (wd_is_upper_ok(pool_config->trusted_servers) != WD_OK) + { + pool_error("failed to connect trusted server"); + /* This server connection may be downwd */ + if (p->status == WD_MASTER) + { + wd_IP_down(); + } + wd_set_myself(&tv, WD_DOWN); + wd_notice_server_down(); + return WD_NG; + } + + /* thread init */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + /* send packet to all watchdogs */ + cnt = 0; + while (p->status != WD_END) + { + thread_arg[cnt].conn = create_conn(p->hostname, p->pgpool_port); + rc = pthread_create(&thread[cnt], &attr, ping_pgpool, (void*)&thread_arg[cnt]); + p ++; + cnt ++; + if (cnt >= MAX_WATCHDOG_NUM) + { + pool_error("trusted server num is out of range(%d)",cnt); + break; + } + } + pthread_attr_destroy(&attr); + p = WD_List; + for (i = 0; i < cnt; ) + { + int result; + rc = pthread_join(thread[i], (void **)&result); + if ((rc != 0) && (errno == EINTR)) + { + usleep(100); + continue; + } + if (result == WD_OK) + { + p->life = pool_config->wd_life_point; + if ((i == 0) && + (WD_List->status == WD_DOWN)) + { + wd_set_myself(&tv, WD_NORMAL); + wd_startup(); + /* check existence of master pgpool */ + if (wd_is_exist_master() == NULL ) + { + /* escalate to delegate_IP holder */ + wd_escalation(); + } + } + } + else + { + if (p->life > 0) + { + p->life --; + } + if (p->life <= 0) + { + if ((i == 0) && + (WD_List->status != WD_DOWN)) + { + wd_set_myself(&tv, WD_DOWN); + wd_notice_server_down(); + } + else + { + pgpool_down(p); + } + } + } + pthread_detach(thread[i]); + i++; + p++; + } + return WD_OK; +} + +static void * +ping_pgpool(void * arg) +{ + WdPgpoolThreadArg * thread_arg; + PGconn * conn; + uintptr_t rtn = (uintptr_t)WD_NG; + int status = PGRES_FATAL_ERROR; + PGresult * res = (PGresult *)NULL; + thread_arg = (WdPgpoolThreadArg *)arg; + conn = thread_arg->conn; + + res = PQexec(conn, "SELECT 1" ); + + status = PQresultStatus(res); + if (res != NULL) + { + PQclear(res); + } + if ((status != PGRES_NONFATAL_ERROR ) && + (status != PGRES_FATAL_ERROR )) + { + rtn = WD_OK; + } + PQfinish(conn); + pthread_exit((void *)rtn); +} + +static PGconn * +create_conn(char * hostname, int port) +{ + char port_str[16]; + PGconn *conn; + + snprintf(port_str, sizeof(port_str), + "%d", port); + conn = PQsetdbLogin(hostname, + port_str, + NULL, + NULL, + "template1", + pool_config->recovery_user, + pool_config->recovery_password); + + if (PQstatus(conn) != CONNECTION_OK) + { + PQfinish(conn); + return NULL; + } + return conn; +} + +static int +pgpool_down(WdInfo * pool) +{ + int rtn = WD_DOWN; + if ((WD_List->status == WD_NORMAL) && + (pool->status == WD_MASTER)) + { + pool->status = WD_DOWN; + if (wd_am_I_oldest() == WD_OK) + { + /* stand for master */ + rtn = wd_stand_for_master(); + if (rtn == WD_OK) + { + /* win */ + wd_escalation(); + } + } + } + pool->status = WD_DOWN; + return rtn; +} diff --git a/watchdog/wd_list.c b/watchdog/wd_list.c new file mode 100644 index 000000000..a883f66af --- /dev/null +++ b/watchdog/wd_list.c @@ -0,0 +1,169 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/time.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" + +int wd_set_wd_list(char * hostname, int pgpool_port, int wd_port, struct timeval * tv, int status); +int wd_add_wd_list(WdDesc * other_wd); +int wd_set_wd_info(WdInfo * info); +WdInfo * wd_is_exist_master(void); +int wd_am_I_oldest(void); +int wd_set_myself(struct timeval * tv, int status); + +int +wd_set_wd_list(char * hostname, int pgpool_port, int wd_port, struct timeval * tv, int status) +{ + int i = 0; + WdInfo * p = NULL; + + if ((WD_List == NULL) || (hostname == NULL)) + { + pool_error("memory allocate error"); + return -1; + } + for ( i = 0 ; i < MAX_WATCHDOG_NUM ; i ++) + { + p = (WD_List+i); + if( p->status != WD_END) + { + if ((!strncmp(p->hostname, hostname, sizeof(p->hostname))) && + (p->pgpool_port == pgpool_port) && + (p->wd_port == wd_port)) + { + if (tv != NULL) + { + memcpy(&(p->tv),tv,sizeof(struct timeval)); + } + p->status = status; + return i; + } + } + else + { + strncpy(p->hostname, hostname, sizeof(p->hostname)); + p->pgpool_port = pgpool_port; + p->wd_port = wd_port; + if (tv != NULL) + { + memcpy(&(p->tv),tv,sizeof(struct timeval)); + } + p->status = status; + return i; + } + } + pool_error("Can not add new watchdog information cause the WD_List is full."); + return -1; +} + +int +wd_add_wd_list(WdDesc * other_wd) +{ + WdInfo * p = NULL; + int i = 0; + + if (other_wd == NULL) + { + pool_error("memory allocate error"); + return -1; + } + for ( i = 0 ; i < other_wd->num_wd ; i ++) + { + p = &(other_wd->wd_info[i]); + wd_set_wd_info(p); + } + return i; +} + +int +wd_set_wd_info(WdInfo * info) +{ + int rtn; + rtn = wd_set_wd_list(info->hostname, info->pgpool_port, info->wd_port, &(info->tv), info->status); + return rtn; +} + +WdInfo * +wd_is_exist_master(void) +{ + WdInfo * p = WD_List; + + p++; + while (p->status != WD_END) + { + /* find master pgpool in the other servers */ + if (p->status == WD_MASTER) + { + /* master found */ + return p; + } + p++; + } + /* not found */ + return NULL; +} + +int +wd_am_I_oldest(void) +{ + WdInfo * p = WD_List; + + p++; + while (p->status != WD_END) + { + if ((p->status == WD_NORMAL) || + (p->status == WD_MASTER)) + { + if ((p->tv.tv_sec < WD_List->tv.tv_sec) || + ((p->tv.tv_sec == WD_List->tv.tv_sec) && + (p->tv.tv_usec < WD_List->tv.tv_usec))) + { + return WD_NG; + } + } + p++; + } + return WD_OK; + +} + +int +wd_set_myself(struct timeval * tv, int status) +{ + if (WD_List == NULL) + { + return WD_NG; + } + if (tv != NULL) + { + memcpy(&(WD_List->tv),tv,sizeof(struct timeval)); + } + WD_List->status = status; + return WD_OK; +} diff --git a/watchdog/wd_packet.c b/watchdog/wd_packet.c new file mode 100644 index 000000000..db12ca499 --- /dev/null +++ b/watchdog/wd_packet.c @@ -0,0 +1,630 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <fcntl.h> + +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" +#include "wd_ext.h" + +int wd_startup(void); +int wd_declare(void); +int wd_stand_for_master(void); +int wd_notice_server_down(void); +int wd_create_send_socket(char * hostname, int port); +int wd_create_recv_socket(int port); +int wd_accept(int sock); +int wd_send_packet(int sock, WdPacket * snd_pack); +int wd_recv_packet(int sock, WdPacket * buf); +int wd_escalation(void); +static void * wd_negotiation(void * arg); +static int send_packet_4_all(WdPacket *packet); +static int hton_wd_packet(WdPacket * to, WdPacket * from); +static int ntoh_wd_packet(WdPacket * to, WdPacket * from); + +int +wd_startup(void) +{ + int rtn; + WdPacket packet; + + /* set add request packet */ + packet.packet_no = WD_ADD_REQ; + memcpy(&(packet.wd_info),WD_List,sizeof(WdInfo)); + /* send packet to all watchdogs */ + rtn = send_packet_4_all(&packet); + return rtn; +} + +int +wd_declare(void) +{ + int rtn; + WdPacket packet; + + /* set declare new master packet */ + packet.packet_no = WD_DECLARE_NEW_MASTER; + memcpy(&(packet.wd_info),WD_List,sizeof(WdInfo)); + /* send packet to all watchdogs */ + rtn = send_packet_4_all(&packet); + return rtn; +} + +int +wd_stand_for_master(void) +{ + int rtn; + WdPacket packet; + + /* set staqnd for master packet */ + packet.packet_no = WD_STAND_FOR_MASTER; + memcpy(&(packet.wd_info),WD_List,sizeof(WdInfo)); + /* send packet to all watchdogs */ + rtn = send_packet_4_all(&packet); + return rtn; +} + +int +wd_notice_server_down(void) +{ + int rtn; + WdPacket packet; + + wd_IP_down(); + /* set notice server down packet */ + packet.packet_no = WD_SERVER_DOWN; + memcpy(&(packet.wd_info),WD_List,sizeof(WdInfo)); + /* send packet to all watchdogs */ + rtn = send_packet_4_all(&packet); + return rtn; +} + +int +wd_create_send_socket(char * hostname, int port) +{ + int sock; + int one = 1; + size_t len = 0; + struct sockaddr_in addr; + struct hostent * hp; + + /* create socket */ + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + /* socket create failed */ + return -1; + } + + /* set socket option */ + if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1 ) + { + return -1; + } + if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)) == -1 ) + { + return -1; + } + + /* set sockaddr_in */ + memset(&addr,0,sizeof(addr)); + addr.sin_family = AF_INET; + hp = gethostbyname(hostname); + if ((hp == NULL) || (hp->h_addrtype != AF_INET)) + { + hp = gethostbyaddr(hostname,strlen(hostname),AF_INET); + if ((hp == NULL) || (hp->h_addrtype != AF_INET)) + { + pool_error("gethostbyname() failed: %s host: %s", hstrerror(h_errno), hostname); + close(sock); + return -1; + } + } + memmove((char *)&(addr.sin_addr), (char *)hp->h_addr, hp->h_length); + addr.sin_port = htons(port); + len = sizeof(struct sockaddr_in); + + /* try to connect */ + for (;;) + { + fd_set wmask; + fd_set emask; + struct timeval timeout; + int sockErrVal = 0; + int rtn; + socklen_t sockErrValLen = sizeof(int); + + timeout.tv_sec = WD_SEND_TIMEOUT; + timeout.tv_usec = 0; + + FD_ZERO(&wmask); + FD_ZERO(&emask); + FD_SET(sock,&wmask); + FD_SET(sock,&emask); + + rtn = select(sock+1, NULL, &wmask, &emask, &timeout ); + if ( rtn < 0 ) + { + if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + { + continue; + } + /* connection failed */ + break; + } + else if ( rtn == 0 ) + { + /* timeout */ + break; + } + else if ( FD_ISSET(sock, &emask) ) + { + /* socket exception occured */ + break; + } + + if ( getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&sockErrVal, &sockErrValLen) == 0 && sockErrVal != 0 ) + { + /* error occured on this socket while connecting to target */ + break; + } + + rtn = connect(sock,(struct sockaddr*)&addr, len); + if ( rtn < 0 ) + { + if ( errno == EINPROGRESS || errno == EALREADY || errno == EWOULDBLOCK || errno == EINTR || errno == 0 ) + continue; + else if ( errno == EISCONN ) + { + return sock; + } + pool_error("connect() is failed,(%s)",strerror(errno)); + break; + } + return sock; + } + close(sock); + return -1; +} + +int +wd_create_recv_socket(int port) +{ + size_t len = 0; + struct sockaddr_in addr; + int one = 1; + int sock = -1; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + /* socket create failed */ + return -1; + } + if ( fcntl(sock, F_SETFL, O_NONBLOCK) == -1) + { + /* failed to set nonblock */ + close(sock); + return -1; + } + if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1 ) + { + /* setsockopt(SO_REUSEADDR) failed */ + close(sock); + return -1; + } + if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1 ) + { + /* setsockopt(TCP_NODELAY) failed */ + close(sock); + return -1; + } + if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)) == -1 ) + { + /* setsockopt(SO_KEEPALIVE) failed */ + close(sock); + return -1; + } + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + len = sizeof(struct sockaddr_in); + + if ( bind(sock, (struct sockaddr *) & addr, len) < 0 ) + { + /* bind failed */ + close(sock); + return -1; + } + + if ( listen(sock, MAX_WATCHDOG_NUM * 2) < 0 ) + { + /* listen failed */ + close(sock); + return -1; + } + + return sock; +} + +int +wd_accept(int sock) +{ + int fd = -1; + fd_set rmask; + fd_set emask; + int rtn; + struct sockaddr addr; + socklen_t addrlen = sizeof(struct sockaddr); + + for (;;) + { + FD_ZERO(&rmask); + FD_ZERO(&emask); + FD_SET(sock,&rmask); + FD_SET(sock,&emask); + + rtn = select(sock+1, &rmask, NULL, &emask, NULL ); + if ( rtn < 0 ) + { + if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + { + continue; + } + /* connection failed */ + break; + } + else if ( rtn == 0 ) + { + /* connection failed */ + break; + } + else if ( FD_ISSET(sock, &emask) ) + { + /* socket exception occured */ + break; + } + else if ( FD_ISSET(sock, &rmask) ) + { + fd = accept(sock, &addr, &addrlen); + if (fd < 0) + { + if ( errno == EINTR || errno == 0 || errno == EAGAIN || errno == EWOULDBLOCK ) + { + /* nothing to accept now */ + continue; + } + /* accept failed */ + return -1; + } + return fd; + } + } + return -1; +} + +int +wd_send_packet(int sock, WdPacket * snd_pack) +{ + fd_set wmask; + struct timeval timeout; + char * send_ptr = NULL; + int send_size= 0; + int buf_size = 0; + int s = 0; + int flag = 0; + int rtn; + WdPacket buf; + + memset(&buf,0,sizeof(WdPacket)); + hton_wd_packet((WdPacket *)&buf,snd_pack); + send_ptr = (char*)&buf; + buf_size = sizeof(WdPacket); + + for (;;) + { + timeout.tv_sec = WD_SEND_TIMEOUT; + timeout.tv_usec = 0; + + FD_ZERO(&wmask); + FD_SET(sock,&wmask); + rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout); + + if (rtn < 0 ) + { + if (errno == EAGAIN || errno == EINTR) + { + continue; + } + return WD_NG; + } + else if (rtn & FD_ISSET(sock, &wmask)) + { + s = send(sock,send_ptr + send_size,buf_size - send_size ,flag); + if (s < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + /* send failed */ + return WD_NG; + } + } + else if (s == 0) + { + /* send failed */ + return WD_NG; + } + else /* s > 0 */ + { + send_size += s; + if (send_size == buf_size) + { + return WD_OK; + } + } + } + } + return WD_NG; +} + +int +wd_recv_packet(int sock, WdPacket * recv_pack) +{ + int cnt = 0; + int r = 0; + WdPacket buf; + char * read_ptr = (char *)&buf; + int read_size = 0; + int len = sizeof(WdPacket); + cnt = 0; + + memset(&buf,0,sizeof(WdPacket)); + for (;;) + { + r = recv(sock,read_ptr + read_size ,len - read_size, 0); + if (r < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + return WD_NG; + } + } + else if (r > 0) + { + read_size += r; + if (read_size == len) + { + ntoh_wd_packet(recv_pack,&buf); + return WD_OK; + } + } + else /* r == 0 */ + { + return WD_NG; + } + } + return WD_NG; +} + +static void * +wd_negotiation(void * arg) +{ + WdPacketThreadArg * thread_arg; + int sock; + uintptr_t rtn; + WdPacket recv_packet; + WdInfo * p; + + thread_arg = (WdPacketThreadArg *)arg; + sock = thread_arg->sock; + + /* packet send to target watchdog */ + rtn = (uintptr_t)wd_send_packet(sock, thread_arg->packet); + if (rtn != WD_OK) + { + close(sock); + pthread_exit((void *)rtn); + } + + /* receive response packet */ + memset(&recv_packet,0,sizeof(WdPacket)); + rtn = (uintptr_t)wd_recv_packet(sock, &recv_packet); + if (rtn != WD_OK) + { + close(sock); + pthread_exit((void *)rtn); + } + rtn = WD_OK; + switch (thread_arg->packet->packet_no) + { + case WD_ADD_REQ: + if (recv_packet.packet_no == WD_ADD_ACCEPT) + { + memcpy(thread_arg->target, &(recv_packet.wd_info),sizeof(WdInfo)); + } + else + { + rtn = WD_NG; + } + break; + case WD_STAND_FOR_MASTER: + if (recv_packet.packet_no == WD_MASTER_EXIST) + { + p = &(recv_packet.wd_info); + wd_set_wd_info(p); + rtn = WD_NG; + } + break; + case WD_DECLARE_NEW_MASTER: + if (recv_packet.packet_no != WD_READY) + { + rtn = WD_NG; + } + break; + default: + break; + } + close(sock); + pthread_exit((void *)rtn); +} + +static int +send_packet_4_all(WdPacket *packet) +{ + int rtn; + WdInfo * p = WD_List; + int i,cnt; + int sock; + int rc; + pthread_attr_t attr; + pthread_t thread[MAX_WATCHDOG_NUM]; + WdPacketThreadArg thread_arg[MAX_WATCHDOG_NUM]; + + if (packet == NULL) + { + return WD_NG; + } + + /* thread init */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + /* send packet to all watchdogs */ + p++; + cnt = 0; + while (p->status != WD_END) + { + sock = wd_create_send_socket(p->hostname, p->wd_port); + if (sock == -1) + { + p++; + continue; + } + thread_arg[cnt].sock = sock; + thread_arg[cnt].target = p; + thread_arg[cnt].packet = packet; + rc = pthread_create(&thread[cnt], &attr, wd_negotiation, (void*)&thread_arg[cnt]); + cnt ++; + p++; + } + + pthread_attr_destroy(&attr); + rtn = (packet->packet_no == WD_STAND_FOR_MASTER)?WD_OK:WD_NG; + for (i=0; i<cnt; ) + { + int result; + rc = pthread_join(thread[i], (void **)&result); + if ((rc != 0) && (errno == EINTR)) + { + usleep(100); + continue; + } + if (packet->packet_no == WD_STAND_FOR_MASTER) + { + if (result == WD_NG) + { + rtn = WD_NG; + } + } + else + { + if (result == WD_OK) + { + rtn = WD_OK; + } + } + pthread_detach(thread[i]); + i++; + } + + return rtn; +} + +static int +hton_wd_packet(WdPacket * to, WdPacket * from) +{ + if ((to == NULL) || (from == NULL)) + { + return WD_NG; + } + to->packet_no = htonl(from->packet_no); + to->wd_info.status = htonl(from->wd_info.status); + to->wd_info.tv.tv_sec = htonl(from->wd_info.tv.tv_sec); + to->wd_info.tv.tv_usec = htonl(from->wd_info.tv.tv_usec); + to->wd_info.pgpool_port = htonl(from->wd_info.pgpool_port); + to->wd_info.wd_port = htonl(from->wd_info.wd_port); + memcpy(to->wd_info.hostname,from->wd_info.hostname,sizeof(to->wd_info.hostname)); + return WD_OK; +} + +static int +ntoh_wd_packet(WdPacket * to, WdPacket * from) +{ + if ((to == NULL) || (from == NULL)) + { + return WD_NG; + } + to->packet_no = ntohl(from->packet_no); + to->wd_info.status = ntohl(from->wd_info.status); + to->wd_info.tv.tv_sec = ntohl(from->wd_info.tv.tv_sec); + to->wd_info.tv.tv_usec = ntohl(from->wd_info.tv.tv_usec); + to->wd_info.pgpool_port = ntohl(from->wd_info.pgpool_port); + to->wd_info.wd_port = ntohl(from->wd_info.wd_port); + memcpy(to->wd_info.hostname,from->wd_info.hostname,sizeof(to->wd_info.hostname)); + return WD_OK; +} + +int +wd_escalation(void) +{ + int rtn; + + /* interface up as delegate IP */ + wd_IP_up(); + /* set master status to the wd list */ + wd_set_wd_list(pool_config->pgpool2_hostname, pool_config->port, pool_config->wd_port, NULL, WD_MASTER); + + /* send declare packet */ + rtn = wd_declare(); + + return rtn; +} diff --git a/watchdog/wd_ping.c b/watchdog/wd_ping.c new file mode 100644 index 000000000..2b134f615 --- /dev/null +++ b/watchdog/wd_ping.c @@ -0,0 +1,228 @@ +/* + * $Header$ + * + * Handles watchdog connection, and protocol communication with pgpool-II + * + * 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. + * + */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <errno.h> +#include "pool.h" +#include "pool_config.h" +#include "watchdog.h" + +int wd_is_upper_ok(char * server_list); + +static void * exec_ping(void * arg); +static double get_result (char * ping_data); + +int +wd_is_upper_ok(char * server_list) +{ + pthread_attr_t attr; + char * buf; + int rc = 0; + int i,cnt; + int len; + pthread_t thread[MAX_WATCHDOG_NUM]; + WdInfo thread_arg[MAX_WATCHDOG_NUM]; + + char * bp, *ep; + int rtn = WD_NG; + + if (server_list == NULL) + { + return WD_NG; + } + len = strlen(server_list)+2; + buf = malloc(len); + memset(buf,0,len); + strncpy(buf,server_list,len); + /* thread init */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + /* set hostname as a thread_arg */ + bp = buf; + cnt = 0; + while (*bp != '\0') + { + ep = strchr(bp,','); + if (ep != NULL) + { + *ep = '\0'; + } + strncpy(thread_arg[cnt].hostname,bp,sizeof(thread_arg[cnt].hostname)); + rc = pthread_create(&thread[cnt], &attr, exec_ping, (void*)&thread_arg[cnt]); + + cnt ++; + if (ep != NULL) + { + bp = ep + 1; + } + else + { + break; + } + if (cnt >= MAX_WATCHDOG_NUM) + { + /* +pool_error("trusted server num is out of range(%d)",cnt); + */ + break; + } + } + pthread_attr_destroy(&attr); + for (i=0; i <cnt; ) + { + int result; + rc = pthread_join(thread[i], (void **)&result); + if ((rc != 0) && (errno == EINTR)) + { + usleep(100); + continue; + } + if (result == WD_OK) + { + rtn = WD_OK; + } + pthread_detach(thread[i]); + i++; + } + free(buf); + return rtn; +} + +static void * +exec_ping(void * arg) +{ + WdInfo * thread_arg; + uintptr_t rtn = (uintptr_t)WD_NG; + int pfd[2]; + int status; + char * args[8]; + int pid, i = 0; + int r_size = 0; + char result[256]; + char ping_path[128]; + + sprintf(ping_path,"%s/ping",pool_config->ping_path); + thread_arg = (WdInfo *)arg; + memset(result,0,sizeof(result)); + if (pipe(pfd) == -1) + { + fprintf(stderr,"pipe open error:%s\n",strerror(errno)); + return NULL; + } + + args[i++] = "ping"; + args[i++] = "-q"; + args[i++] = "-c3"; + args[i++] = thread_arg->hostname; + args[i++] = NULL; + + pid = fork(); + if (pid == 0) + { + close(STDOUT_FILENO); + dup2(pfd[1], STDOUT_FILENO); + close(pfd[0]); + status = execv(ping_path,args); + exit(0); + } + else + { + close(pfd[1]); + for (;;) + { + int r; + r = wait(&status); + if (r < 0) + { + if (errno == EINTR) + continue; + return NULL; + } + + if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) + return NULL; + else + break; + } + i = 0; + while (( (r_size = read (pfd[0], &result[i], sizeof(result)-i)) > 0) && (errno == EINTR)) + { + i += r_size; + } + close(pfd[0]); + } + rtn = (get_result (result) > 0)?WD_OK:WD_NG; + pthread_exit((void *)rtn); +} + +static double +get_result (char * ping_data) +{ + char * sp = NULL; + char * ep = NULL; + int i; + double msec = 0; + + if (ping_data == NULL) + { + return -1; + } + /* + skip result until average data + tipical result of ping is as follows, + "rtt min/avg/max/mdev = 0.045/0.045/0.046/0.006 ms" + we can find the average data beyond the 4th '/'. + */ + sp = ping_data; + for ( i = 0 ; i < 4 ; i ++) + { + sp = strchr(sp,'/'); + if (sp == NULL) + { + return -1; + } + sp ++; + } + ep = strchr (sp,'/'); + if (ep == NULL) + { + return -1; + } + *ep = '\0'; + errno = 0; + /* convert to numeric data from text */ + msec = strtod(sp,(char **)NULL); + if (errno != 0) + { + return -1; + } + return msec; +} [parent: 1cd60b0597de]