Skip to content

Commit

Permalink
[#285] Introduce update_process_title setting
Browse files Browse the repository at this point in the history
This commit adds the `update_process_title` configuration setting.
Values for such setting are:
- `never` or `off`, means the user does not want to update the process
title at all;
- `strict` (used on Linux and systems that do no provide a native call
to update the process title) allows for changing the process title
without overflowing the length of the initial command line;
- `minimal` sets the process title to `user/database` even if this
exceeds the initial command line length;
- `verbose` sets the process title to `user@host:port/database` even
if this overflows the initial command line length.

By default the setting is configured as `verbose`, but this could
break some aggressively secured environments, where no native way to
set the process title is provided.

The `pgagroal_set_proc_title` function has been refactored so that, if
the update policy is set to `never` the process title will never be
updated. This can be confusing because even the "main" process will
not have a title update.
Likely, if the policy is `strict`, the function will never try to
overflow the initial command line length.

When set to `verbose` or leaved as default, the process title is built
with information about the hostname, port, username and database.
This can produce a very long title, that is in any case cut at
`MAX_PROCESS_TITLE_LENGTH` (256 bytes, including the terminator).
In the unluckily case the primary server cannot be determined, the
`verbose` mode is set back to `minimal`, but this indicates there is
something wrong somewhere else.

On those systems that do provide a native way to set the process
title, there is no difference between `strict` and `minimal` and the
`minmal` policy is always adopted.

Documentation updated.

Close #285
  • Loading branch information
fluca1978 committed Jul 14, 2022
1 parent 3350e1b commit b089d43
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 8 deletions.
1 change: 1 addition & 0 deletions doc/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ See a more complete [sample](./etc/pgagroal.conf) configuration for running `pga
| tracker | off | Bool | No | Track connection lifecycle |
| track_prepared_statements | off | Bool | No | Track prepared statements (transaction pooling) |
| pidfile | | String | No | Path to the PID file. If omitted, automatically set to `unix_socket_dir`/pgagroal.`port`.pid |
| update_process_title | `verbose` | No | The behavior for updating the operating system process title, mainly related to connection processes. Allowed settings are: `never` (or `off`), does not update the process title; `strict` to set the process title without overriding the existing initial process title length; `minimal` to set the process title to `username/database`; `verbose` (or `full`) to set the process title to `user@host:port/database`. Please note that `strict` and `minimal` are honored only on those systems that do not provide a native way to set the process title (e.g., Linux). On other systems, there is no difference between `strict` and `minimal` and the assumed behaviour is `minimal` even if `strict` is used. `never` and `verbose` are always honored, on every system. On Linux systems the process title is always trimmed to 255 characters, while on system that provide a natve way to set the process title it can be longer. |

__Danger zone__

Expand Down
8 changes: 8 additions & 0 deletions src/include/pgagroal.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ extern "C" {
#define PGAGROAL_DEFAULT_ADMINS_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_admins.conf"
#define PGAGROAL_DEFAULT_SUPERUSER_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_superuser.conf"

#define MAX_PROCESS_TITLE_LENGTH 256

#define MAX_BUFFER_SIZE 65535
#define DEFAULT_BUFFER_SIZE 65535
Expand Down Expand Up @@ -134,6 +135,11 @@ extern "C" {
#define HUGEPAGE_TRY 1
#define HUGEPAGE_ON 2

#define UPDATE_PROCESS_TITLE_NEVER 0
#define UPDATE_PROCESS_TITLE_STRICT 1
#define UPDATE_PROCESS_TITLE_MINIMAL 2
#define UPDATE_PROCESS_TITLE_VERBOSE 3

#define likely(x) __builtin_expect (!!(x), 1)
#define unlikely(x) __builtin_expect (!!(x), 0)

Expand Down Expand Up @@ -399,6 +405,8 @@ struct configuration
char log_line_prefix[MISC_LENGTH]; /**< The logging prefix */
atomic_schar log_lock; /**< The logging lock */

unsigned int update_process_title; /**< Behaviour for updating the process title */

bool authquery; /**< Is authentication query enabled */

bool tls; /**< Is TLS enabled */
Expand Down
21 changes: 20 additions & 1 deletion src/include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,22 @@ int
pgagroal_base64_decode(char* encoded, size_t encoded_length, char** raw, int* raw_length);

/**
* Set process title
* Set process title.
*
* The function will autonomously check the update policy set
* via the configuration option `update_process_title` and
* will do nothing if the setting is `never`.
* In the case the policy is set to `strict`, the process title
* will not overflow the initial command line length (i.e., strlen(argv[*]))
* otherwise it will do its best to set the title to the desired string.
*
* The policies `strict` and `minimal` will be honored only on Linux platforms
* where a native call to set the process title is not available.
*
*
* The resulting process title will be set to either `s1` or `s1/s2` if there
* both strings and the length is allowed by the policy.
*
* @param argc The number of arguments
* @param argv The argv pointer
* @param s1 The first string
Expand All @@ -261,6 +276,10 @@ pgagroal_set_proc_title(int argc, char** argv, char* s1, char* s2);
* with the form
* user@host:port/database
*
* This means that all the policies honored by the latter function and
* set via the `update_process_title` configuration paramter will be
* honored.
*
* @param argc the number of arguments
* @param argv command line arguments
* @param connection the struct connection pointer for the established connection.
Expand Down
63 changes: 63 additions & 0 deletions src/libpgagroal/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ static int as_logging_rotation_age(char* str, unsigned int* age);
static int as_validation(char* str);
static int as_pipeline(char* str);
static int as_hugepage(char* str);
static unsigned int as_update_process_title(char* str, unsigned int* policy, unsigned int default_policy);
static int extract_value(char* str, int offset, char** value);
static void extract_hba(char* str, char** type, char** database, char** user, char** address, char** method);
static void extract_limit(char* str, int server_max, char** database, char** user, int* max_size, int* initial_size, int* min_size);
Expand Down Expand Up @@ -141,6 +142,8 @@ pgagroal_init_configuration(void* shm)

atomic_init(&config->su_connection, STATE_FREE);

config->update_process_title = UPDATE_PROCESS_TITLE_VERBOSE;

return 0;
}

Expand Down Expand Up @@ -570,6 +573,13 @@ pgagroal_read_configuration(void* shm, char* filename, bool emitWarnings)
unknown = true;
}
}
else if (key_in_section("update_process_title", section, key, true, &unknown))
{
if (as_update_process_title(value, &config->update_process_title, UPDATE_PROCESS_TITLE_VERBOSE))
{
unknown = false;
}
}
else
{
unknown = true;
Expand Down Expand Up @@ -2416,6 +2426,9 @@ transfer_configuration(struct configuration* config, struct configuration* reloa
config->metrics_cache_max_age = reload->metrics_cache_max_age;
restart_int("metrics_cache_max_size", config->metrics_cache_max_size, reload->metrics_cache_max_size);
config->management = reload->management;

config->update_process_title = reload->update_process_title;

/* gracefully */

/* disabled */
Expand Down Expand Up @@ -3133,3 +3146,53 @@ as_bytes(char* str, unsigned int* bytes, unsigned int default_bytes)
return 1;
}
}

/**
* Utility function to understand the setting for updating
* the process title.
*
* @param str the value obtained by the configuration parsing
* @param policy the pointer to the value where the setting will be stored
* @param default_policy a value to set when the configuration cannot be
* understood
*
* @return 0 on success, 1 on error. In any case the `policy` variable is set to
* `default_policy`.
*/
static unsigned int
as_update_process_title(char* str, unsigned int* policy, unsigned int default_policy)
{
if (is_empty_string(str))
{
*policy = default_policy;
return 1;
}

if (!strncmp(str, "never", MISC_LENGTH) || !strncmp(str, "off", MISC_LENGTH))
{
*policy = UPDATE_PROCESS_TITLE_NEVER;
return 0;
}
else if (!strncmp(str, "strict", MISC_LENGTH))
{
*policy = UPDATE_PROCESS_TITLE_STRICT;
return 0;
}
else if (!strncmp(str, "minimal", MISC_LENGTH))
{
*policy = UPDATE_PROCESS_TITLE_MINIMAL;
return 0;
}
else if (!strncmp(str, "verbose", MISC_LENGTH) || !strncmp(str, "full", MISC_LENGTH))
{
*policy = UPDATE_PROCESS_TITLE_VERBOSE;
return 0;
}
else
{
// not a valid setting
*policy = default_policy;
return 1;
}

}
38 changes: 32 additions & 6 deletions src/libpgagroal/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,20 @@ void
pgagroal_set_proc_title(int argc, char** argv, char* s1, char* s2)
{
#ifdef HAVE_LINUX
char title[256];
char title[MAX_PROCESS_TITLE_LENGTH];
size_t size;
char** env = environ;
int es = 0;
struct configuration* config;

config = (struct configuration*)shmem;

// sanity check: if the user does not want to
// update the process title, do nothing
if (config->update_process_title == UPDATE_PROCESS_TITLE_NEVER)
{
return;
}

if (!env_changed)
{
Expand Down Expand Up @@ -772,11 +782,21 @@ pgagroal_set_proc_title(int argc, char** argv, char* s1, char* s2)
s1 != NULL && s2 != NULL ? "/" : "",
s2 != NULL ? s2 : "");

size = strlen(title) + 1;

// nuke the command line info
memset(*argv, 0, max_process_title_size);

// copy the new title over argv checking
// the update_process_title policy
if (config->update_process_title == UPDATE_PROCESS_TITLE_STRICT)
{
size = max_process_title_size;
}
else
{
// here we can set the title to a full description
size = strlen(title) + 1;
}

memcpy(*argv, title, size);
memset(*argv + size, 0, 1);

Expand All @@ -797,13 +817,19 @@ pgagroal_set_connection_proc_title(int argc, char** argv, struct connection* con
{
struct configuration* config;
int primary;
char info[MISC_LENGTH];
char info[MAX_PROCESS_TITLE_LENGTH];

config = (struct configuration*)shmem;

pgagroal_get_primary(&primary);
if (pgagroal_get_primary(&primary))
{
// cannot find the primary, this is a problem!
pgagroal_set_proc_title(argc, argv, connection->username, connection->database);
return;
}

snprintf(info, MISC_LENGTH, "%s@%s:%d",
memset(&info, 0, sizeof(info));
snprintf(info, MAX_PROCESS_TITLE_LENGTH - 1, "%s@%s:%d",
connection->username,
config->servers[primary].host,
config->servers[primary].port);
Expand Down
14 changes: 13 additions & 1 deletion src/libpgagroal/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,19 @@ pgagroal_worker(int client_fd, char* address, char** argv)
pgagroal_prometheus_client_active_add();

pgagroal_pool_status();
pgagroal_set_connection_proc_title(1, argv, &config->connections[slot]);

// do we have to update the process title?
switch (config->update_process_title)
{
case UPDATE_PROCESS_TITLE_MINIMAL:
case UPDATE_PROCESS_TITLE_STRICT:
// pgagroal_set_proc_title will check the policy
pgagroal_set_proc_title(1, argv, config->connections[slot].username, config->connections[slot].database);
break;
case UPDATE_PROCESS_TITLE_VERBOSE:
pgagroal_set_connection_proc_title(1, argv, &config->connections[slot]);
break;
}

if (config->pipeline == PIPELINE_PERFORMANCE)
{
Expand Down

0 comments on commit b089d43

Please sign in to comment.