Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions lib/MySQL_Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1261,14 +1261,25 @@ void MySQL_Logger::audit_flush_log_unlocked() {
}

void MySQL_Logger::events_open_log_unlocked() {
events.log_file_id=events_find_next_id();
if (events.log_file_id!=0) {
events.log_file_id=events_find_next_id()+1;
} else {
events.log_file_id++;
// Check if this is a special device file like /dev/stdout or /dev/stderr
bool is_special_device = (strcmp(events.base_filename, "/dev/stdout") == 0 ||
strcmp(events.base_filename, "/dev/stderr") == 0);

if (!is_special_device) {
events.log_file_id=events_find_next_id();
if (events.log_file_id!=0) {
events.log_file_id=events_find_next_id()+1;
} else {
events.log_file_id++;
}
Comment on lines +1269 to +1274

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The events_find_next_id() function is called multiple times, which is inefficient and could lead to incorrect behavior if the directory contents change between calls. To avoid this, call the function once and store the result.

Suggested change
events.log_file_id=events_find_next_id();
if (events.log_file_id!=0) {
events.log_file_id=events_find_next_id()+1;
} else {
events.log_file_id++;
}
events.log_file_id=events_find_next_id();
events.log_file_id++;

}

char *filen=NULL;
if (events.base_filename[0]=='/') { // absolute path
if (is_special_device) {
// For special device files, use the filename directly without rotation
filen=(char *)malloc(strlen(events.base_filename)+1);
strcpy(filen, events.base_filename);
Comment on lines +1280 to +1281

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using strdup instead of malloc and strcpy for a more concise and safer way to allocate memory and copy the string.

Suggested change
filen=(char *)malloc(strlen(events.base_filename)+1);
strcpy(filen, events.base_filename);
filen=strdup(events.base_filename);

} else if (events.base_filename[0]=='/') { // absolute path
filen=(char *)malloc(strlen(events.base_filename)+11);
sprintf(filen,"%s.%08d",events.base_filename,events.log_file_id);
} else { // relative path
Expand Down Expand Up @@ -1310,14 +1321,25 @@ void MySQL_Logger::events_open_log_unlocked() {
};

void MySQL_Logger::audit_open_log_unlocked() {
audit.log_file_id=audit_find_next_id();
if (audit.log_file_id!=0) {
audit.log_file_id=audit_find_next_id()+1;
} else {
audit.log_file_id++;
// Check if this is a special device file like /dev/stdout or /dev/stderr
bool is_special_device = (strcmp(audit.base_filename, "/dev/stdout") == 0 ||
strcmp(audit.base_filename, "/dev/stderr") == 0);

if (!is_special_device) {
audit.log_file_id=audit_find_next_id();
if (audit.log_file_id!=0) {
audit.log_file_id=audit_find_next_id()+1;
} else {
audit.log_file_id++;
}
Comment on lines +1329 to +1334

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The audit_find_next_id() function is called multiple times, which is inefficient and could lead to incorrect behavior if the directory contents change between calls. To avoid this, call the function once and store the result.

Suggested change
audit.log_file_id=audit_find_next_id();
if (audit.log_file_id!=0) {
audit.log_file_id=audit_find_next_id()+1;
} else {
audit.log_file_id++;
}
audit.log_file_id=audit_find_next_id();
audit.log_file_id++;

}

char *filen=NULL;
if (audit.base_filename[0]=='/') { // absolute path
if (is_special_device) {
// For special device files, use the filename directly without rotation
filen=(char *)malloc(strlen(audit.base_filename)+1);
strcpy(filen, audit.base_filename);
Comment on lines +1340 to +1341

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using strdup instead of malloc and strcpy for a more concise and safer way to allocate memory and copy the string.

Suggested change
filen=(char *)malloc(strlen(audit.base_filename)+1);
strcpy(filen, audit.base_filename);
filen=strdup(audit.base_filename);

} else if (audit.base_filename[0]=='/') { // absolute path
filen=(char *)malloc(strlen(audit.base_filename)+11);
sprintf(filen,"%s.%08d",audit.base_filename,audit.log_file_id);
} else { // relative path
Expand Down
92 changes: 92 additions & 0 deletions test/tap/tests/test_logger_special_devices-t.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* @file test_logger_special_devices-t.cpp
* @brief Tests for MySQL_Logger special device file handling (/dev/stdout, /dev/stderr)
* @details This test ensures that eventslog_filename and auditlog_filename can be set to
* special device files like /dev/stdout and /dev/stderr without rotation errors.
*/

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <string>
#include <fstream>

#include "mysql.h"
#include "mysqld_error.h"
#include "proxysql.h"
#include "cpp-dotenv/dotenv.h"

#include "tap.h"
#include "command_line.h"
#include "utils.h"

int main(int argc, char** argv) {
CommandLine cl;

if (cl.getEnv()) {
diag("Failed to get the required environmental variables.");
return -1;
}

MYSQL* proxysql_admin = mysql_init(NULL);

if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
return -1;
}

plan(6);

// Test 1: Set eventslog_filename to /dev/stdout (should not fail)
{
MYSQL_QUERY(proxysql_admin, "SET mysql-eventslog_filename='/dev/stdout'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
ok(true, "Successfully set eventslog_filename to /dev/stdout");
}

// Test 2: Set eventslog_filename to /dev/stderr (should not fail)
{
MYSQL_QUERY(proxysql_admin, "SET mysql-eventslog_filename='/dev/stderr'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
ok(true, "Successfully set eventslog_filename to /dev/stderr");
}

// Test 3: Set auditlog_filename to /dev/stdout (should not fail)
{
MYSQL_QUERY(proxysql_admin, "SET mysql-auditlog_filename='/dev/stdout'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
ok(true, "Successfully set auditlog_filename to /dev/stdout");
}

// Test 4: Set auditlog_filename to /dev/stderr (should not fail)
{
MYSQL_QUERY(proxysql_admin, "SET mysql-auditlog_filename='/dev/stderr'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
ok(true, "Successfully set auditlog_filename to /dev/stderr");
}

// Test 5: FLUSH LOGS with special device should work
{
MYSQL_QUERY(proxysql_admin, "SET mysql-eventslog_filename='/dev/stdout'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH LOGS");
ok(true, "FLUSH LOGS works with /dev/stdout");
}

// Test 6: Verify we can switch back to regular file
{
MYSQL_QUERY(proxysql_admin, "SET mysql-eventslog_filename='/tmp/test_events.log'");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
ok(true, "Successfully switched back to regular file");
}

// Cleanup
MYSQL_QUERY(proxysql_admin, "SET mysql-eventslog_filename=''");
MYSQL_QUERY(proxysql_admin, "SET mysql-auditlog_filename=''");
MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");

mysql_close(proxysql_admin);

return exit_status();
}