1 /*
2 * $Header$
3 *
4 * pgpool: a language independent connection pool server for PostgreSQL
5 * written by Tatsuo Ishii
6 *
7 * Copyright (c) 2003-2016 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 switch (ch)
169 {
170 case 'd':
171 debug = true;
172 break;
173
174 case 'a':
175 all = true;
176 break;
177
178 case 'w':
179 need_password = false;
180 break;
181
182 case 'W':
183 need_password = true;
184 break;
185
186 case 'g':
187 gracefully = true;
188 break;
189
190 case 'm':
191 if (current_app_type->app_type == PCP_STOP_PGPOOL)
192 {
193 if (strcmp(optarg, "s") == 0 || strcmp(optarg, "smart") == 0)
194 shutdown_mode = 's';
195 else if (strcmp(optarg, "f") == 0 || strcmp(optarg, "fast") == 0)
196 shutdown_mode = 'f';
197 else if (strcmp(optarg, "i") == 0 || strcmp(optarg, "immediate") == 0)
198 shutdown_mode = 'i';
199 else
200 {
201 fprintf(stderr, "%s: Invalid shutdown mode \"%s\", must be either \"smart\" \"immediate\" or \"fast\" \n",progname,optarg);
202 exit(1);
203 }
204 }
205 else
206 {
207 fprintf(stderr, "Invalid argument \"%s\", Try \"%s --help\" for more information.\n",optarg,progname);
208 exit(1);
209 }
210 break;
211
212 case 'v':
213 verbose = true;
214 break;
215
216 case 'n':
217 nodeID = atoi(optarg);
218 if (current_app_type->app_type == PCP_WATCHDOG_INFO)
219 {
220 if (nodeID < 0)
221 {
222 fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for a local watchdog node\n",progname,optarg);
223 exit(0);
224 }
225 }
226 else
227 {
228 if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
229 {
230 fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS);
231 exit(0);
232 }
233 }
234 break;
235
236 case 'p':
237 port = atoi(optarg);
238 if (port <= 1024 || port > 65535)
239 {
240 fprintf(stderr, "%s: Invalid port number \"%s\", must be between 1024 and 65535\n",progname,optarg);
241 exit(0);
242 }
243 break;
244
245 case 'P': /* PID */
246 processID = atoi(optarg);
247 if (processID <= 0 )
248 {
249 fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg);
250 exit(0);
251 }
252 break;
253
254 case 'h':
255 host = strdup(optarg);
256 break;
257
258 case 'U':
259 user = strdup(optarg);
260 break;
261
262 case '?':
263 default:
264 /*
265 * getopt_long whould already have emitted a complaint
266 */
267 fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname);
268 exit(1);
269 }
270 }
271
272 /*
273 * if we still have arguments, use it
274 */
275 while (argc - optind >= 1)
276 {
277 if (current_app_type->app_type == PCP_PROC_INFO && processID <= 0)
278 {
279 processID = atoi(argv[optind]);
280 if (processID <= 0 )
281 {
282 fprintf(stderr, "%s: Invalid process-id \"%s\", must be greater than 0\n",progname,optarg);
283 exit(0);
284 }
285 }
286 else if (current_app_type->app_type == PCP_WATCHDOG_INFO && nodeID < 0)
287 {
288 nodeID = atoi(argv[optind]);
289 if (nodeID < 0 )
290 {
291 fprintf(stderr, "%s: Invalid watchdog-id \"%s\", must be a positive number or zero for local watchdog node\n",progname,optarg);
292 exit(0);
293 }
294 }
295 else if (app_require_nodeID() && nodeID < 0)
296 {
297 nodeID = atoi(argv[optind]);
298 if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
299 {
300 fprintf(stderr, "%s: Invalid node-id \"%s\", must be between 0 and %d\n",progname,optarg,MAX_NUM_BACKENDS);
301 exit(0);
302 }
303 }
304 else
305 fprintf(stderr, "%s: Warning: extra command-line argument \"%s\" ignored\n",
306 progname, argv[optind]);
307
308 optind++;
309 }
310
311 if(nodeID < 0)
312 {
313 if (app_require_nodeID())
314 {
315 fprintf(stderr, "%s: missing node-id\n",progname);
316 fprintf(stderr, "Try \"%s --help\" for more information.\n\n",progname);
317 exit(1);
318 }
319 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
320 {
321 nodeID = -1;
322 }
323 }
324
325 /* Get a new password if appropriate */
326 if (need_password)
327 {
328 pass = simple_prompt("Password: ", 100, false);
329 need_password = false;
330 }
331
332 pcpConn = pcp_connect(host, port, user, pass, debug?stdout:NULL);
333 if(PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
334 {
335 fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
336 exit(1);
337 }
338
339 /*
340 * Okay the connection is successful not call the actual PCP function
341 */
342 if (current_app_type->app_type == PCP_ATTACH_NODE)
343 {
344 pcpResInfo = pcp_attach_node(pcpConn,nodeID);
345 }
346
347 else if (current_app_type->app_type == PCP_DETACH_NODE)
348 {
349 if (gracefully)
350 pcpResInfo = pcp_detach_node_gracefully(pcpConn,nodeID);
351 else
352 pcpResInfo = pcp_detach_node(pcpConn,nodeID);
353 }
354
355 else if (current_app_type->app_type == PCP_NODE_COUNT)
356 {
357 pcpResInfo = pcp_node_count(pcpConn);
358 }
359
360 else if (current_app_type->app_type == PCP_NODE_INFO)
361 {
362 pcpResInfo = pcp_node_info(pcpConn,nodeID);
363 }
364
365 else if (current_app_type->app_type == PCP_POOL_STATUS)
366 {
367 pcpResInfo = pcp_pool_status(pcpConn);
368 }
369
370 else if (current_app_type->app_type == PCP_PROC_COUNT)
371 {
372 pcpResInfo = pcp_process_count(pcpConn);
373 }
374
375 else if (current_app_type->app_type == PCP_PROC_INFO)
376 {
377 pcpResInfo = pcp_process_info(pcpConn, processID);
378 }
379
380 else if (current_app_type->app_type == PCP_PROMOTE_NODE)
381 {
382 if (gracefully)
383 pcpResInfo = pcp_promote_node_gracefully(pcpConn,nodeID);
384 else
385 pcpResInfo = pcp_promote_node(pcpConn,nodeID);
386 }
387
388 else if (current_app_type->app_type == PCP_RECOVERY_NODE)
389 {
390 pcpResInfo = pcp_recovery_node(pcpConn, nodeID);
391 }
392
393 else if (current_app_type->app_type == PCP_STOP_PGPOOL)
394 {
395 pcpResInfo = pcp_terminate_pgpool(pcpConn, shutdown_mode);
396 }
397
398 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
399 {
400 pcpResInfo = pcp_watchdog_info(pcpConn,nodeID);
401 }
402
403 else
404 {
405 /* should never happen */
406 fprintf(stderr,"%s: Invalid pcp process\n",progname);
407 goto DISCONNECT_AND_EXIT;
408 }
409
410 if(pcpResInfo == NULL || PCPResultStatus(pcpResInfo) != PCP_RES_COMMAND_OK)
411 {
412 fprintf(stderr, "%s\n",pcp_get_last_error(pcpConn)?pcp_get_last_error(pcpConn):"Unknown Error");
413 goto DISCONNECT_AND_EXIT;
414 }
415
416 if (pcp_result_is_empty(pcpResInfo))
417 {
418 fprintf(stdout,"%s -- Command Successful\n",progname);
419 }
420 else
421 {
422 if (current_app_type->app_type == PCP_NODE_COUNT)
423 output_nodecount_result(pcpResInfo, verbose);
424
425 if (current_app_type->app_type == PCP_NODE_INFO)
426 output_nodeinfo_result(pcpResInfo, verbose);
427
428 if (current_app_type->app_type == PCP_POOL_STATUS)
429 output_poolstatus_result(pcpResInfo, verbose);
430
431 if (current_app_type->app_type == PCP_PROC_COUNT)
432 output_proccount_result(pcpResInfo, verbose);
433
434 if (current_app_type->app_type == PCP_PROC_INFO)
435 output_procinfo_result(pcpResInfo, all, verbose);
436
437 else if (current_app_type->app_type == PCP_WATCHDOG_INFO)
438 output_watchdog_info_result(pcpResInfo, verbose);
439 }
440
441 DISCONNECT_AND_EXIT:
442
443 pcp_disconnect(pcpConn);
444 pcp_free_connection(pcpConn);
445
446 return 0;
447 }
448
449 static void
output_nodecount_result(PCPResultInfo * pcpResInfo,bool verbose)450 output_nodecount_result(PCPResultInfo* pcpResInfo, bool verbose)
451 {
452 if(verbose)
453 {
454 printf("Node Count\n");
455 printf("____________\n");
456 printf(" %d\n", pcp_get_int_data(pcpResInfo, 0));
457 }
458 else
459 printf("%d\n", pcp_get_int_data(pcpResInfo, 0));
460 }
461
462 static void
output_nodeinfo_result(PCPResultInfo * pcpResInfo,bool verbose)463 output_nodeinfo_result(PCPResultInfo* pcpResInfo, bool verbose)
464 {
465 BackendInfo *backend_info = (BackendInfo *) pcp_get_binary_data(pcpResInfo,0);
466
467 if (verbose)
468 {
469 printf("Hostname : %s\nPort : %d\nStatus : %d\nWeight : %f\nStatus Name: %s\nRole : %s\n",
470 backend_info->backend_hostname,
471 backend_info->backend_port,
472 backend_info->backend_status,
473 backend_info->backend_weight/RAND_MAX,
474 backend_status_to_string(backend_info),
475 role_to_str(backend_info->role));
476 } else {
477 printf("%s %d %d %f %s %s\n",
478 backend_info->backend_hostname,
479 backend_info->backend_port,
480 backend_info->backend_status,
481 backend_info->backend_weight/RAND_MAX,
482 backend_status_to_string(backend_info),
483 role_to_str(backend_info->role));
484 }
485 }
486
487 static void
output_poolstatus_result(PCPResultInfo * pcpResInfo,bool verbose)488 output_poolstatus_result(PCPResultInfo* pcpResInfo, bool verbose)
489 {
490 POOL_REPORT_CONFIG *status;
491 int i;
492 int array_size = pcp_result_slot_count(pcpResInfo);
493
494 if(verbose)
495 {
496 for (i=0; i < array_size; i++)
497 {
498 status = (POOL_REPORT_CONFIG *)pcp_get_binary_data(pcpResInfo, i);
499 printf("Name [%3d]:\t%s\n",i,status?status->name:"NULL");
500 printf("Value: \t%s\n",status?status->value:"NULL");
501 printf("Description:\t%s\n\n",status?status->desc:"NULL");
502 }
503 }
504 else
505 {
506 for (i=0; i < array_size; i++) {
507 status = (POOL_REPORT_CONFIG *)pcp_get_binary_data(pcpResInfo, i);
508 if(status == NULL)
509 {
510 printf("****Data at %d slot is NULL\n",i);
511 continue;
512 }
513 printf("name : %s\nvalue: %s\ndesc : %s\n\n", status->name, status->value, status->desc);
514 }
515 }
516 }
517
518 static void
output_proccount_result(PCPResultInfo * pcpResInfo,bool verbose)519 output_proccount_result(PCPResultInfo* pcpResInfo, bool verbose)
520 {
521 int i;
522 int process_count = pcp_get_data_length(pcpResInfo, 0) / sizeof(int);
523 int *process_list = (int *)pcp_get_binary_data(pcpResInfo, 0);
524
525 if (verbose)
526 {
527 printf("No \t | \t PID\n");
528 printf("_____________________\n");
529 for (i = 0; i < process_count; i++)
530 printf("%d \t | \t %d\n", i,process_list[i]);
531 printf("\nTotal Processes:%d\n",process_count);
532 }
533 else
534 {
535 for (i = 0; i < process_count; i++)
536 printf("%d ", process_list[i]);
537 printf("\n");
538 }
539 }
540
541 static void
output_procinfo_result(PCPResultInfo * pcpResInfo,bool all,bool verbose)542 output_procinfo_result(PCPResultInfo* pcpResInfo, bool all, bool verbose)
543 {
544 bool printed = false;
545 int i;
546 char * frmt;
547 char strcreatetime[128];
548 char strstarttime[128];
549 int array_size = pcp_result_slot_count(pcpResInfo);
550 if (verbose)
551 {
552 if (all)
553 frmt = "Database : %s\n"
554 "Username : %s\n"
555 "Start time : %s\n"
556 "Creation time: %s\n"
557 "Major : %d\n"
558 "Minor : %d\n"
559 "Counter : %d\n"
560 "Backend PID : %d\n"
561 "Connected : %d\n"
562 "PID : %d\n"
563 "Backend ID : %d\n";
564 else
565 frmt = "Database : %s\n"
566 "Username : %s\n"
567 "Start time : %s\n"
568 "Creation time: %s\n"
569 "Major : %d\n"
570 "Minor : %d\n"
571 "Counter : %d\n"
572 "Backend PID : %d\n"
573 "Connected : %d\n";
574 }
575 else
576 {
577 if (all)
578 frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
579 else
580 frmt = "%s %s %s %s %d %d %d %d %d\n";
581 }
582
583 for (i = 0; i < array_size; i++)
584 {
585
586 ProcessInfo *process_info = (ProcessInfo*) pcp_get_binary_data(pcpResInfo, i);
587 if(process_info == NULL)
588 break;
589 if ((!all) && (process_info->connection_info->database[0] == '\0'))
590 continue;
591 printed = true;
592 *strcreatetime = *strstarttime = '\0';
593
594 if (process_info->start_time)
595 strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
596 if (process_info->connection_info->create_time)
597 strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
598
599 printf(frmt,
600 process_info->connection_info->database,
601 process_info->connection_info->user,
602 strstarttime,
603 strcreatetime,
604 process_info->connection_info->major,
605 process_info->connection_info->minor,
606 process_info->connection_info->counter,
607 process_info->connection_info->pid,
608 process_info->connection_info->connected,
609 process_info->pid,
610 process_info->connection_info->backend_id);
611 }
612 if(printed == false)
613 printf("No process information available\n\n");
614 }
615
616 static void
output_watchdog_info_result(PCPResultInfo * pcpResInfo,bool verbose)617 output_watchdog_info_result(PCPResultInfo* pcpResInfo, bool verbose)
618 {
619 int i;
620 PCPWDClusterInfo *cluster = (PCPWDClusterInfo *)pcp_get_binary_data(pcpResInfo,0);
621 if (verbose)
622 {
623 char* quorumStatus;
624 if (cluster->quorumStatus == 0)
625 quorumStatus = "QUORUM IS ON THE EDGE";
626 else if (cluster->quorumStatus == 1)
627 quorumStatus = "QUORUM EXIST";
628 else if (cluster->quorumStatus == -1)
629 quorumStatus = "QUORUM ABSENT";
630 else if (cluster->quorumStatus == -2)
631 quorumStatus = "NO MASTER NODE";
632 else
633 quorumStatus = "UNKNOWN";
634
635 printf("Watchdog Cluster Information \n");
636 printf("Total Nodes : %d\n",cluster->remoteNodeCount +1);
637 printf("Remote Nodes : %d\n",cluster->remoteNodeCount);
638 printf("Quorum state : %s\n",quorumStatus);
639 printf("Alive Remote Nodes : %d\n",cluster->aliveNodeCount);
640 printf("VIP up on local node : %s\n",cluster->escalated?"YES":"NO");
641 printf("Master Node Name : %s\n",cluster->masterNodeName);
642 printf("Master Host Name : %s\n\n",cluster->masterHostName);
643
644 printf("Watchdog Node Information \n");
645 for (i=0; i< cluster->nodeCount; i++)
646 {
647 PCPWDNodeInfo* watchdog_info = &cluster->nodeList[i];
648 printf("Node Name : %s\n",watchdog_info->nodeName);
649 printf("Host Name : %s\n",watchdog_info->hostName);
650 printf("Delegate IP : %s\n",watchdog_info->delegate_ip);
651 printf("Pgpool port : %d\n",watchdog_info->pgpool_port);
652 printf("Watchdog port : %d\n",watchdog_info->wd_port);
653 printf("Node priority : %d\n",watchdog_info->wd_priority);
654 printf("Status : %d\n",watchdog_info->state);
655 printf("Status Name : %s\n\n",watchdog_info->stateName);
656 }
657 }
658 else
659 {
660 printf("%d %s %s %s\n\n",
661 cluster->remoteNodeCount +1,
662 cluster->escalated?"YES":"NO",
663 cluster->masterNodeName,
664 cluster->masterHostName);
665
666 for (i=0; i< cluster->nodeCount; i++)
667 {
668 PCPWDNodeInfo* watchdog_info = &cluster->nodeList[i];
669 printf("%s %s %d %d %d %s\n",
670 watchdog_info->nodeName,
671 watchdog_info->hostName,
672 watchdog_info->pgpool_port,
673 watchdog_info->wd_port,
674 watchdog_info->state,
675 watchdog_info->stateName);
676 }
677 }
678 }
679
680 /* returns true if the current application requires node id argument */
681 static inline bool
app_require_nodeID(void)682 app_require_nodeID(void)
683 {
684 return(current_app_type->app_type == PCP_ATTACH_NODE ||
685 current_app_type->app_type == PCP_DETACH_NODE ||
686 current_app_type->app_type == PCP_NODE_INFO ||
687 current_app_type->app_type == PCP_PROMOTE_NODE ||
688 current_app_type->app_type == PCP_RECOVERY_NODE);
689 }
690
691
692 static void
usage(void)693 usage(void)
694 {
695 fprintf(stderr, "%s - %s\n",progname,current_app_type->description);
696 fprintf(stderr, "Usage:\n");
697 fprintf(stderr, "%s [OPTION...] %s\n",progname,
698 app_require_nodeID()?"[node-id]":
699 (current_app_type->app_type == PCP_WATCHDOG_INFO)?"[watchdog-id]":
700 (current_app_type->app_type == PCP_PROC_INFO)?"[process-id]":"");
701
702 fprintf(stderr, "Options:\n");
703 /*
704 * print the command options
705 */
706 fprintf(stderr, " -U, --username=NAME username for PCP authentication\n");
707 fprintf(stderr, " -h, --host=HOSTNAME pgpool-II host\n");
708 fprintf(stderr, " -p, --port=PORT PCP port number\n");
709 fprintf(stderr, " -w, --no-password never prompt for password\n");
710 fprintf(stderr, " -W, --password force password prompt (should happen automatically)\n");
711 /*
712 * Now the options not available for all utilities
713 */
714 if (app_require_nodeID())
715 {
716 fprintf(stderr, " -n, --node-id=NODEID ID of a backend node\n");
717 }
718
719 if (current_app_type->app_type == PCP_STOP_PGPOOL)
720 {
721 fprintf(stderr, " -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n");
722 }
723 if (current_app_type->app_type == PCP_PROMOTE_NODE ||
724 current_app_type->app_type == PCP_DETACH_NODE)
725 {
726 fprintf(stderr, " -g, --gracefully promote gracefully(optional)\n");
727 }
728
729 if (current_app_type->app_type == PCP_WATCHDOG_INFO)
730 {
731 fprintf(stderr, " -n, --watchdog-id=ID ID of a other pgpool to get information for\n");
732 fprintf(stderr, " ID 0 for the local watchdog\n");
733 fprintf(stderr, " If omitted then get information of all watchdog nodes\n");
734 }
735 if (current_app_type->app_type == PCP_PROC_INFO)
736 {
737 fprintf(stderr, " -P, --process-id=PID PID of the child process to get information for (optional)\n");
738 fprintf(stderr, " -a, --all display all child processes and their available connection slots\n");
739 }
740
741 fprintf(stderr, " -d, --debug enable debug message (optional)\n");
742 fprintf(stderr, " -v, --verbose output verbose messages\n");
743 fprintf(stderr, " -?, --help print this help\n\n");
744 }
745
746
747 /*
748 * Extracts the actual name of the program as called -
749 * stripped of .exe suffix if any
750 */
751 const char *
get_progname(const char * argv0)752 get_progname(const char *argv0)
753 {
754 const char *nodir_name;
755 char *progname;
756
757 nodir_name = last_dir_separator(argv0);
758 if (nodir_name)
759 nodir_name++;
760 else
761 nodir_name = argv0;
762
763 /*
764 * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
765 * called only once.
766 */
767 progname = strdup(nodir_name);
768 if (progname == NULL)
769 {
770 fprintf(stderr, "%s: out of memory\n", nodir_name);
771 exit(1); /* This could exit the postmaster */
772 }
773
774 return progname;
775 }
776
777 /*
778 * Translate the BACKEND_STATUS enum value to string.
779 * the function returns the constant string so should not be freed
780 */
backend_status_to_string(BackendInfo * bi)781 static char* backend_status_to_string(BackendInfo *bi)
782 {
783 char *statusName;
784
785 switch (bi->backend_status) {
786
787 case CON_UNUSED:
788 statusName = BACKEND_STATUS_CON_UNUSED;
789 break;
790
791 case CON_CONNECT_WAIT:
792 statusName = BACKEND_STATUS_CON_CONNECT_WAIT;
793 break;
794
795 case CON_UP:
796 statusName = BACKEND_STATUS_CON_UP;
797 break;
798
799 case CON_DOWN:
800 {
801 if (bi->quarantine)
802 statusName = BACKEND_STATUS_QUARANTINE;
803 else
804 statusName = BACKEND_STATUS_CON_DOWN;
805 }
806 break;
807
808 default:
809 statusName = "unknown";
810 break;
811 }
812 return statusName;
813 }
814
815 /* Convert enum role to string */
role_to_str(SERVER_ROLE role)816 char *role_to_str(SERVER_ROLE role)
817 {
818 static char *role_str[] = {"master", "slave", "primary", "standby"};
819 if (role < ROLE_MASTER || role > ROLE_STANDBY)
820 return "unknown";
821 return role_str[role];
822 }
823