1 /*
2 * $Header$
3 *
4 * pgpool: a language independent connection pool server for PostgreSQL
5 * written by Tatsuo Ishii
6 *
7 * Copyright (c) 2003-2018 PgPool Global Development Group
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that copyright notice and this permission
13 * notice appear in supporting documentation, and that the name of the
14 * author not be used in advertising or publicity pertaining to
15 * distribution of the software without specific, written prior
16 * permission. The author makes no representations about the
17 * suitability of this software for any purpose. It is provided "as
18 * is" without express or implied warranty.
19 *
20 * PCP client program to execute pcp commands.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <time.h>
28
29 #include "utils/fe_ports.h"
30 #include "utils/pool_path.h"
31 #include "pcp/pcp.h"
32
33 #ifdef HAVE_GETOPT_H
34 #include <getopt.h>
35 #else
36 #include "utils/getopt_long.h"
37 #endif
38
39 const char *progname = NULL;
40 const char *get_progname(const char *argv0);
41 char *last_dir_separator(const char *filename);
42
43 static void usage(void);
44 static inline bool app_require_nodeID(void);
45 static void output_watchdog_info_result(PCPResultInfo * pcpResInfo, bool verbose);
46 static void output_procinfo_result(PCPResultInfo * pcpResInfo, bool all, bool verbose);
47 static void output_proccount_result(PCPResultInfo * pcpResInfo, bool verbose);
48 static void output_poolstatus_result(PCPResultInfo * pcpResInfo, bool verbose);
49 static void output_nodeinfo_result(PCPResultInfo * pcpResInfo, bool verbose);
50 static void output_nodecount_result(PCPResultInfo * pcpResInfo, bool verbose);
51 static char *backend_status_to_string(BackendInfo * bi);
52
53 typedef enum
54 {
55 PCP_ATTACH_NODE,
56 PCP_DETACH_NODE,
57 PCP_NODE_COUNT,
58 PCP_NODE_INFO,
59 PCP_POOL_STATUS,
60 PCP_PROC_COUNT,
61 PCP_PROC_INFO,
62 PCP_PROMOTE_NODE,
63 PCP_RECOVERY_NODE,
64 PCP_STOP_PGPOOL,
65 PCP_WATCHDOG_INFO,
66 UNKNOWN,
67 } PCP_UTILITIES;
68
69 struct AppTypes
70 {
71 const char *app_name;
72 PCP_UTILITIES app_type;
73 const char *allowed_options;
74 const char *description;
75 };
76
77 struct AppTypes AllAppTypes[] =
78 {
79 {"pcp_attach_node", PCP_ATTACH_NODE, "n:h:p:U:wWvd", "attach a node from pgpool-II"},
80 {"pcp_detach_node", PCP_DETACH_NODE, "n:h:p:U:gwWvd", "detach a node from pgpool-II"},
81 {"pcp_node_count", PCP_NODE_COUNT, "h:p:U:wWvd", "display the total number of nodes under pgpool-II's control"},
82 {"pcp_node_info", PCP_NODE_INFO, "n:h:p:U:wWvd", "display a pgpool-II node's information"},
83 {"pcp_pool_status", PCP_POOL_STATUS, "h:p:U:wWvd", "display pgpool configuration and status"},
84 {"pcp_proc_count", PCP_PROC_COUNT, "h:p:U:wWvd", "display the list of pgpool-II child process PIDs"},
85 {"pcp_proc_info", PCP_PROC_INFO, "h:p:P:U:awWvd", "display a pgpool-II child process' information"},
86 {"pcp_promote_node", PCP_PROMOTE_NODE, "n:h:p:U:gwWvd", "promote a node as new master from pgpool-II"},
87 {"pcp_recovery_node", PCP_RECOVERY_NODE, "n:h:p:U:wWvd", "recover a node"},
88 {"pcp_stop_pgpool", PCP_STOP_PGPOOL, "m:h:p:U:wWvd", "terminate pgpool-II"},
89 {"pcp_watchdog_info", PCP_WATCHDOG_INFO, "n:h:p:U:wWvd", "display a pgpool-II watchdog's information"},
90 {NULL, UNKNOWN, NULL, NULL},
91 };
92 struct AppTypes *current_app_type;
93
94 int
main(int argc,char ** argv)95 main(int argc, char **argv)
96 {
97 char *host = NULL;
98 int port = 9898;
99 char *user = NULL;
100 char *pass = NULL;
101 int nodeID = -1;
102 int processID = 0;
103 int ch;
104 char shutdown_mode = 's';
105 int optindex;
106 int i;
107 bool all = false;
108 bool debug = false;
109 bool need_password = true;
110 bool gracefully = false;
111 bool verbose = false;
112 PCPConnInfo *pcpConn;
113 PCPResultInfo *pcpResInfo;
114
115 /* here we put all the allowed long options for all utilities */
116 static struct option long_options[] = {
117 {"help", no_argument, NULL, '?'},
118 {"debug", no_argument, NULL, 'd'},
119 {"version", no_argument, NULL, 'V'},
120 {"host", required_argument, NULL, 'h'},
121 {"port", required_argument, NULL, 'p'},
122 {"process-id", required_argument, NULL, 'P'},
123 {"username", required_argument, NULL, 'U'},
124 {"no-password", no_argument, NULL, 'w'},
125 {"password", no_argument, NULL, 'W'},
126 {"mode", required_argument, NULL, 'm'},
127 {"gracefully", no_argument, NULL, 'g'},
128 {"verbose", no_argument, NULL, 'v'},
129 {"all", no_argument, NULL, 'a'},
130 {"node-id", required_argument, NULL, 'n'},
131 {"watchdog-id", required_argument, NULL, 'n'},
132 {NULL, 0, NULL, 0}
133 };
134
135 /* Identify the utility app */
136 progname = get_progname(argv[0]);
137 for (i = 0;; i++)
138 {
139 current_app_type = &AllAppTypes[i];
140 if (current_app_type->app_type == UNKNOWN)
141 break;
142 if (strcmp(current_app_type->app_name, progname) == 0)
143 break;
144 }
145
146 if (current_app_type->app_type == UNKNOWN)
147 {
148 fprintf(stderr, "%s is a invalid PCP utility\n", progname);
149 exit(1);
150 }
151
152 if (argc > 1)
153 {
154 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
155 {
156 usage();
157 exit(0);
158 }
159 else if (strcmp(argv[1], "-V") == 0
160 || strcmp(argv[1], "--version") == 0)
161 {
162 fprintf(stderr, "%s (%s) %s\n", progname, PACKAGE, VERSION);
163 exit(0);
164 }
165 }
166
167 while ((ch = getopt_long(argc, argv, current_app_type->allowed_options, long_options, &optindex)) != -1)
168 {
169 switch (ch)
170 {
171 case 'd':
172 debug = true;
173 break;
174
175 case 'a':
176 all = true;
177 break;
178
179 case 'w':
180 need_password = false;
181 break;
182
183 case 'W':
184 need_password = true;
185 break;
186
187 case 'g':
188 gracefully = true;
189 break;
190
191 case 'm':
192 if (current_app_type->app_type == PCP_STOP_PGPOOL)
193 {
194 if (strcmp(optarg, "s") == 0 || strcmp(optarg, "smart") == 0)
195 shutdown_mode = 's';
196 else if (strcmp(optarg, "f") == 0 || strcmp(optarg, "fast") == 0)
197 shutdown_mode = 'f';
198 else if (strcmp(optarg, "i") == 0 || strcmp(optarg, "immediate") == 0)
199 shutdown_mode = 'i';
200 else
201 {
202 fprintf(stderr, "%s: Invalid shutdown mode \"%s\", must be either \"smart\" \"immediate\" or \"fast\" \n", progname, optarg);
203 exit(1);
204 }
205 }
206 else
207 {
208 fprintf(stderr, "Invalid argument \"%s\", Try \"%s --help\" for more information.\n", optarg, progname);
209 exit(1);
210 }
211 break;
212
213 case 'v':
214 verbose = true;
215 break;
216
217 case 'n':
218 nodeID = atoi(optarg);
219 if (current_app_type->app_type == PCP_WATCHDOG_INFO)
220 {
221 if (nodeID < 0)
222 {
223 fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for a local watchdog node\n", progname, optarg);
224 exit(0);
225 }
226 }
227 else
228 {
229 if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
230 {
231 fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n", progname, optarg, MAX_NUM_BACKENDS);
232 exit(0);
233 }
234 }
235 break;
236
237 case 'p':
238 port = atoi(optarg);
239 if (port <= 1024 || port > 65535)
240 {
241 fprintf(stderr, "%s: Invalid port number \"%s\", must be between 1024 and 65535\n", progname, optarg);
242 exit(0);
243 }
244 break;
245
246 case 'P': /* PID */
247 processID = atoi(optarg);
248 if (processID <= 0)
249 {
250 fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n", progname, optarg);
251 exit(0);
252 }
253 break;
254
255 case 'h':
256 host = strdup(optarg);
257 break;
258
259 case 'U':
260 user = strdup(optarg);
261 break;
262
263 case '?':
264 default:
265
266 /*
267 * getopt_long whould already have emitted a complaint
268 */
269 fprintf(stderr, "Try \"%s --help\" for more information.\n\n", progname);
270 exit(1);
271 }
272 }
273
274 /*
275 * if we still have arguments, use it
276 */
277 while (argc - optind >= 1)
278 {
279 if (current_app_type->app_type == PCP_PROC_INFO && processID <= 0)
280 {
281 processID = atoi(argv[optind]);
282 if (processID <= 0)
283 {
284 fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n", progname, optarg);
285 exit(0);
286 }
287 }
288 else if (current_app_type->app_type == PCP_WATCHDOG_INFO && nodeID < 0)
289 {
290 nodeID = atoi(argv[optind]);
291 if (nodeID < 0)
292 {
293 fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for local watchdog node\n", progname, optarg);
294 exit(0);
295 }
296 }
297 else if (app_require_nodeID() && nodeID < 0)
298 {
299 nodeID = atoi(argv[optind]);
300 if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
301 {
302 fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n", progname, optarg, MAX_NUM_BACKENDS);
303 exit(0);
304 }
305 }
306 else
307 fprintf(stderr, "%s: Warning: extra command-line argument \"%s\" ignored\n",
308 progname, argv[optind]);
309
310 optind++;
311 }
312
313 if (nodeID < 0)
314 {
315 if (app_require_nodeID())
316 {
317 fprintf(stderr, "%s: missing node-id\n", progname);
318 fprintf(stderr, "Try \"%s --help\" for more information.\n\n", progname);
319 exit(1);
320 }
321 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
322 {
323 nodeID = -1;
324 }
325 }
326
327 /* Get a new password if appropriate */
328 if (need_password)
329 {
330 pass = simple_prompt("Password: ", 100, false);
331 need_password = false;
332 }
333
334 pcpConn = pcp_connect(host, port, user, pass, debug ? stdout : NULL);
335 if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
336 {
337 fprintf(stderr, "%s\n", pcp_get_last_error(pcpConn) ? pcp_get_last_error(pcpConn) : "Unknown Error");
338 exit(1);
339 }
340
341 /*
342 * Okay the connection is successful not call the actual PCP function
343 */
344 if (current_app_type->app_type == PCP_ATTACH_NODE)
345 {
346 pcpResInfo = pcp_attach_node(pcpConn, nodeID);
347 }
348
349 else if (current_app_type->app_type == PCP_DETACH_NODE)
350 {
351 if (gracefully)
352 pcpResInfo = pcp_detach_node_gracefully(pcpConn, nodeID);
353 else
354 pcpResInfo = pcp_detach_node(pcpConn, nodeID);
355 }
356
357 else if (current_app_type->app_type == PCP_NODE_COUNT)
358 {
359 pcpResInfo = pcp_node_count(pcpConn);
360 }
361
362 else if (current_app_type->app_type == PCP_NODE_INFO)
363 {
364 pcpResInfo = pcp_node_info(pcpConn, nodeID);
365 }
366
367 else if (current_app_type->app_type == PCP_POOL_STATUS)
368 {
369 pcpResInfo = pcp_pool_status(pcpConn);
370 }
371
372 else if (current_app_type->app_type == PCP_PROC_COUNT)
373 {
374 pcpResInfo = pcp_process_count(pcpConn);
375 }
376
377 else if (current_app_type->app_type == PCP_PROC_INFO)
378 {
379 pcpResInfo = pcp_process_info(pcpConn, processID);
380 }
381
382 else if (current_app_type->app_type == PCP_PROMOTE_NODE)
383 {
384 if (gracefully)
385 pcpResInfo = pcp_promote_node_gracefully(pcpConn, nodeID);
386 else
387 pcpResInfo = pcp_promote_node(pcpConn, nodeID);
388 }
389
390 else if (current_app_type->app_type == PCP_RECOVERY_NODE)
391 {
392 pcpResInfo = pcp_recovery_node(pcpConn, nodeID);
393 }
394
395 else if (current_app_type->app_type == PCP_STOP_PGPOOL)
396 {
397 pcpResInfo = pcp_terminate_pgpool(pcpConn, shutdown_mode);
398 }
399
400 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
401 {
402 pcpResInfo = pcp_watchdog_info(pcpConn, nodeID);
403 }
404
405 else
406 {
407 /* should never happen */
408 fprintf(stderr, "%s: Invalid pcp process\n", progname);
409 goto DISCONNECT_AND_EXIT;
410 }
411
412 if (pcpResInfo == NULL || PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
413 {
414 fprintf(stderr, "%s\n", pcp_get_last_error(pcpConn) ? pcp_get_last_error(pcpConn) : "Unknown Error");
415 goto DISCONNECT_AND_EXIT;
416 }
417
418 if (pcp_result_is_empty(pcpResInfo))
419 {
420 fprintf(stdout, "%s -- Command Successful\n", progname);
421 }
422 else
423 {
424 if (current_app_type->app_type == PCP_NODE_COUNT)
425 output_nodecount_result(pcpResInfo, verbose);
426
427 if (current_app_type->app_type == PCP_NODE_INFO)
428 output_nodeinfo_result(pcpResInfo, verbose);
429
430 if (current_app_type->app_type == PCP_POOL_STATUS)
431 output_poolstatus_result(pcpResInfo, verbose);
432
433 if (current_app_type->app_type == PCP_PROC_COUNT)
434 output_proccount_result(pcpResInfo, verbose);
435
436 if (current_app_type->app_type == PCP_PROC_INFO)
437 output_procinfo_result(pcpResInfo, all, verbose);
438
439 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
440 output_watchdog_info_result(pcpResInfo, verbose);
441 }
442
443 DISCONNECT_AND_EXIT:
444
445 pcp_disconnect(pcpConn);
446 pcp_free_connection(pcpConn);
447
448 return 0;
449 }
450
451 static void
output_nodecount_result(PCPResultInfo * pcpResInfo,bool verbose)452 output_nodecount_result(PCPResultInfo * pcpResInfo, bool verbose)
453 {
454 if (verbose)
455 {
456 printf("Node Count\n");
457 printf("____________\n");
458 printf(" %d\n", pcp_get_int_data(pcpResInfo, 0));
459 }
460 else
461 printf("%d\n", pcp_get_int_data(pcpResInfo, 0));
462 }
463
464 static void
output_nodeinfo_result(PCPResultInfo * pcpResInfo,bool verbose)465 output_nodeinfo_result(PCPResultInfo * pcpResInfo, bool verbose)
466 {
467 BackendInfo *backend_info = (BackendInfo *) pcp_get_binary_data(pcpResInfo, 0);
468 char last_status_change[20];
469 struct tm tm;
470
471 localtime_r(&backend_info->status_changed_time, &tm);
472 strftime(last_status_change, sizeof(last_status_change), "%F %T", &tm);
473
474 if (verbose)
475 {
476 printf("Hostname : %s\nPort : %d\nStatus : %d\nWeight : %f\nStatus Name : %s\nRole : %s\nReplication Delay : %lu\nLast Status Change: %s\n",
477 backend_info->backend_hostname,
478 backend_info->backend_port,
479 backend_info->backend_status,
480 backend_info->backend_weight / RAND_MAX,
481 backend_status_to_string(backend_info),
482 role_to_str(backend_info->role),
483 backend_info->standby_delay,
484 last_status_change);
485 }
486 else
487 {
488 printf("%s %d %d %f %s %s %lu %s\n",
489 backend_info->backend_hostname,
490 backend_info->backend_port,
491 backend_info->backend_status,
492 backend_info->backend_weight / RAND_MAX,
493 backend_status_to_string(backend_info),
494 role_to_str(backend_info->role),
495 backend_info->standby_delay,
496 last_status_change);
497 }
498 }
499
500 static void
output_poolstatus_result(PCPResultInfo * pcpResInfo,bool verbose)501 output_poolstatus_result(PCPResultInfo * pcpResInfo, bool verbose)
502 {
503 POOL_REPORT_CONFIG *status;
504 int i;
505 int array_size = pcp_result_slot_count(pcpResInfo);
506
507 if (verbose)
508 {
509 for (i = 0; i < array_size; i++)
510 {
511 status = (POOL_REPORT_CONFIG *) pcp_get_binary_data(pcpResInfo, i);
512 printf("Name [%3d]:\t%s\n", i, status ? status->name : "NULL");
513 printf("Value: \t%s\n", status ? status->value : "NULL");
514 printf("Description:\t%s\n\n", status ? status->desc : "NULL");
515 }
516 }
517 else
518 {
519 for (i = 0; i < array_size; i++)
520 {
521 status = (POOL_REPORT_CONFIG *) pcp_get_binary_data(pcpResInfo, i);
522 if (status == NULL)
523 {
524 printf("****Data at %d slot is NULL\n", i);
525 continue;
526 }
527 printf("name : %s\nvalue: %s\ndesc : %s\n\n", status->name, status->value, status->desc);
528 }
529 }
530 }
531
532 static void
output_proccount_result(PCPResultInfo * pcpResInfo,bool verbose)533 output_proccount_result(PCPResultInfo * pcpResInfo, bool verbose)
534 {
535 int i;
536 int process_count = pcp_get_data_length(pcpResInfo, 0) / sizeof(int);
537 int *process_list = (int *) pcp_get_binary_data(pcpResInfo, 0);
538
539 if (verbose)
540 {
541 printf("No \t | \t PID\n");
542 printf("_____________________\n");
543 for (i = 0; i < process_count; i++)
544 printf("%d \t | \t %d\n", i, process_list[i]);
545 printf("\nTotal Processes:%d\n", process_count);
546 }
547 else
548 {
549 for (i = 0; i < process_count; i++)
550 printf("%d ", process_list[i]);
551 printf("\n");
552 }
553 }
554
555 static void
output_procinfo_result(PCPResultInfo * pcpResInfo,bool all,bool verbose)556 output_procinfo_result(PCPResultInfo * pcpResInfo, bool all, bool verbose)
557 {
558 bool printed = false;
559 int i;
560 char *frmt;
561 char strcreatetime[128];
562 char strstarttime[128];
563 int array_size = pcp_result_slot_count(pcpResInfo);
564
565 if (verbose)
566 {
567 frmt = "Database : %s\n"
568 "Username : %s\n"
569 "Start time : %s\n"
570 "Creation time: %s\n"
571 "Major : %d\n"
572 "Minor : %d\n"
573 "Counter : %d\n"
574 "Backend PID : %d\n"
575 "Connected : %d\n"
576 "PID : %d\n"
577 "Backend ID : %d\n";
578 }
579 else
580 {
581 frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
582 }
583
584 for (i = 0; i < array_size; i++)
585 {
586
587 ProcessInfo *process_info = (ProcessInfo *) pcp_get_binary_data(pcpResInfo, i);
588
589 if (process_info == NULL)
590 break;
591 if ((!all) && (process_info->connection_info->database[0] == '\0'))
592 continue;
593 printed = true;
594 *strcreatetime = *strstarttime = '\0';
595
596 if (process_info->start_time)
597 strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
598 if (process_info->connection_info->create_time)
599 strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
600
601 printf(frmt,
602 process_info->connection_info->database,
603 process_info->connection_info->user,
604 strstarttime,
605 strcreatetime,
606 process_info->connection_info->major,
607 process_info->connection_info->minor,
608 process_info->connection_info->counter,
609 process_info->connection_info->pid,
610 process_info->connection_info->connected,
611 process_info->pid,
612 process_info->connection_info->backend_id);
613 }
614 if (printed == false)
615 printf("No process information available\n\n");
616 }
617
618 static void
output_watchdog_info_result(PCPResultInfo * pcpResInfo,bool verbose)619 output_watchdog_info_result(PCPResultInfo * pcpResInfo, bool verbose)
620 {
621 int i;
622 PCPWDClusterInfo *cluster = (PCPWDClusterInfo *) pcp_get_binary_data(pcpResInfo, 0);
623
624 if (verbose)
625 {
626 char *quorumStatus;
627
628 if (cluster->quorumStatus == 0)
629 quorumStatus = "QUORUM IS ON THE EDGE";
630 else if (cluster->quorumStatus == 1)
631 quorumStatus = "QUORUM EXIST";
632 else if (cluster->quorumStatus == -1)
633 quorumStatus = "QUORUM ABSENT";
634 else if (cluster->quorumStatus == -2)
635 quorumStatus = "NO MASTER NODE";
636 else
637 quorumStatus = "UNKNOWN";
638
639 printf("Watchdog Cluster Information \n");
640 printf("Total Nodes : %d\n", cluster->remoteNodeCount + 1);
641 printf("Remote Nodes : %d\n", cluster->remoteNodeCount);
642 printf("Quorum state : %s\n", quorumStatus);
643 printf("Alive Remote Nodes : %d\n", cluster->aliveNodeCount);
644 printf("VIP up on local node : %s\n", cluster->escalated ? "YES" : "NO");
645 printf("Master Node Name : %s\n", cluster->masterNodeName);
646 printf("Master Host Name : %s\n\n", cluster->masterHostName);
647
648 printf("Watchdog Node Information \n");
649 for (i = 0; i < cluster->nodeCount; i++)
650 {
651 PCPWDNodeInfo *watchdog_info = &cluster->nodeList[i];
652
653 printf("Node Name : %s\n", watchdog_info->nodeName);
654 printf("Host Name : %s\n", watchdog_info->hostName);
655 printf("Delegate IP : %s\n", watchdog_info->delegate_ip);
656 printf("Pgpool port : %d\n", watchdog_info->pgpool_port);
657 printf("Watchdog port : %d\n", watchdog_info->wd_port);
658 printf("Node priority : %d\n", watchdog_info->wd_priority);
659 printf("Status : %d\n", watchdog_info->state);
660 printf("Status Name : %s\n\n", watchdog_info->stateName);
661 }
662 }
663 else
664 {
665 printf("%d %s %s %s\n\n",
666 cluster->remoteNodeCount + 1,
667 cluster->escalated ? "YES" : "NO",
668 cluster->masterNodeName,
669 cluster->masterHostName);
670
671 for (i = 0; i < cluster->nodeCount; i++)
672 {
673 PCPWDNodeInfo *watchdog_info = &cluster->nodeList[i];
674
675 printf("%s %s %d %d %d %s\n",
676 watchdog_info->nodeName,
677 watchdog_info->hostName,
678 watchdog_info->pgpool_port,
679 watchdog_info->wd_port,
680 watchdog_info->state,
681 watchdog_info->stateName);
682 }
683 }
684 }
685
686 /* returns true if the current application requires node id argument */
687 static inline bool
app_require_nodeID(void)688 app_require_nodeID(void)
689 {
690 return (current_app_type->app_type == PCP_ATTACH_NODE ||
691 current_app_type->app_type == PCP_DETACH_NODE ||
692 current_app_type->app_type == PCP_NODE_INFO ||
693 current_app_type->app_type == PCP_PROMOTE_NODE ||
694 current_app_type->app_type == PCP_RECOVERY_NODE);
695 }
696
697
698 static void
usage(void)699 usage(void)
700 {
701 fprintf(stderr, "%s - %s\n", progname, current_app_type->description);
702 fprintf(stderr, "Usage:\n");
703 fprintf(stderr, "%s [OPTION...] %s\n", progname,
704 app_require_nodeID() ? "[node-id]" :
705 (current_app_type->app_type == PCP_WATCHDOG_INFO) ? "[watchdog-id]" :
706 (current_app_type->app_type == PCP_PROC_INFO) ? "[process-id]" : "");
707
708 fprintf(stderr, "Options:\n");
709
710 /*
711 * print the command options
712 */
713 fprintf(stderr, " -U, --username=NAME username for PCP authentication\n");
714 fprintf(stderr, " -h, --host=HOSTNAME pgpool-II host\n");
715 fprintf(stderr, " -p, --port=PORT PCP port number\n");
716 fprintf(stderr, " -w, --no-password never prompt for password\n");
717 fprintf(stderr, " -W, --password force password prompt (should happen automatically)\n");
718
719 /*
720 * Now the options not available for all utilities
721 */
722 if (app_require_nodeID())
723 {
724 fprintf(stderr, " -n, --node-id=NODEID ID of a backend node\n");
725 }
726
727 if (current_app_type->app_type == PCP_STOP_PGPOOL)
728 {
729 fprintf(stderr, " -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n");
730 }
731 if (current_app_type->app_type == PCP_PROMOTE_NODE ||
732 current_app_type->app_type == PCP_DETACH_NODE)
733 {
734 fprintf(stderr, " -g, --gracefully promote gracefully(optional)\n");
735 }
736
737 if (current_app_type->app_type == PCP_WATCHDOG_INFO)
738 {
739 fprintf(stderr, " -n, --watchdog-id=ID ID of a other pgpool to get information for\n");
740 fprintf(stderr, " ID 0 for the local watchdog\n");
741 fprintf(stderr, " If omitted then get information of all watchdog nodes\n");
742 }
743 if (current_app_type->app_type == PCP_PROC_INFO)
744 {
745 fprintf(stderr, " -P, --process-id=PID PID of the child process to get information for (optional)\n");
746 fprintf(stderr, " -a, --all display all child processes and their available connection slots\n");
747 }
748
749 fprintf(stderr, " -d, --debug enable debug message (optional)\n");
750 fprintf(stderr, " -v, --verbose output verbose messages\n");
751 fprintf(stderr, " -?, --help print this help\n\n");
752 }
753
754
755 /*
756 * Extracts the actual name of the program as called -
757 * stripped of .exe suffix if any
758 */
759 const char *
get_progname(const char * argv0)760 get_progname(const char *argv0)
761 {
762 const char *nodir_name;
763 char *progname;
764
765 nodir_name = last_dir_separator(argv0);
766 if (nodir_name)
767 nodir_name++;
768 else
769 nodir_name = argv0;
770
771 /*
772 * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
773 * called only once.
774 */
775 progname = strdup(nodir_name);
776 if (progname == NULL)
777 {
778 fprintf(stderr, "%s: out of memory\n", nodir_name);
779 exit(1); /* This could exit the postmaster */
780 }
781
782 return progname;
783 }
784
785 /*
786 * Translate the BACKEND_STATUS enum value to string.
787 * the function returns the constant string so should not be freed
788 */
789 static char *
backend_status_to_string(BackendInfo * bi)790 backend_status_to_string(BackendInfo * bi)
791 {
792 char *statusName;
793
794 switch (bi->backend_status)
795 {
796
797 case CON_UNUSED:
798 statusName = BACKEND_STATUS_CON_UNUSED;
799 break;
800
801 case CON_CONNECT_WAIT:
802 statusName = BACKEND_STATUS_CON_CONNECT_WAIT;
803 break;
804
805 case CON_UP:
806 statusName = BACKEND_STATUS_CON_UP;
807 break;
808
809 case CON_DOWN:
810 {
811 if (bi->quarantine)
812 statusName = BACKEND_STATUS_QUARANTINE;
813 else
814 statusName = BACKEND_STATUS_CON_DOWN;
815 }
816 break;
817
818 default:
819 statusName = "unknown";
820 break;
821 }
822 return statusName;
823 }
824
825 /* Convert enum role to string */
826 char *
role_to_str(SERVER_ROLE role)827 role_to_str(SERVER_ROLE role)
828 {
829 static char *role_str[] = {"master", "slave", "primary", "standby"};
830
831 if (role < ROLE_MASTER || role > ROLE_STANDBY)
832 return "unknown";
833 return role_str[role];
834 }
835