diff --git a/contrib/shell_comp/pgagroal_comp.bash b/contrib/shell_comp/pgagroal_comp.bash index cefc72c1..12b025e9 100644 --- a/contrib/shell_comp/pgagroal_comp.bash +++ b/contrib/shell_comp/pgagroal_comp.bash @@ -25,7 +25,7 @@ pgagroal_cli_completions() COMPREPLY+=($(compgen -W "server prometheus" "${COMP_WORDS[2]}")) ;; conf) - COMPREPLY+=($(compgen -W "reload get set" "${COMP_WORDS[2]}")) + COMPREPLY+=($(compgen -W "reload get set ls" "${COMP_WORDS[2]}")) ;; status) COMPREPLY+=($(compgen -W "details" "${COMP_WORDS[2]}")) diff --git a/contrib/shell_comp/pgagroal_comp.zsh b/contrib/shell_comp/pgagroal_comp.zsh index b0555423..5b0ef704 100644 --- a/contrib/shell_comp/pgagroal_comp.zsh +++ b/contrib/shell_comp/pgagroal_comp.zsh @@ -40,7 +40,7 @@ function _pgagroal_cli_conf() { local line _arguments -C \ - "1: :(reload get set)" \ + "1: :(reload get set ls)" \ "*::arg:->args" } diff --git a/doc/CLI.md b/doc/CLI.md index 62f6ec1c..3a3d5a6a 100644 --- a/doc/CLI.md +++ b/doc/CLI.md @@ -184,7 +184,8 @@ Manages the configuration of the running instance. This command requires one subcommand, that can be: - `reload` issue a reload of the configuration, applying at runtime any changes from the configuration files; - `get` provides a configuration parameter value; -- `set` modifies a configuration parameter at runtime. +- `set` modifies a configuration parameter at runtime; +- `ls` prints where the configuration files are located. Command @@ -205,7 +206,7 @@ pgagroal-cli conf set max_connections 25 The details about how to get and set values at run-time are explained in the following. -### conf get +#### conf get Given a configuration setting name, provides the current value for such setting. The configuration setting name must be the same as the one used in the configuration files. @@ -256,7 +257,7 @@ If the parameter name specified is not found or invalid, the program `pgagroal-c -### conf set +#### conf set Allows the setting of a configuration parameter at run-time, if possible. Examples @@ -303,7 +304,20 @@ WARN 1 settings cannot be applied DEBUG pgagroal_management_write_config_set: unable to apply changes to -> <100> ``` +#### conf ls +The command `conf ls` provides information about the location of the configuration files. +As an example: + +``` +Main Configuration file: /etc/pgagroal/pgagroal.conf +HBA file: /etc/pgagroal/pgagroal_hba.conf +Limit file: /etc/pgagroal/pgagroal_databases.conf +Frontend users file: /etc/pgagroal/pgagroal_frontend_users.conf +Admins file: /etc/pgagroal/pgagroal_admins.conf +Superuser file: +Users file: /etc/pgagroal/pgagroal_users.conf +``` ### clear Resets different parts of the pooler. It accepts an operational mode: diff --git a/src/cli.c b/src/cli.c index dc3a0a30..75c47ee5 100644 --- a/src/cli.c +++ b/src/cli.c @@ -66,6 +66,7 @@ #define ACTION_RELOAD 13 #define ACTION_CONFIG_GET 14 #define ACTION_CONFIG_SET 15 +#define ACTION_CONFIG_LS 16 static int flush(SSL* ssl, int socket, int32_t mode, char* database); static int enabledb(SSL* ssl, int socket, char* database); @@ -82,6 +83,7 @@ static int switch_to(SSL* ssl, int socket, char* server); static int reload(SSL* ssl, int socket); static int config_get(SSL* ssl, int socket, char* config_key, bool verbose); static int config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verbose); +static int config_ls(SSL* ssl, int socket); static void version(void) @@ -134,7 +136,8 @@ usage(void) printf(" - 'get' to obtain information about a runtime configuration value;\n"); printf(" conf get \n"); printf(" - 'set' to modify a configuration value;\n"); - printf(" conf set \n"); + printf(" conf set ;\n"); + printf(" - 'ls' lists the configuration files used.\n"); printf(" clear Resets either the Prometheus statistics or the specified server.\n"); printf(" can be\n"); printf(" - 'server' (default) followed by a server name\n"); @@ -431,20 +434,25 @@ main(int argc, char** argv) { action = ACTION_RELOAD; } - pgagroal_log_debug("Command: "); + pgagroal_log_trace("Command: "); } else if (parse_command(argc, argv, optind, "conf", "get", &config_key, NULL, NULL, NULL) || parse_deprecated_command(argc, argv, optind, "config-get", NULL, "conf get", 1, 6)) { action = config_key != NULL && strlen(config_key) > 0 ? ACTION_CONFIG_GET : ACTION_UNKNOWN; - pgagroal_log_debug("Command: [%s]", config_key); + pgagroal_log_trace("Command: [%s]", config_key); } else if (parse_command(argc, argv, optind, "conf", "set", &config_key, NULL, &config_value, NULL) || parse_deprecated_command(argc, argv, optind, "config-set", NULL, "conf set", 1, 6)) { // if there is no configuration key set the action to unknown, so the help screen will be printed action = config_key != NULL && strlen(config_key) > 0 ? ACTION_CONFIG_SET : ACTION_UNKNOWN; - pgagroal_log_debug("Command: [%s] = [%s]", config_key, config_value); + pgagroal_log_trace("Command: [%s] = [%s]", config_key, config_value); + } + else if (parse_command_simple(argc, argv, optind, "conf", "ls")) + { + pgagroal_log_debug("Command: "); + action = ACTION_CONFIG_LS; } if (action != ACTION_UNKNOWN) @@ -606,6 +614,10 @@ main(int argc, char** argv) { exit_code = config_set(s_ssl, socket, config_key, config_value, verbose); } + else if (action == ACTION_CONFIG_LS) + { + exit_code = config_ls(s_ssl, socket); + } done: @@ -970,3 +982,27 @@ config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verb error: return EXIT_STATUS_CONNECTION_ERROR; } + +/** + * Asks the daemon about the configuration file location. + * + * @returns 0 on success + */ +static int +config_ls(SSL* ssl, int socket) +{ + + if (pgagroal_management_conf_ls(ssl, socket)) + { + goto error; + } + + if (pgagroal_management_read_conf_ls(ssl, socket)) + { + goto error; + } + + return EXIT_STATUS_OK; +error: + return EXIT_STATUS_CONNECTION_ERROR; +} diff --git a/src/include/management.h b/src/include/management.h index 11b26476..0f8ad2ea 100644 --- a/src/include/management.h +++ b/src/include/management.h @@ -61,6 +61,7 @@ extern "C" { #define MANAGEMENT_REMOVE_FD 19 #define MANAGEMENT_CONFIG_GET 20 #define MANAGEMENT_CONFIG_SET 21 +#define MANAGEMENT_CONFIG_LS 22 /** * Read the management header @@ -386,6 +387,60 @@ pgagroal_management_config_set(SSL* ssl, int socket, char* config_key, char* con int pgagroal_management_write_config_set(int socket, char* config_key, char* config_value); +/** + * Entry point for managing the `conf ls` command that + * will list all the configuration files used by the running + * daemon. + * + * @param ssl the SSL handler + * @param fd the socket file descriptor + * @returns 0 on success + */ +int +pgagroal_management_conf_ls(SSL* ssl, int fd); + +/** + * Reads out of the socket the list of configuration + * files and prints them out to the standard output. + * + * The order of the read paths is: + * - configuration path + * - HBA path + * - limit path + * - frontend users path + * - admins path + * - Superusers path + * - users path + * + * @param socket the file descriptor of the open socket + * @param ssl the SSL handler + * @returns 0 on success + */ +int +pgagroal_management_read_conf_ls(SSL* ssl, int socket); + +/** + * The management function responsible for sending + * the configuration paths into the socket. + * + * The function sends every path following the path length, + * that must be limited to MAX_PATH size. + * + * The order of the sent paths is: + * - configuration path + * - HBA path + * - limit path + * - frontend users path + * - admins path + * - Superusers path + * - users path + * + * @params socket the file descriptor of the open socket + * @returns 0 on success + */ +int +pgagroal_management_write_conf_ls(int socket); + #ifdef __cplusplus } #endif diff --git a/src/libpgagroal/management.c b/src/libpgagroal/management.c index 1b104149..908b6766 100644 --- a/src/libpgagroal/management.c +++ b/src/libpgagroal/management.c @@ -59,6 +59,9 @@ static int write_socket(int socket, void* buf, size_t size); static int write_ssl(SSL* ssl, void* buf, size_t size); static int write_header(SSL* ssl, int fd, signed char type, int slot); +static int pgagroal_management_write_conf_ls_detail(int socket, char* what); +static int pgagroal_management_read_conf_ls_detail(SSL* ssl, int socket, char* buffer); + int pgagroal_management_read_header(int socket, signed char* id, int32_t* slot) { @@ -175,6 +178,7 @@ pgagroal_management_read_payload(int socket, signed char id, int* payload_i, cha case MANAGEMENT_DISABLEDB: case MANAGEMENT_CONFIG_GET: case MANAGEMENT_CONFIG_SET: + if (read_complete(NULL, socket, &buf4[0], sizeof(buf4))) { goto error; @@ -213,6 +217,7 @@ pgagroal_management_read_payload(int socket, signed char id, int* payload_i, cha case MANAGEMENT_DETAILS: case MANAGEMENT_RESET: case MANAGEMENT_RELOAD: + case MANAGEMENT_CONFIG_LS: break; default: goto error; @@ -1726,3 +1731,243 @@ pgagroal_management_write_config_set(int socket, char* config_key, char* config_ return 1; } + +int +pgagroal_management_conf_ls(SSL* ssl, int fd) +{ + if (write_header(ssl, fd, MANAGEMENT_CONFIG_LS, -1)) + { + pgagroal_log_warn("pgagroal_management_conf_ls: write: %d", fd); + errno = 0; + goto error; + } + + return 0; + +error: + + return 1; +} + +int +pgagroal_management_read_conf_ls(SSL* ssl, int socket) +{ + char buf[4]; + char* buffer; + + memset(&buf, 0, sizeof(buf)); + buffer = calloc(1, MAX_PATH); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Main Configuration file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("HBA file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Limit file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Frontend users file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Admins file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Superuser file: %s\n", buffer); + + if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer)) + { + goto error; + } + + printf("Users file: %s\n", buffer); + + free(buffer); + + return 0; + +error: + free(buffer); + pgagroal_log_warn("pgagroal_management_read_conf_ls: read: %d %s", socket, strerror(errno)); + errno = 0; + + return 1; +} + +int +pgagroal_management_write_conf_ls(int socket) +{ + struct configuration* config; + + config = (struct configuration*)shmem; + + if (pgagroal_management_write_conf_ls_detail(socket, config->configuration_path)) + { + goto error; + } + + if (pgagroal_management_write_conf_ls_detail(socket, config->hba_path)) + { + goto error; + } + + if (pgagroal_management_write_conf_ls_detail(socket, config->limit_path)) + { + goto error; + } + + // 4 + if (pgagroal_management_write_conf_ls_detail(socket, config->frontend_users_path)) + { + goto error; + } + //5 + if (pgagroal_management_write_conf_ls_detail(socket, config->admins_path)) + { + goto error; + } + //6 + if (pgagroal_management_write_conf_ls_detail(socket, config->superuser_path)) + { + goto error; + } + // 7 + if (pgagroal_management_write_conf_ls_detail(socket, config->users_path)) + { + goto error; + } + + return 0; + +error: + pgagroal_log_debug("pgagroal_management_write_conf_ls: error writing out file paths"); + return 1; +} + +/** + * Utility function to write a single configuration path to the socket. + * + * @param socket the file descriptor of the open socket + * @param what the pointer to the path to send out on the socket. It cannot + * exceed in size MAX_PATH - 1. + * @returns 0 on success + */ +static int +pgagroal_management_write_conf_ls_detail(int socket, char* what) +{ + char buf[4]; + size_t size = 0; + char data[MAX_PATH]; + + if (what && strlen(what) > MAX_PATH) + { + goto error; + } + + memset(&buf, 0, sizeof(buf)); + memset(&data, 0, sizeof(data)); + + size = what ? strlen(what) + 1 : 0; + if (size > MAX_PATH) + { + errno = EMSGSIZE; + goto error; + } + + pgagroal_write_int32(&buf, size); + + if (write_complete(NULL, socket, &buf, sizeof(buf))) + { + goto error; + } + + memcpy(&data[0], what, size); + if (write_complete(NULL, socket, data, size)) + { + goto error; + } + + pgagroal_log_trace("pgagroal_management_write_conf_ls_deail: writing <%s> with %d bytes", what, size); + return 0; + +error: + pgagroal_log_debug("pgagroal_management_write_conf_ls_detail: error %d %s", errno, strerror(errno)); + errno = 0; + return 1; +} + +/** + * Utility function to read back from the socket a configuration path. + * + * It does zero fill the buffer pointed by its argument, so + * it is safe to call this function with a prefilled buffer, but its content + * will be lost. + * + * The buffer will be considered able to store MAX_PATH bytes. + * + * @param socket the file descriptor of the open socket + * @param buffer an already allocated buffer where to place the read value. Only + * MAX_PATH bytes will be read out of socket. + * @return 0 on success + */ +static int +pgagroal_management_read_conf_ls_detail(SSL* ssl, int socket, char* buffer) +{ + char buf[4]; + int size = 0; + + memset(&buf, 0, sizeof(buf)); + memset(buffer, 0, MAX_PATH); + + if (read_complete(ssl, socket, &buf[0], sizeof(buf))) + { + goto error; + } + + size = pgagroal_read_int32(&buf); + + if (size > MAX_PATH) + { + errno = EMSGSIZE; + goto error; + } + + if (read_complete(ssl, socket, buffer, size)) + { + goto error; + } + + return 0; + +error: + memset(buffer, 0, MAX_PATH); + pgagroal_log_warn("pgagroal_management_read_conf_ls_detail: read: %d %s", socket, strerror(errno)); + errno = 0; + + return 1; +} diff --git a/src/main.c b/src/main.c index eeacc2e6..05a46a4d 100644 --- a/src/main.c +++ b/src/main.c @@ -1496,6 +1496,10 @@ accept_mgt_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) pgagroal_log_debug("pgagroal: Management isalive"); pgagroal_management_write_isalive(client_fd, config->gracefully); break; + case MANAGEMENT_CONFIG_LS: + pgagroal_log_debug("pgagroal: Management conf ls"); + pgagroal_management_write_conf_ls(client_fd); + break; case MANAGEMENT_RESET: pgagroal_log_debug("pgagroal: Management reset"); pgagroal_prometheus_reset();