1 /* -*-pgsql-c-*- */
2 /*
3 * $Header$
4 *
5 * pgpool: a language independent connection pool server for PostgreSQL
6 * written by Tatsuo Ishii
7 *
8 * Copyright (c) 2003-2018 PgPool Global Development Group
9 *
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that copyright notice and this permission
14 * notice appear in supporting documentation, and that the name of the
15 * author not be used in advertising or publicity pertaining to
16 * distribution of the software without specific, written prior
17 * permission. The author makes no representations about the
18 * suitability of this software for any purpose. It is provided "as
19 * is" without express or implied warranty.
20 */
21 #include "pool.h"
22 #include "pool_config.h"
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28
29 #ifdef HAVE_GETOPT_H
30 #include <getopt.h>
31 #else
32 #include "utils/getopt_long.h"
33 #endif
34
35 #include <errno.h>
36 #include <string.h>
37 #include <libgen.h>
38 #include "utils/elog.h"
39 #include "utils/palloc.h"
40 #include "utils/memutils.h"
41 #include "utils/pool_path.h"
42
43 #include "version.h"
44 #include "auth/pool_passwd.h"
45 #include "auth/pool_hba.h"
46 #include "query_cache/pool_memqcache.h"
47 #include "watchdog/wd_utils.h"
48 #include "pool_config_variables.h"
49
50 static void daemonize(void);
51 static char *get_pid_file_path(void);
52 static int read_pid_file(void);
53 static void write_pid_file(void);
54 static void usage(void);
55 static void show_version(void);
56 static void stop_me(void);
57 static void FileUnlink(int code, Datum path);
58
59 char *pcp_conf_file = NULL; /* absolute path of the pcp.conf */
60 char *conf_file = NULL; /* absolute path of the pgpool.conf */
61 char *hba_file = NULL; /* absolute path of the hba.conf */
62 char *base_dir = NULL; /* The working dir from where pgpool was invoked from */
63
64 static int not_detach = 0; /* non 0 if non detach option (-n) is given */
65 int stop_sig = SIGTERM; /* stopping signal default value */
66 int myargc;
67 char **myargv;
68 int assert_enabled = 0;
69
main(int argc,char ** argv)70 int main(int argc, char **argv)
71 {
72 int opt;
73 int debug_level = 0;
74 int optindex;
75 bool discard_status = false;
76 bool clear_memcache_oidmaps = false;
77
78 char pcp_conf_file_path[POOLMAXPATHLEN+1];
79 char conf_file_path[POOLMAXPATHLEN+1];
80 char hba_file_path[POOLMAXPATHLEN+1];
81
82 static struct option long_options[] = {
83 {"hba-file", required_argument, NULL, 'a'},
84 {"debug", no_argument, NULL, 'd'},
85 {"config-file", required_argument, NULL, 'f'},
86 {"pcp-file", required_argument, NULL, 'F'},
87 {"help", no_argument, NULL, 'h'},
88 {"mode", required_argument, NULL, 'm'},
89 {"dont-detach", no_argument, NULL, 'n'},
90 {"discard-status", no_argument, NULL, 'D'},
91 {"clear-oidmaps", no_argument, NULL, 'C'},
92 {"debug-assertions", no_argument, NULL, 'x'},
93 {"version", no_argument, NULL, 'v'},
94 {NULL, 0, NULL, 0}
95 };
96
97 myargc = argc;
98 myargv = argv;
99
100 snprintf(conf_file_path, sizeof(conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
101 snprintf(pcp_conf_file_path, sizeof(pcp_conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
102 snprintf(hba_file_path, sizeof(hba_file_path), "%s/%s", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
103 while ((opt = getopt_long(argc, argv, "a:df:F:hm:nDCxv", long_options, &optindex)) != -1)
104 {
105 switch (opt)
106 {
107 case 'a': /* specify hba configuration file */
108 if (!optarg)
109 {
110 usage();
111 exit(1);
112 }
113 strlcpy(hba_file_path, optarg, sizeof(hba_file_path));
114 break;
115
116 case 'x': /* enable cassert */
117 assert_enabled = 1;
118 break;
119
120 case 'd': /* debug option */
121 debug_level = 1;
122 break;
123
124 case 'f': /* specify configuration file */
125 if (!optarg)
126 {
127 usage();
128 exit(1);
129 }
130 strlcpy(conf_file_path, optarg, sizeof(conf_file_path));
131 break;
132
133 case 'F': /* specify PCP password file */
134 if (!optarg)
135 {
136 usage();
137 exit(1);
138 }
139 strlcpy(pcp_conf_file_path, optarg, sizeof(pcp_conf_file_path));
140 break;
141
142 case 'h':
143 usage();
144 exit(0);
145 break;
146
147 case 'm': /* stop mode */
148 if (!optarg)
149 {
150 usage();
151 exit(1);
152 }
153 if (*optarg == 's' || !strcmp("smart", optarg))
154 stop_sig = SIGTERM; /* smart shutdown */
155 else if (*optarg == 'f' || !strcmp("fast", optarg))
156 stop_sig = SIGINT; /* fast shutdown */
157 else if (*optarg == 'i' || !strcmp("immediate", optarg))
158 stop_sig = SIGQUIT; /* immediate shutdown */
159 else
160 {
161 usage();
162 exit(1);
163 }
164 break;
165
166 case 'n': /* no detaching control ttys */
167 not_detach = 1;
168 break;
169
170 case 'D': /* discard pgpool_status */
171 discard_status = true;
172 break;
173
174 case 'C': /* discard caches in memcached */
175 clear_memcache_oidmaps = true;
176 break;
177
178 case 'v':
179 show_version();
180 exit(0);
181
182 default:
183 usage();
184 exit(1);
185 }
186 }
187 #ifdef USE_SSL
188 /* global ssl init */
189 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
190 OPENSSL_init_ssl(0, NULL);
191 #else
192 SSL_library_init();
193 #endif
194 SSL_load_error_strings();
195 #endif /* USE_SSL */
196
197 myargv = save_ps_display_args(myargc, myargv);
198 /* create MemoryContexts */
199 MemoryContextInit();
200
201 /* load the CWD before it is changed */
202 base_dir = get_current_working_dir();
203 /* convert all the paths to absolute paths*/
204 conf_file = make_absolute_path(conf_file_path, base_dir);
205 pcp_conf_file = make_absolute_path(pcp_conf_file_path, base_dir);
206 hba_file = make_absolute_path(hba_file_path, base_dir);
207
208 mypid = getpid();
209
210 pool_init_config();
211
212 pool_get_config(conf_file, CFGCXT_INIT);
213
214 /*
215 * Override debug level
216 * if command line -d arg is given adjust the log_min_message config variable
217 */
218 if(debug_level > 0 && pool_config->log_min_messages > DEBUG1)
219 set_one_config_option("log_min_messages", "DEBUG1",CFGCXT_INIT, PGC_S_ARGV, INFO);
220
221 /*
222 * If a non-switch argument remains, then it should be either "reload" or "stop".
223 */
224 if (optind == (argc - 1))
225 {
226 if (!strcmp(argv[optind], "reload"))
227 {
228 pid_t pid;
229
230 pid = read_pid_file();
231 if (pid < 0)
232 {
233 ereport(FATAL,
234 (return_code(1),
235 errmsg("could not read pid file")));
236 }
237
238 if (kill(pid, SIGHUP) == -1)
239 {
240 ereport(FATAL,
241 (return_code(1),
242 errmsg("could not reload configuration file pid: %d. reason: %s", pid, strerror(errno))));
243 }
244 exit(0);
245 }
246 if (!strcmp(argv[optind], "stop"))
247 {
248 stop_me();
249 exit(0);
250 }
251 else
252 {
253 usage();
254 exit(1);
255 }
256 }
257 /*
258 * else if no non-switch argument remains, then it should be a start request
259 */
260 else if (optind == argc)
261 {
262 int pid = read_pid_file();
263 if (pid > 0)
264 {
265 if (kill(pid, 0) == 0)
266 {
267 fprintf(stderr, "ERROR: pid file found. is another pgpool(%d) is running?\n", pid);
268 exit(EXIT_FAILURE);
269 }
270 else
271 fprintf(stderr, "NOTICE: pid file found but it seems bogus. Trying to start pgpool anyway...\n");
272 }
273 }
274 /*
275 * otherwise an error...
276 */
277 else
278 {
279 usage();
280 exit(1);
281 }
282
283 if (pool_config->enable_pool_hba)
284 load_hba(hba_file);
285
286 /* check effective user id for watchdog */
287 /* watchdog must be started under the privileged user */
288 wd_check_network_command_configurations();
289
290 /* set signal masks */
291 poolinitmask();
292
293 if (not_detach)
294 write_pid_file();
295 else
296 daemonize();
297 /*
298 * Locate pool_passwd
299 * The default file name "pool_passwd" can be changed by setting
300 * pgpool.conf's "pool_passwd" directive.
301 */
302 if (strcmp("", pool_config->pool_passwd))
303 {
304 char pool_passwd[POOLMAXPATHLEN+1];
305 char dirnamebuf[POOLMAXPATHLEN+1];
306 char *dirp;
307
308 strlcpy(dirnamebuf, conf_file, sizeof(dirnamebuf));
309 dirp = dirname(dirnamebuf);
310 snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s",
311 dirp, pool_config->pool_passwd);
312 pool_init_pool_passwd(pool_passwd, POOL_PASSWD_R);
313 }
314
315 pool_semaphore_create(MAX_NUM_SEMAPHORES);
316
317 PgpoolMain(discard_status, clear_memcache_oidmaps); /* this is an infinate loop */
318
319 exit(0);
320
321 }
322
show_version(void)323 static void show_version(void)
324 {
325 fprintf(stderr, "%s version %s (%s)\n", PACKAGE, VERSION, PGPOOLVERSION);
326 }
327
usage(void)328 static void usage(void)
329 {
330 fprintf(stderr, "%s version %s (%s),\n", PACKAGE, VERSION, PGPOOLVERSION);
331 fprintf(stderr, " A generic connection pool/replication/load balance server for PostgreSQL\n\n");
332 fprintf(stderr, "Usage:\n");
333 fprintf(stderr, " pgpool [ -c] [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
334 fprintf(stderr, " [ -n ] [ -D ] [ -d ]\n");
335 fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
336 fprintf(stderr, " [ -m SHUTDOWN-MODE ] stop\n");
337 fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ] reload\n\n");
338 fprintf(stderr, "Common options:\n");
339 fprintf(stderr, " -a, --hba-file=HBA_CONFIG_FILE\n");
340 fprintf(stderr, " Set the path to the pool_hba.conf configuration file\n");
341 fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
342 fprintf(stderr, " -f, --config-file=CONFIG_FILE\n");
343 fprintf(stderr, " Set the path to the pgpool.conf configuration file\n");
344 fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
345 fprintf(stderr, " -F, --pcp-file=PCP_CONFIG_FILE\n");
346 fprintf(stderr, " Set the path to the pcp.conf configuration file\n");
347 fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
348 fprintf(stderr, " -h, --help Print this help\n\n");
349 fprintf(stderr, "Start options:\n");
350 fprintf(stderr, " -C, --clear-oidmaps Clear query cache oidmaps when memqcache_method is memcached\n");
351 fprintf(stderr, " (If shmem, discards whenever pgpool starts.)\n");
352 fprintf(stderr, " -n, --dont-detach Don't run in daemon mode, does not detach control tty\n");
353 fprintf(stderr, " -x, --debug-assertions Turns on various assertion checks, This is a debugging aid\n");
354 fprintf(stderr, " -D, --discard-status Discard pgpool_status file and do not restore previous status\n");
355 fprintf(stderr, " -d, --debug Debug mode\n\n");
356 fprintf(stderr, "Stop options:\n");
357 fprintf(stderr, " -m, --mode=SHUTDOWN-MODE\n");
358 fprintf(stderr, " Can be \"smart\", \"fast\", or \"immediate\"\n\n");
359 fprintf(stderr, "Shutdown modes are:\n");
360 fprintf(stderr, " smart quit after all clients have disconnected\n");
361 fprintf(stderr, " fast quit directly, with proper shutdown\n");
362 fprintf(stderr, " immediate the same mode as fast\n");
363 }
364
365 /*
366 * detach control ttys
367 */
daemonize(void)368 static void daemonize(void)
369 {
370 int i;
371 pid_t pid;
372 int fdlimit;
373
374 pid = fork();
375 if (pid == (pid_t) -1)
376 {
377 ereport(FATAL,
378 (errmsg("could not daemonize the pgpool-II"),
379 errdetail("fork() system call failed with reason: \"%s\"", strerror(errno) )));
380 }
381 else if (pid > 0)
382 { /* parent */
383 exit(0);
384 }
385
386 #ifdef HAVE_SETSID
387 if (setsid() < 0)
388 {
389 ereport(FATAL,
390 (errmsg("could not daemonize the pgpool-II"),
391 errdetail("setsid() system call failed with reason: \"%s\"", strerror(errno) )));
392 }
393 #endif
394
395 mypid = getpid();
396 write_pid_file();
397 if(chdir("/"))
398 ereport(WARNING,
399 (errmsg("change directory failed"),
400 errdetail("chdir() system call failed with reason: \"%s\"", strerror(errno) )));
401
402 /* redirect stdin, stdout and stderr to /dev/null */
403 i = open("/dev/null", O_RDWR);
404 if(i < 0)
405 {
406 ereport(WARNING,
407 (errmsg("failed to open \"/dev/null\", open() failed with error \"%s\"", strerror(errno))));
408 }
409 else
410 {
411 dup2(i, 0);
412 dup2(i, 1);
413 dup2(i, 2);
414 close(i);
415 }
416 /* close syslog connection for daemonizing */
417 if (pool_config->log_destination & LOG_DESTINATION_SYSLOG)
418 {
419 closelog();
420 }
421
422 /* close other file descriptors */
423 fdlimit = sysconf(_SC_OPEN_MAX);
424 for (i = 3; i < fdlimit; i++)
425 close(i);
426 }
427
428 /*
429 * stop myself
430 */
stop_me(void)431 static void stop_me(void)
432 {
433 pid_t pid;
434 char *pid_file;
435
436 pid = read_pid_file();
437 if (pid < 0)
438 {
439 ereport(FATAL,
440 (errmsg("could not read pid file")));
441 }
442
443 if (kill(pid, stop_sig) == -1)
444 {
445 ereport(FATAL,
446 (errmsg("could not stop process with pid: %d", pid),
447 errdetail("\"%s\"", strerror(errno))));
448 }
449 ereport(LOG,
450 (errmsg ("stop request sent to pgpool. waiting for termination...")));
451
452 while (kill(pid, 0) == 0)
453 {
454 fprintf(stderr, ".");
455 sleep(1);
456 }
457 fprintf(stderr, "done.\n");
458 pid_file = get_pid_file_path();
459 unlink(pid_file);
460 pfree(pid_file);
461 }
462
463 /*
464 * The function returns the palloc'd copy of pid_file_path,
465 * caller must free it after use
466 */
get_pid_file_path(void)467 static char *get_pid_file_path(void)
468 {
469 char *new = NULL;
470 if (!is_absolute_path(pool_config->pid_file_name))
471 {
472 /*
473 * some implementations of dirname() may modify the
474 * string argument passed to it, so do not use the original
475 * conf_file as an argument
476 */
477 char *conf_file_copy = pstrdup(conf_file);
478 char *conf_dir = dirname(conf_file_copy);
479 size_t path_size;
480 if (conf_dir == NULL)
481 {
482 ereport(LOG,
483 (errmsg("failed to get the dirname of pid file:\"%s\". reason: %s",
484 pool_config->pid_file_name, strerror(errno))));
485 return NULL;
486 }
487 path_size = strlen(conf_dir) + strlen(pool_config->pid_file_name) + 1 + 1;
488 new = palloc(path_size);
489 snprintf(new, path_size, "%s/%s",conf_dir, pool_config->pid_file_name);
490
491 ereport(DEBUG1,
492 (errmsg("pid file location is \"%s\"",
493 new)));
494
495 pfree(conf_file_copy);
496 }
497 else
498 {
499 new = pstrdup(pool_config->pid_file_name);
500 }
501
502 return new;
503 }
504
505 /*
506 * read the pid file
507 */
read_pid_file(void)508 static int read_pid_file(void)
509 {
510 int fd;
511 int readlen;
512 char pidbuf[128];
513 char *pid_file = get_pid_file_path();
514
515 if (pid_file == NULL)
516 {
517 ereport(FATAL,
518 (errmsg("failed to read pid file"),
519 errdetail("failed to get pid file path from \"%s\"",
520 pool_config->pid_file_name)));
521 }
522 fd = open(pid_file, O_RDONLY);
523 if (fd == -1)
524 {
525 pfree(pid_file);
526 return -1;
527 }
528 if ((readlen = read(fd, pidbuf, sizeof(pidbuf))) == -1)
529 {
530 close(fd);
531 pfree(pid_file);
532 ereport(FATAL,
533 (errmsg("could not read pid file as \"%s\". reason: %s",
534 pool_config->pid_file_name, strerror(errno))));
535 }
536 else if (readlen == 0)
537 {
538 close(fd);
539 pfree(pid_file);
540 ereport(FATAL,
541 (errmsg("EOF detected while reading pid file \"%s\". reason: %s",
542 pool_config->pid_file_name, strerror(errno))));
543 }
544 pfree(pid_file);
545 close(fd);
546 return(atoi(pidbuf));
547 }
548
549 /*
550 * write the pid file
551 */
write_pid_file(void)552 static void write_pid_file(void)
553 {
554 int fd;
555 char pidbuf[128];
556 char *pid_file = get_pid_file_path();
557
558 if (pid_file == NULL)
559 {
560 ereport(FATAL,
561 (errmsg("failed to write pid file"),
562 errdetail("failed to get pid file path from \"%s\"",
563 pool_config->pid_file_name)));
564 }
565
566 fd = open(pid_file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
567 if (fd == -1)
568 {
569 ereport(FATAL,
570 (errmsg("could not open pid file as %s. reason: %s",
571 pool_config->pid_file_name, strerror(errno))));
572 }
573 snprintf(pidbuf, sizeof(pidbuf), "%d", (int)getpid());
574 if (write(fd, pidbuf, strlen(pidbuf)+1) == -1)
575 {
576 close(fd);
577 pfree(pid_file);
578 ereport(FATAL,
579 (errmsg("could not write pid file as %s. reason: %s",
580 pool_config->pid_file_name, strerror(errno))));
581 }
582 if (fsync(fd) == -1)
583 {
584 close(fd);
585 pfree(pid_file);
586 ereport(FATAL,
587 (errmsg("could not fsync pid file as %s. reason: %s",
588 pool_config->pid_file_name, strerror(errno))));
589 }
590 if (close(fd) == -1)
591 {
592 pfree(pid_file);
593 ereport(FATAL,
594 (errmsg("could not close pid file as %s. reason: %s",
595 pool_config->pid_file_name, strerror(errno))));
596 }
597 /* register the call back to delete the pid file at system exit */
598 on_proc_exit(FileUnlink, (Datum) pid_file);
599 }
600
601 /*
602 * get_config_file_name: return full path of pgpool.conf.
603 */
get_config_file_name(void)604 char *get_config_file_name(void)
605 {
606 return conf_file;
607 }
608
609 /*
610 * get_hba_file_name: return full path of pool_hba.conf.
611 */
get_hba_file_name(void)612 char *get_hba_file_name(void)
613 {
614 return hba_file;
615 }
616 /*
617 * Call back function to unlink the file
618 */
FileUnlink(int code,Datum path)619 static void FileUnlink(int code, Datum path)
620 {
621 char* filePath = (char*)path;
622 if (unlink(filePath) == 0) return;
623 /*
624 * We are already exiting the system just produce a log entry to report an error
625 */
626 ereport(LOG,
627 (errmsg("unlink failed for file at path \"%s\"", filePath),
628 errdetail("\"%s\"", strerror(errno))));
629 }
630