]> git.8kb.co.uk Git - pgpool-ii/pgpool-ii_2.2.5/blob - pool_config.l
Attempt to send a proper failure message to frontend when authentication
[pgpool-ii/pgpool-ii_2.2.5] / pool_config.l
1 /* -*-pgsql-c-*- */
2 /*
3  *
4  * $Header: /cvsroot/pgpool/pgpool-II/pool_config.l,v 1.24 2009/01/25 10:13:15 t-ishii Exp $
5  *
6  * pgpool: a language independent connection pool server for PostgreSQL 
7  * written by Tatsuo Ishii
8  *
9  * Copyright (c) 2003-2009      PgPool Global Development Group
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby
13  * granted, provided that the above copyright notice appear in all
14  * copies and that both that copyright notice and this permission
15  * notice appear in supporting documentation, and that the name of the
16  * author not be used in advertising or publicity pertaining to
17  * distribution of the software without specific, written prior
18  * permission. The author makes no representations about the
19  * suitability of this software for any purpose.  It is provided "as
20  * is" without express or implied warranty.
21  *
22  * pool_config.l: read configuration file
23  *
24  */
25
26 %{
27
28 #include "pool.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #define CHECK_CONTEXT(mask, context) ((mask) & (context))
35
36 /* to shut off compiler warnings */
37 int yylex(void);
38
39 POOL_CONFIG *pool_config;       /* configuration values */
40 POOL_SYSTEMDB_CONNECTION_POOL *system_db_info;
41 static unsigned Lineno;
42 static char *default_reset_query_list[] = {"ABORT", "RESET ALL", "SET SESSION AUTHORIZATION DEFAULT"};
43
44 typedef enum {
45   POOL_KEY = 1,
46   POOL_INTEGER,
47   POOL_REAL,
48   POOL_STRING,
49   POOL_UNQUOTED_STRING,
50   POOL_EQUALS,
51   POOL_EOL,
52   POOL_PARSE_ERROR
53 } POOL_TOKEN;
54
55 static char *extract_string(char *value, POOL_TOKEN token);
56 static char **extract_string_tokens(char *str, char *delim, int *n);
57 static int eval_logical(char *str);
58 static void clear_host_entry(int slot);
59
60 %}
61
62 %option 8bit
63 %option never-interactive
64 %option nounput
65 %option noyywrap
66
67 SIGN            ("-"|"+")
68 DIGIT           [0-9]
69 HEXDIGIT        [0-9a-fA-F]
70
71 INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+)
72
73 EXPONENT        [Ee]{SIGN}?{DIGIT}+
74 REAL            {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
75
76 LETTER          [A-Za-z_\200-\377]
77 LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
78
79 KEY              {LETTER}{LETTER_OR_DIGIT}*
80
81 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
82 STRING          \'([^'\n]|\\.)*\'
83
84 %%
85
86 \n              Lineno++; return POOL_EOL;
87 [ \t\r]+        /* eat whitespace */
88 #.*$            /* eat comment */
89
90 {KEY}           return POOL_KEY;
91 {STRING}        return POOL_STRING;
92 {UNQUOTED_STRING} return POOL_UNQUOTED_STRING;
93 {INTEGER}       return POOL_INTEGER;
94 {REAL}          return POOL_REAL;
95 =               return POOL_EQUALS;
96
97 .               return POOL_PARSE_ERROR;
98
99 %%
100
101 int pool_init_config(void)
102 {
103         int res;
104         static char localhostname[256];
105         int i;
106
107         pool_config = malloc(sizeof(POOL_CONFIG));
108         if (pool_config == NULL)
109         {
110                 pool_error("failed to allocate pool_config");
111                 return(-1);
112         }
113
114         memset(pool_config, 0, sizeof(POOL_CONFIG));
115
116         pool_config->backend_desc = pool_shared_memory_create(sizeof(BackendDesc));
117         if (pool_config->backend_desc == NULL)
118         {
119                 pool_error("failed to allocate pool_config->backend_desc");
120                 return -1;
121         }
122
123         /* set hardcoded default values */
124         pool_config->listen_addresses = "localhost";
125         pool_config->port = 9999;
126         pool_config->pcp_port = 9898;
127         pool_config->socket_dir = DEFAULT_SOCKET_DIR;
128         pool_config->pcp_socket_dir = DEFAULT_SOCKET_DIR;
129         pool_config->backend_socket_dir = DEFAULT_SOCKET_DIR;
130         pool_config->pcp_timeout = 10;
131         pool_config->num_init_children = 32;
132         pool_config->max_pool = 4;
133         pool_config->child_life_time = 300;
134         pool_config->client_idle_limit = 0;
135         pool_config->connection_life_time = 0;
136         pool_config->child_max_connections = 0;
137         pool_config->authentication_timeout = 60;
138         pool_config->logdir = DEFAULT_LOGDIR;
139         pool_config->pid_file_name = DEFAULT_PID_FILE_NAME;
140         pool_config->log_statement = 0;
141         pool_config->log_connections = 0;
142         pool_config->log_hostname = 0;
143         pool_config->enable_pool_hba = 0;
144
145         pool_config->replication_mode = 0;
146         pool_config->load_balance_mode = 0;
147         pool_config->replication_stop_on_mismatch = 0;
148         pool_config->replicate_select = 0;
149         pool_config->reset_query_list = default_reset_query_list;
150         pool_config->num_reset_queries = sizeof(default_reset_query_list)/sizeof(char *);
151         pool_config->reset_query_list = default_reset_query_list;
152         pool_config->print_timestamp = 1;
153         pool_config->master_slave_mode = 0;
154         pool_config->connection_cache = 1;
155         pool_config->health_check_timeout = 20;
156         pool_config->health_check_period = 0;
157         pool_config->health_check_user = "nobody";
158         pool_config->failover_command = "";
159         pool_config->failback_command = "";
160         pool_config->insert_lock = 1;
161         pool_config->ignore_leading_white_space = 1;
162         pool_config->parallel_mode = 0;
163         pool_config->enable_query_cache = 0;
164         pool_config->system_db_hostname = "localhost";
165         pool_config->system_db_port = 5432;
166         pool_config->system_db_dbname = "pgpool";
167         pool_config->system_db_schema = "pgpool_catalog";
168         pool_config->system_db_user = "pgpool";
169         pool_config->system_db_password = "";
170         pool_config->backend_desc->num_backends = 0;
171     pool_config->recovery_user = "";
172     pool_config->recovery_password = "";
173     pool_config->recovery_1st_stage_command = "";
174     pool_config->recovery_2nd_stage_command = "";
175         pool_config->recovery_timeout = 90;
176         pool_config->client_idle_limit_in_recovery = 0;
177
178         res = gethostname(localhostname,sizeof(localhostname));
179         if(res !=0 )
180         {
181                 pool_debug("faild to get this hostname");
182         }
183         pool_config->pgpool2_hostname = localhostname;
184
185         for (i=0;i<MAX_CONNECTION_SLOTS;i++)
186         {
187                 clear_host_entry(i);
188         }
189         return 0;
190 }
191
192 int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context)
193 {
194         FILE *fd;
195         int token;
196         char key[1024];
197         double total_weight;
198         int i;
199
200 #define PARSE_ERROR()           pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
201
202         /* open config file */
203         fd = fopen(confpath, "r");
204         if (!fd)
205         {
206                 fprintf(stderr, "pool_config: could not open configuration file (%s)\n",
207                                 POOL_CONF_FILE_NAME);
208                 fprintf(stderr, "pool_config: using default values...\n");
209                 return 0;
210         }
211
212         yyin = fd;
213         Lineno = 1;
214
215         while ((token = yylex()))
216         {
217                 if (token == POOL_PARSE_ERROR)
218                 {
219                         PARSE_ERROR();
220                         fclose(fd);
221                         return(-1);
222                 }
223                 if (token == POOL_EOL)
224                         continue;
225
226                 if (token != POOL_KEY)
227                 {
228                         PARSE_ERROR();
229                         fclose(fd);
230                         return(-1);
231                 }
232
233                 strncpy(key, yytext, sizeof(key));
234
235                 pool_debug("key: %s", key);
236
237                 token = yylex();
238
239                 if (token == POOL_EQUALS)
240                         token = yylex();
241
242                 pool_debug("value: %s kind: %d", yytext, token);
243
244                 if (!strcmp(key, "allow_inet_domain_socket") && CHECK_CONTEXT(INIT_CONFIG, context))
245                 {
246                         /* for backward compatibility */
247                         int v = eval_logical(yytext);
248
249                         if (v < 0)
250                         {
251                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
252                                 fclose(fd);
253                                 return(-1);
254                         }
255                         if (v)
256                                 pool_config->listen_addresses = strdup("*");
257                         else
258                                 pool_config->listen_addresses = strdup("");
259                 }
260                 else if (!strcmp(key, "listen_addresses") && CHECK_CONTEXT(INIT_CONFIG, context))
261                 {
262                         char *str;
263
264                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
265                         {
266                                 PARSE_ERROR();
267                                 fclose(fd);
268                                 return(-1);
269                         }
270                         str = extract_string(yytext, token);
271                         if (str == NULL)
272                         {
273                                 fclose(fd);
274                                 return(-1);
275                         }
276                         pool_config->listen_addresses = str;
277                 }
278
279                 else if (!strcmp(key, "port") && CHECK_CONTEXT(INIT_CONFIG, context))
280                 {
281                         int v = atoi(yytext);
282
283                         if (token != POOL_INTEGER || v < 1024)
284                         {
285                                 pool_error("pool_config: %s must be 1024 or higher numeric value", key);
286                                 fclose(fd);
287                                 return(-1);
288                         }
289                         pool_config->port = v;
290                 }
291                 else if (!strcmp(key, "pcp_port") && CHECK_CONTEXT(INIT_CONFIG, context))
292                 {
293                         int v = atoi(yytext);
294
295                         if (token != POOL_INTEGER || v < 1024)
296                         {
297                                 pool_error("pool_config: %s must be 1024 or higher numeric value", key);
298                                 fclose(fd);
299                                 return(-1);
300                         }
301                         pool_config->pcp_port = v;
302                 }
303                 else if (!strcmp(key, "socket_dir") && CHECK_CONTEXT(INIT_CONFIG, context))
304                 {
305                         char *str;
306
307                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
308                         {
309                                 PARSE_ERROR();
310                                 fclose(fd);
311                                 return(-1);
312                         }
313                         str = extract_string(yytext, token);
314                         if (str == NULL)
315                         {
316                                 fclose(fd);
317                                 return(-1);
318                         }
319                         pool_config->socket_dir = str;
320                 }
321                 else if (!strcmp(key, "pcp_socket_dir") && CHECK_CONTEXT(INIT_CONFIG, context))
322                 {
323                         char *str;
324
325                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
326                         {
327                                 PARSE_ERROR();
328                                 fclose(fd);
329                                 return(-1);
330                         }
331                         str = extract_string(yytext, token);
332                         if (str == NULL)
333                         {
334                                 fclose(fd);
335                                 return(-1);
336                         }
337                         pool_config->pcp_socket_dir = str;
338                 }
339                 else if (!strcmp(key, "pcp_timeout") &&
340                          CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
341                 {
342                         int v = atoi(yytext);
343
344                         if (token != POOL_INTEGER || v < 0)
345                         {
346                                 pool_error("pool_config: %s must be equal or greater or equal to 0 numeric value", key);
347                                 fclose(fd);
348                                 return(-1);
349                         }
350                         pool_config->pcp_timeout = v;
351                 }
352                 else if (!strcmp(key, "num_init_children") && CHECK_CONTEXT(INIT_CONFIG, context))
353                 {
354                         int v = atoi(yytext);
355
356                         if (token != POOL_INTEGER || v < 1)
357                         {
358                                 pool_error("pool_config: %s must be higher than 1 numeric value", key);
359                                 fclose(fd);
360                                 return(-1);
361                         }
362                         pool_config->num_init_children = v;
363                 }
364                 else if (!strcmp(key, "child_life_time") &&
365                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
366                 {
367                         int v = atoi(yytext);
368
369                         if (token != POOL_INTEGER || v < 0)
370                         {
371                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
372                                 fclose(fd);
373                                 return(-1);
374                         }
375                         pool_config->child_life_time = v;
376                 }
377                 else if (!strcmp(key, "client_idle_limit") &&
378                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
379                 {
380                         int v = atoi(yytext);
381
382                         if (token != POOL_INTEGER || v < 0)
383                         {
384                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
385                                 fclose(fd);
386                                 return(-1);
387                         }
388                         pool_config->client_idle_limit = v;
389                 }
390                 else if (!strcmp(key, "connection_life_time") &&
391                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
392                 {
393                         int v = atoi(yytext);
394
395                         if (token != POOL_INTEGER || v < 0)
396                         {
397                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
398                                 fclose(fd);
399                                 return(-1);
400                         }
401                         pool_config->connection_life_time = v;
402                 }
403                 else if (!strcmp(key, "child_max_connections") &&
404                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
405                 {
406                         int v = atoi(yytext);
407
408                         if (token != POOL_INTEGER || v < 0)
409                         {
410                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
411                                 fclose(fd);
412                                 return(-1);
413                         }
414                         pool_config->child_max_connections = v;
415                 }
416                 else if (!strcmp(key, "authentication_timeout") &&
417                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
418                 {
419                         int v = atoi(yytext);
420
421                         if (token != POOL_INTEGER || v < 0)
422                         {
423                                 pool_error("pool_config: %s must be higher than 0 numeric value", key);
424                                 fclose(fd);
425                                 return(-1);
426                         }
427                         pool_config->authentication_timeout = v;
428                 }
429                 else if (!strcmp(key, "max_pool") && CHECK_CONTEXT(INIT_CONFIG, context))
430                 {
431                         int v = atoi(yytext);
432
433                         if (token != POOL_INTEGER || v < 0)
434                         {
435                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
436                                 fclose(fd);
437                                 return(-1);
438                         }
439                         pool_config->max_pool = v;
440                 }
441                 else if (!strcmp(key, "logdir") && CHECK_CONTEXT(INIT_CONFIG, context))
442                 {
443                         char *str;
444
445                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
446                         {
447                                 PARSE_ERROR();
448                                 fclose(fd);
449                                 return(-1);
450                         }
451                         str = extract_string(yytext, token);
452                         if (str == NULL)
453                         {
454                                 fclose(fd);
455                                 return(-1);
456                         }
457                         pool_config->logdir = str;
458                 }
459                 else if (!strcmp(key, "pid_file_name") && CHECK_CONTEXT(INIT_CONFIG, context))
460                 {
461                         char *str;
462
463                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
464                         {
465                                 PARSE_ERROR();
466                                 fclose(fd);
467                                 return(-1);
468                         }
469                         str = extract_string(yytext, token);
470                         if (str == NULL)
471                         {
472                                 fclose(fd);
473                                 return(-1);
474                         }
475                         pool_config->pid_file_name = str;
476                 }
477         else if (!strcmp(key, "log_connections") &&
478                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
479                 {
480                         int v = eval_logical(yytext);
481
482                         if (v < 0)
483                         {
484                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
485                                 fclose(fd);
486                                 return(-1);
487                         }
488                         pool_config->log_connections = v;
489                 }
490         else if (!strcmp(key, "log_hostname") &&
491                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
492                 {
493                         int v = eval_logical(yytext);
494
495                         if (v < 0)
496                         {
497                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
498                                 fclose(fd);
499                                 return(-1);
500                         }
501                         pool_config->log_hostname = v;
502                 }
503         else if (!strcmp(key, "enable_pool_hba") &&
504                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
505                 {
506                         int v = eval_logical(yytext);
507
508                         if (v < 0)
509                         {
510                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
511                                 fclose(fd);
512                                 return(-1);
513                         }
514                         pool_config->enable_pool_hba = v;
515                 }
516                 else if (!strcmp(key, "backend_socket_dir") && CHECK_CONTEXT(INIT_CONFIG, context))
517                 {
518                         char *str;
519
520                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
521                         {
522                                 PARSE_ERROR();
523                                 fclose(fd);
524                                 return(-1);
525                         }
526                         str = extract_string(yytext, token);
527                         if (str == NULL)
528                         {
529                                 fclose(fd);
530                                 return(-1);
531                         }
532                         pool_config->backend_socket_dir = str;
533                 }
534                 else if (!strcmp(key, "replication_mode") && CHECK_CONTEXT(INIT_CONFIG, context))
535                 {
536                         int v = eval_logical(yytext);
537
538                         if (v < 0)
539                         {
540                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
541                                 fclose(fd);
542                                 return(-1);
543                         }
544                         pool_config->replication_mode = pool_config->replication_enabled = v;
545
546                         if (pool_config->master_slave_enabled && pool_config->replication_enabled)
547                         {
548                                 pool_error("pool_config: replication_mode and master_slave_mode cannot be enabled at the same time");
549                                 fclose(fd);
550                                 return(-1);
551                         }
552
553                 }
554                 else if (!strcmp(key, "load_balance_mode") && CHECK_CONTEXT(INIT_CONFIG, context))
555                 {
556                         int v = eval_logical(yytext);
557
558                         if (v < 0)
559                         {
560                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
561                                 fclose(fd);
562                                 return(-1);
563                         }
564                         pool_config->load_balance_mode = v;
565                 }
566                 else if (!strcmp(key, "replication_stop_on_mismatch") &&
567                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
568                 {
569                         int v = eval_logical(yytext);
570
571                         if (v < 0)
572                         {
573                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
574                                 fclose(fd);
575                                 return(-1);
576                         }
577                         pool_debug("replication_stop_on_mismatch: %d", v);
578                         pool_config->replication_stop_on_mismatch = v;
579                 }
580                 else if (!strcmp(key, "replicate_select") &&
581                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
582                 {
583                         int v = eval_logical(yytext);
584
585                         if (v < 0)
586                         {
587                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
588                                 fclose(fd);
589                                 return(-1);
590                         }
591                         pool_debug("replicate_select: %d", v);
592                         pool_config->replicate_select = v;
593                 }
594                 else if (!strcmp(key, "reset_query_list") &&
595                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
596                 {
597                         char *str;
598
599                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
600                         {
601                                 PARSE_ERROR();
602                                 fclose(fd);
603                                 return(-1);
604                         }
605                         str = extract_string(yytext, token);
606                         if (str == NULL)
607                         {
608                                 fclose(fd);
609                                 return(-1);
610                         }
611                         pool_config->reset_query_list = extract_string_tokens(str, ";", &pool_config->num_reset_queries);
612                         if (pool_config->reset_query_list == NULL)
613                         {
614                                 fclose(fd);
615                                 return(-1);
616                         }
617                 }
618
619                 else if (!strcmp(key, "print_timestamp") && CHECK_CONTEXT(INIT_CONFIG, context))
620                 {
621                         int v = eval_logical(yytext);
622
623                         if (v < 0)
624                         {
625                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
626                                 fclose(fd);
627                                 return(-1);
628                         }
629                         pool_config->print_timestamp = v;
630                 }
631
632                 else if (!strcmp(key, "master_slave_mode") && CHECK_CONTEXT(INIT_CONFIG, context))
633                 {
634                         int v = eval_logical(yytext);
635
636                         if (v < 0)
637                         {
638                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
639                                 fclose(fd);
640                                 return(-1);
641                         }
642                         pool_config->master_slave_mode = pool_config->master_slave_enabled = v;
643
644                         if (pool_config->master_slave_enabled && pool_config->replication_enabled)
645                         {
646                                 pool_error("pool_config: replication_mode and master_slave_mode cannot be enabled at the same time");
647                                 fclose(fd);
648                                 return(-1);
649                         }
650                 }
651
652                 else if (!strcmp(key, "connection_cache") && CHECK_CONTEXT(INIT_CONFIG, context))
653                 {
654                         int v = eval_logical(yytext);
655
656                         if (v < 0)
657                         {
658                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
659                                 fclose(fd);
660                                 return(-1);
661                         }
662                         pool_config->connection_cache = v;
663                 }
664
665                 else if (!strcmp(key, "health_check_timeout") &&
666                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
667                 {
668                         int v = atoi(yytext);
669
670                         if (token != POOL_INTEGER || v < 0)
671                         {
672                                 pool_error("pool_config: %s must be equal or higher than 0 numeric value", key);
673                                 fclose(fd);
674                                 return(-1);
675                         }
676                         pool_config->health_check_timeout = v;
677                 }
678
679                 else if (!strcmp(key, "health_check_period") &&
680                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
681                 {
682                         int v = atoi(yytext);
683
684                         if (token != POOL_INTEGER || v < 0)
685                         {
686                                 pool_error("pool_config: %s must be equal or higher than 0 numeric value", key);
687                                 fclose(fd);
688                                 return(-1);
689                         }
690                         pool_config->health_check_period = v;
691                 }
692
693                 else if (!strcmp(key, "health_check_user") &&
694                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
695                 {
696                         char *str;
697
698                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
699                         {
700                                 PARSE_ERROR();
701                                 fclose(fd);
702                                 return(-1);
703                         }
704                         str = extract_string(yytext, token);
705                         if (str == NULL)
706                         {
707                                 fclose(fd);
708                                 return(-1);
709                         }
710                         pool_config->health_check_user = str;
711                 }
712
713                 else if (!strcmp(key, "failover_command") &&
714                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
715                 {
716                         char *str;
717
718                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
719                         {
720                                 PARSE_ERROR();
721                                 fclose(fd);
722                                 return(-1);
723                         }
724                         str = extract_string(yytext, token);
725                         if (str == NULL)
726                         {
727                                 fclose(fd);
728                                 return(-1);
729                         }
730                         pool_config->failover_command = str;
731                 }
732
733                 else if (!strcmp(key, "failback_command") &&
734                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
735                 {
736                         char *str;
737
738                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
739                         {
740                                 PARSE_ERROR();
741                                 fclose(fd);
742                                 return(-1);
743                         }
744                         str = extract_string(yytext, token);
745                         if (str == NULL)
746                         {
747                                 fclose(fd);
748                                 return(-1);
749                         }
750                         pool_config->failback_command = str;
751                 }
752
753                 else if (!strcmp(key, "recovery_user") &&
754                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
755                 {
756                         char *str;
757
758                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
759                         {
760                                 PARSE_ERROR();
761                                 fclose(fd);
762                                 return(-1);
763                         }
764                         str = extract_string(yytext, token);
765                         if (str == NULL)
766                         {
767                                 fclose(fd);
768                                 return(-1);
769                         }
770                         pool_config->recovery_user = str;
771                 }
772
773                 else if (!strcmp(key, "recovery_password") &&
774                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
775                 {
776                         char *str;
777
778                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
779                         {
780                                 PARSE_ERROR();
781                                 fclose(fd);
782                                 return(-1);
783                         }
784                         str = extract_string(yytext, token);
785                         if (str == NULL)
786                         {
787                                 fclose(fd);
788                                 return(-1);
789                         }
790                         pool_config->recovery_password = str;
791                 }
792
793                 else if (!strcmp(key, "recovery_1st_stage_command") &&
794                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
795                 {
796                         char *str;
797
798                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
799                         {
800                                 PARSE_ERROR();
801                                 fclose(fd);
802                                 return(-1);
803                         }
804                         str = extract_string(yytext, token);
805                         if (str == NULL)
806                         {
807                                 fclose(fd);
808                                 return(-1);
809                         }
810                         pool_config->recovery_1st_stage_command = str;
811                 }
812
813                 else if (!strcmp(key, "recovery_2nd_stage_command") &&
814                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
815                 {
816                         char *str;
817
818                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
819                         {
820                                 PARSE_ERROR();
821                                 fclose(fd);
822                                 return(-1);
823                         }
824                         str = extract_string(yytext, token);
825                         if (str == NULL)
826                         {
827                                 fclose(fd);
828                                 return(-1);
829                         }
830                         pool_config->recovery_2nd_stage_command = str;
831                 }
832
833                 else if (!strcmp(key, "recovery_timeout") &&
834                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
835                 {
836                         int v = atoi(yytext);
837
838                         if (token != POOL_INTEGER || v < 0)
839                         {
840                                 pool_error("pool_config: %s must be equal or higher than 0 numeric value", key);
841                                 fclose(fd);
842                                 return(-1);
843                         }
844                         pool_config->recovery_timeout = v;
845                 }
846
847                 else if (!strcmp(key, "client_idle_limit_in_recovery") &&
848                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
849                 {
850                         int v = atoi(yytext);
851
852                         if (token != POOL_INTEGER || v < 0)
853                         {
854                                 pool_error("pool_config: %s must be greater or equal to 0 numeric value", key);
855                                 fclose(fd);
856                                 return(-1);
857                         }
858                         pool_config->client_idle_limit_in_recovery = v;
859                 }
860
861                 else if (!strcmp(key, "insert_lock") &&
862                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
863                 {
864                         int v = eval_logical(yytext);
865
866                         if (v < 0)
867                         {
868                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
869                                 fclose(fd);
870                                 return(-1);
871                         }
872                         pool_config->insert_lock = v;
873                 }
874
875                 else if (!strcmp(key, "ignore_leading_white_space") &&
876                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
877                 {
878                         int v = eval_logical(yytext);
879
880                         if (v < 0)
881                         {
882                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
883                                 fclose(fd);
884                                 return(-1);
885                         }
886                         pool_config->ignore_leading_white_space = v;
887                 }
888
889                 else if (!strcmp(key, "parallel_mode") && CHECK_CONTEXT(INIT_CONFIG, context))
890                 {
891                         int v = eval_logical(yytext);
892
893                         if (v < 0)
894                         {
895                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
896                                 fclose(fd);
897                                 return(-1);
898                         }
899                         pool_config->parallel_mode = v;
900                 }
901
902                 else if (!strcmp(key, "enable_query_cache") && CHECK_CONTEXT(INIT_CONFIG, context))
903                 {
904                         int v = eval_logical(yytext);
905
906                         if (v < 0)
907                         {
908                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
909                                 fclose(fd);
910                                 return(-1);
911                         }
912                         pool_config->enable_query_cache = v;
913                 }
914
915                 else if (!strcmp(key, "pgpool2_hostname") && CHECK_CONTEXT(INIT_CONFIG, context))
916                 {
917                         char *str;
918
919                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
920                         {
921                                 PARSE_ERROR();
922                                 fclose(fd);
923                                 return(-1);
924                         }
925                         str = extract_string(yytext, token);
926                         if (str == NULL)
927                         {
928                                 fclose(fd);
929                                 return(-1);
930                         }
931                         if(strlen(str))
932                                 pool_config->pgpool2_hostname = str;
933                 }
934
935                 else if (!strcmp(key, "system_db_hostname") && CHECK_CONTEXT(INIT_CONFIG, context))
936                 {
937                         char *str;
938
939                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
940                         {
941                                 PARSE_ERROR();
942                                 fclose(fd);
943                                 return(-1);
944                         }
945                         str = extract_string(yytext, token);
946                         if (str == NULL)
947                         {
948                                 fclose(fd);
949                                 return(-1);
950                         }
951                         pool_config->system_db_hostname = str;
952                 }
953
954                 else if (!strcmp(key, "system_db_port") && CHECK_CONTEXT(INIT_CONFIG, context))
955                 {
956                         int v = atoi(yytext);
957
958                         if (token != POOL_INTEGER || v < 0)
959                         {
960                                 pool_error("pool_config: %s must be equal or higher than 0 numeric value", key);
961                                 fclose(fd);
962                                 return(-1);
963                         }
964                         pool_config->system_db_port = v;
965                 }
966
967                 else if (!strcmp(key, "system_db_dbname") && CHECK_CONTEXT(INIT_CONFIG, context))
968                 {
969                         char *str;
970
971                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
972                         {
973                                 PARSE_ERROR();
974                                 fclose(fd);
975                                 return(-1);
976                         }
977                         str = extract_string(yytext, token);
978                         if (str == NULL)
979                         {
980                                 fclose(fd);
981                                 return(-1);
982                         }
983                         pool_config->system_db_dbname = str;
984                 }
985
986                 else if (!strcmp(key, "system_db_schema") && CHECK_CONTEXT(INIT_CONFIG, context))
987                 {
988                         char *str;
989
990                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
991                         {
992                                 PARSE_ERROR();
993                                 fclose(fd);
994                                 return(-1);
995                         }
996                         str = extract_string(yytext, token);
997                         if (str == NULL)
998                         {
999                                 fclose(fd);
1000                                 return(-1);
1001                         }
1002                         pool_config->system_db_schema = str;
1003                 }
1004
1005                 else if (!strcmp(key, "system_db_user") && CHECK_CONTEXT(INIT_CONFIG, context))
1006                 {
1007                         char *str;
1008
1009                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
1010                         {
1011                                 PARSE_ERROR();
1012                                 fclose(fd);
1013                                 return(-1);
1014                         }
1015                         str = extract_string(yytext, token);
1016                         if (str == NULL)
1017                         {
1018                                 fclose(fd);
1019                                 return(-1);
1020                         }
1021                         pool_config->system_db_user = str;
1022                 }
1023
1024                 else if (!strcmp(key, "system_db_password") && CHECK_CONTEXT(INIT_CONFIG, context))
1025                 {
1026                         char *str;
1027
1028                         if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
1029                         {
1030                                 PARSE_ERROR();
1031                                 fclose(fd);
1032                                 return(-1);
1033                         }
1034                         str = extract_string(yytext, token);
1035                         if (str == NULL)
1036                         {
1037                                 fclose(fd);
1038                                 return(-1);
1039                         }
1040                         pool_config->system_db_password = str;
1041                 }
1042
1043                 else if (!strncmp(key, "backend_hostname", 16) &&
1044                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
1045                                  mypid == getpid()) /* this parameter must be modified by parent pid */
1046                 {
1047                         int slot;
1048                         char *str;
1049
1050                         slot = atoi(key + 16);
1051                         if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
1052                         {
1053                                 pool_error("pool_config: backend number %s for backend_hostname out of range", key);
1054                                 fclose(fd);
1055                                 return(-1);
1056                         }
1057
1058                         str = extract_string(yytext, token);
1059                         if (str == NULL)
1060                         {
1061                                 fclose(fd);
1062                                 return(-1);
1063                         }
1064                         if (context == INIT_CONFIG ||
1065                                 (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED))
1066                                 strncpy(BACKEND_INFO(slot).backend_hostname, str, MAX_DB_HOST_NAMELEN);
1067                 }
1068
1069                 else if (!strncmp(key, "backend_port", 12) &&
1070                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
1071                                  mypid == getpid()) /* this parameter must be modified by parent pid */
1072                 {
1073                         int slot;
1074
1075                         slot = atoi(key + 12);
1076                         if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
1077                         {
1078                                 pool_error("pool_config: host number %s for port number out of range", key);
1079                                 fclose(fd);
1080                                 return(-1);
1081                         }
1082                         pool_debug("pool_config: port slot number %d ", slot);
1083                         if (context == INIT_CONFIG)
1084                         {
1085                                 BACKEND_INFO(slot).backend_port = atoi(yytext);
1086                                 BACKEND_INFO(slot).backend_status = CON_CONNECT_WAIT;
1087                         }
1088                         else if (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED)
1089                         {
1090                                 BACKEND_INFO(slot).backend_port = atoi(yytext);
1091                                 BACKEND_INFO(slot).backend_status = CON_DOWN;
1092                         }
1093                 }
1094
1095                 else if (!strncmp(key, "backend_weight", 14) &&
1096                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
1097                                  mypid == getpid()) /* this parameter must be modified by parent pid */
1098                 {
1099                         int slot;
1100                         double v;
1101                         BACKEND_STATUS status;
1102
1103                         slot = atoi(key + 14);
1104                         if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
1105                         {
1106                                 pool_error("pool_config: weight number %s for port number out of range", key);
1107                                 fclose(fd);
1108                                 return(-1);
1109                         }
1110
1111                         v = atof(yytext);
1112
1113                         if (v < 0.0)
1114                         {
1115                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
1116                                 fclose(fd);
1117                                 return(-1);
1118                         }
1119
1120                         pool_debug("pool_config: weight slot number %d weight: %f", slot, v);
1121                         status = BACKEND_INFO(slot).backend_status;
1122                         if (context == INIT_CONFIG ||
1123                                 (context == RELOAD_CONFIG && (context == RELOAD_CONFIG && (status == CON_UNUSED || status == CON_DOWN))))
1124                         {
1125                                 pool_config->backend_desc->backend_info[slot].unnormalized_weight = v;
1126                         }
1127                 }
1128                 else if (!strncmp(key, "backend_data_directory", 22) &&
1129                                  CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
1130                                  mypid == getpid()) /* this parameter must be modified by parent pid */
1131                 {
1132                         int slot;
1133                         char *str;
1134                         BACKEND_STATUS status;
1135
1136                         slot = atoi(key + 22);
1137                         if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
1138                         {
1139                                 pool_error("pool_config: backend number %s for backend_data_directory out of range", key);
1140                                 fclose(fd);
1141                                 return(-1);
1142                         }
1143
1144                         str = extract_string(yytext, token);
1145                         if (str == NULL)
1146                         {
1147                                 fclose(fd);
1148                                 return(-1);
1149                         }
1150                         status = BACKEND_INFO(slot).backend_status;
1151                         if (context == INIT_CONFIG ||
1152                                 (context == RELOAD_CONFIG && (status == CON_UNUSED || status == CON_DOWN)))
1153                                 strncpy(BACKEND_INFO(slot).backend_data_directory, str, MAX_PATH_LENGTH);
1154                 }
1155         else if (!strcmp(key, "log_statement") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
1156                 {
1157                         int v = eval_logical(yytext);
1158
1159                         if (v < 0)
1160                         {
1161                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
1162                                 return(-1);
1163                         }
1164                         pool_config->log_statement = v;
1165                 }
1166         else if (!strcmp(key, "log_statement") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
1167                 {
1168                         int v = eval_logical(yytext);
1169
1170                         if (v < 0)
1171                         {
1172                                 pool_error("pool_config: invalid value %s for %s", yytext, key);
1173                                 return(-1);
1174                         }
1175                         pool_config->log_statement = v;
1176                 }
1177         }
1178
1179         fclose(fd);
1180
1181         pool_config->backend_desc->num_backends = 0;
1182         total_weight = 0.0;
1183
1184         for (i=0;i<MAX_CONNECTION_SLOTS;i++)
1185         {
1186                 /* port number == 0 indicates that this server is out of use */
1187                 if (BACKEND_INFO(i).backend_port == 0)
1188                 {
1189                         clear_host_entry(i);
1190                 }
1191
1192                 else
1193                 {
1194                         total_weight += BACKEND_INFO(i).unnormalized_weight;
1195                         pool_config->backend_desc->num_backends = i+1;
1196                 }
1197         }
1198
1199         pool_debug("num_backends: %d num_backends: %d total_weight: %f",
1200                            pool_config->backend_desc->num_backends, pool_config->backend_desc->num_backends, total_weight);
1201         /*
1202          * Normalize load balacing weights. What we are doing here is,
1203          * assign 0 to RAND_MAX to each backend's weight according to the
1204          * value weightN.  For example, if two backends are assigned 1.0,
1205          * then each backend will get RAND_MAX/2 normalized weight.
1206          */
1207         for (i=0;i<MAX_CONNECTION_SLOTS;i++)
1208         {
1209 #ifdef DEBUG
1210                 print_host_entry(i);
1211 #endif
1212
1213                 if (pool_config->backend_desc->backend_info[i].backend_port != 0)
1214                 {
1215                         pool_config->backend_desc->backend_info[i].backend_weight =
1216                                 (RAND_MAX) * pool_config->backend_desc->backend_info[i].unnormalized_weight / total_weight;
1217                         pool_debug("backend %d weight: %f", i, pool_config->backend_desc->backend_info[i].backend_weight);
1218                 }
1219         }
1220
1221         if (pool_config->parallel_mode || pool_config->enable_query_cache)
1222         {
1223                 int dist_num;
1224                 SystemDBInfo *info;
1225                 
1226                 system_db_info = malloc(sizeof(POOL_SYSTEMDB_CONNECTION_POOL));
1227                 if (system_db_info == NULL)
1228                 {
1229                         pool_error("failed to allocate sytem_db_info");
1230                         return -1;
1231                 }
1232                 memset(system_db_info, 0, sizeof(*system_db_info));
1233
1234                 system_db_info->system_db_status = pool_shared_memory_create(sizeof(BACKEND_STATUS));
1235                 if (system_db_info->system_db_status == NULL)
1236                 {
1237                         pool_error("failed to allocate system_db_info->system_db_status");
1238                         return -1;
1239                 }
1240                 *system_db_info->system_db_status = CON_CONNECT_WAIT;   /* which is the same as SYSDB_STATUS = CON_CONNECT_WAIT */
1241
1242                 info = malloc(sizeof(SystemDBInfo));
1243                 if (info == NULL)
1244                 {
1245                         pool_error("failed to allocate info");
1246                         return -1;
1247                 }
1248
1249                 system_db_info->info = info;
1250                 info->hostname = pool_config->system_db_hostname;
1251                 info->port = pool_config->system_db_port;
1252                 info->user = pool_config->system_db_user;
1253                 info->password = pool_config->system_db_password;
1254                 info->database_name = pool_config->system_db_dbname;
1255                 info->schema_name = pool_config->system_db_schema;
1256                 info->dist_def_num = 0;
1257                 info->dist_def_slot = NULL;
1258
1259                 if (pool_config->parallel_mode)
1260                 {
1261                         dist_num = pool_memset_system_db_info(info);
1262                         if(dist_num < 0)
1263                         {
1264                                 pool_error("failed to get systemdb info");
1265                                 return(-1);
1266                         }
1267                 }
1268                 if (pool_config->enable_query_cache)
1269                 {
1270                         info->query_cache_table_info.register_prepared_statement = NULL;
1271                         if (! pool_query_cache_table_exists())
1272                         {
1273                                 pool_error("failed to locate query_cache table. perhaps it's not defined?");
1274                                 return -1;
1275                         }
1276                 }
1277                 SYSDB_STATUS = CON_UP;
1278         }
1279
1280         return 0;
1281 }
1282
1283 static char *extract_string(char *value, POOL_TOKEN token)
1284 {
1285         char *ret;
1286
1287         ret = strdup(value);
1288         if (!ret)
1289         {
1290                 pool_error("extract_string: out of memory");
1291                 return NULL;
1292         }
1293
1294         if (token == POOL_STRING)
1295         {
1296                 ret[strlen(ret)-1] = '\0';
1297                 return (ret+1);
1298         }
1299         return ret;
1300 }
1301
1302 static int eval_logical(char *str)
1303 {
1304         int ret;
1305
1306         if (!strcasecmp(str, "true"))
1307                 ret = 1;
1308         else if (!strcasecmp(str, "false"))
1309                 ret = 0;
1310         else if (!strcmp(str, "1"))
1311                 ret = 1;
1312         else if (!strcmp(str, "0"))
1313                 ret = 0;
1314         else
1315                 ret = -1;
1316
1317         return ret;
1318 }
1319
1320 /*
1321  * extract tokens separated by delimi from str. return value is an
1322  * array of pointers to malloced strings. number of tokens is set to
1323  * n; note that str will be destroyed by strtok(). Also return value
1324  * points to static data, that means subsequent call will change the
1325  * return value.
1326  */
1327 #define MAXTOKENS 1024
1328 static char **extract_string_tokens(char *str, char *delimi, int *n)
1329 {
1330         char *token;
1331         static char *tokens[MAXTOKENS];
1332
1333         *n = 0;
1334
1335         for (token = strtok(str, delimi); token != NULL && *n < MAXTOKENS; token = strtok(NULL, delimi))
1336         {
1337                 tokens[*n] = strdup(token);
1338                 if (tokens[*n] == NULL)
1339                 {
1340                         pool_error("extract_string_tokens: out of memory");
1341                         return NULL;
1342                 }
1343                 pool_debug("extract_string_tokens: token: %s", tokens[*n]);
1344                 (*n)++;
1345         }
1346         return tokens;
1347 }
1348
1349 static void clear_host_entry(int slot)
1350 {
1351         *pool_config->backend_desc->backend_info[slot].backend_hostname = '\0';
1352         pool_config->backend_desc->backend_info[slot].backend_port = 0;
1353         pool_config->backend_desc->backend_info[slot].backend_status = CON_UNUSED;
1354         pool_config->backend_desc->backend_info[slot].backend_weight = 0.0;
1355 }
1356
1357 #ifdef DEBUG
1358 static void print_host_entry(int slot)
1359 {
1360         pool_debug("slot: %d host: %s port: %d status: %d weight: %f",
1361                            slot,
1362                            pool_config->server_hostnames[slot],
1363                            pool_config->server_ports[slot],
1364                            pool_config->server_status[slot],
1365                            pool_config->server_weights[slot]);
1366 }
1367 #endif
1368