[monitoring-plugins] Refactor check_mysql

Lorenz Kästle git at monitoring-plugins.org
Tue Mar 11 13:40:12 CET 2025


 Module: monitoring-plugins
 Branch: master
 Commit: 3143b5217cf1c71a085e6c4c7d22a5b699c4ff07
 Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
   Date: Tue Mar 11 13:22:13 2025 +0100
    URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=3143b521

Refactor check_mysql

---

 plugins/Makefile.am            |   1 +
 plugins/check_mysql.c          | 217 +++++++++++++++++++----------------------
 plugins/check_mysql.d/config.h |  58 +++++++++++
 3 files changed, 160 insertions(+), 116 deletions(-)

diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 06958849..9449f051 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -60,6 +60,7 @@ EXTRA_DIST = t \
 			 check_apt.d \
 			 check_by_ssh.d \
 			 check_smtp.d \
+			 check_mysql.d \
 			 check_dig.d \
 			 check_cluster.d \
 			 check_fping.d
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index 2b6cfeaf..ca3422b5 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -40,32 +40,14 @@ const char *email = "devel at monitoring-plugins.org";
 #include "utils.h"
 #include "utils_base.h"
 #include "netutils.h"
+#include "check_mysql.d/config.h"
 
 #include <mysql.h>
 #include <mysqld_error.h>
 #include <errmsg.h>
 
-static char *db_user = NULL;
-static char *db_host = NULL;
-static char *db_socket = NULL;
-static char *db_pass = NULL;
-static char *db = NULL;
-static char *ca_cert = NULL;
-static char *ca_dir = NULL;
-static char *cert = NULL;
-static char *key = NULL;
-static char *ciphers = NULL;
-static bool ssl = false;
-static char *opt_file = NULL;
-static char *opt_group = NULL;
-static unsigned int db_port = MYSQL_PORT;
-static bool check_replica = false;
-static bool ignore_auth = false;
 static int verbose = 0;
 
-static double warning_time = 0;
-static double critical_time = 0;
-
 #define LENGTH_METRIC_UNIT 6
 static const char *metric_unit[LENGTH_METRIC_UNIT] = {
 	"Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"};
@@ -78,28 +60,16 @@ static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
 #define MYSQLDUMP_THREADS_QUERY                                                                                                            \
 	"SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
 
-static thresholds *my_threshold = NULL;
-
-static int process_arguments(int, char **);
-static int validate_arguments(void);
+typedef struct {
+	int errorcode;
+	check_mysql_config config;
+} check_mysql_config_wrapper;
+static check_mysql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
+static check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper /*config_wrapper*/);
 static void print_help(void);
 void print_usage(void);
 
 int main(int argc, char **argv) {
-
-	MYSQL mysql;
-	MYSQL_RES *res;
-	MYSQL_ROW row;
-
-	/* should be status */
-
-	char *result = NULL;
-	char *error = NULL;
-	char replica_result[REPLICA_RESULTSIZE] = {0};
-	char *perf;
-
-	perf = strdup("");
-
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
@@ -107,36 +77,43 @@ int main(int argc, char **argv) {
 	/* Parse extra opts if any */
 	argv = np_extra_opts(&argc, argv, progname);
 
-	if (process_arguments(argc, argv) == ERROR) {
+	check_mysql_config_wrapper tmp_config = process_arguments(argc, argv);
+	if (tmp_config.errorcode == ERROR) {
 		usage4(_("Could not parse arguments"));
 	}
 
+	const check_mysql_config config = tmp_config.config;
+
+	MYSQL mysql;
 	/* initialize mysql  */
 	mysql_init(&mysql);
 
-	if (opt_file != NULL) {
-		mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, opt_file);
+	if (config.opt_file != NULL) {
+		mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
 	}
 
-	if (opt_group != NULL) {
-		mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, opt_group);
+	if (config.opt_group != NULL) {
+		mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
 	} else {
 		mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
 	}
 
-	if (ssl) {
-		mysql_ssl_set(&mysql, key, cert, ca_cert, ca_dir, ciphers);
+	if (config.ssl) {
+		mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers);
 	}
 	/* establish a connection to the server and error checking */
-	if (!mysql_real_connect(&mysql, db_host, db_user, db_pass, db, db_port, db_socket, 0)) {
+	if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
 		/* Depending on internally-selected auth plugin MySQL might return */
 		/* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
 		/* Semantically these errors are the same. */
-		if (ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
+		if (config.ignore_auth &&
+			(mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
 			printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
 			mysql_close(&mysql);
 			return STATE_OK;
-		} else if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
+		}
+
+		if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
 			die(STATE_WARNING, "%s\n", mysql_error(&mysql));
 		} else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
 			die(STATE_WARNING, "%s\n", mysql_error(&mysql));
@@ -152,7 +129,7 @@ int main(int argc, char **argv) {
 	}
 
 	/* get the server stats */
-	result = strdup(mysql_stat(&mysql));
+	char *result = strdup(mysql_stat(&mysql));
 
 	/* error checking once more */
 	if (mysql_error(&mysql)) {
@@ -165,6 +142,10 @@ int main(int argc, char **argv) {
 		}
 	}
 
+	char *perf = strdup("");
+	char *error = NULL;
+	MYSQL_RES *res;
+	MYSQL_ROW row;
 	/* try to fetch some perf data */
 	if (mysql_query(&mysql, "show global status") == 0) {
 		if ((res = mysql_store_result(&mysql)) == NULL) {
@@ -174,15 +155,13 @@ int main(int argc, char **argv) {
 		}
 
 		while ((row = mysql_fetch_row(res)) != NULL) {
-			int i;
-
-			for (i = 0; i < LENGTH_METRIC_UNIT; i++) {
+			for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
 				if (strcmp(row[0], metric_unit[i]) == 0) {
 					xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
 					continue;
 				}
 			}
-			for (i = 0; i < LENGTH_METRIC_COUNTER; i++) {
+			for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
 				if (strcmp(row[0], metric_counter[i]) == 0) {
 					xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
 					continue;
@@ -195,8 +174,8 @@ int main(int argc, char **argv) {
 		}
 	}
 
-	if (check_replica) {
-
+	char replica_result[REPLICA_RESULTSIZE] = {0};
+	if (config.check_replica) {
 		// Detect which version we are, on older version
 		// "show slave status" should work, on newer ones
 		// "show replica status"
@@ -283,12 +262,14 @@ int main(int argc, char **argv) {
 
 		} else {
 			/* mysql 4.x.x and mysql 5.x.x */
-			int replica_io_field = -1, replica_sql_field = -1, seconds_behind_field = -1, i, num_fields;
+			int replica_io_field = -1;
+			int replica_sql_field = -1;
+			int seconds_behind_field = -1;
+			int num_fields;
 			MYSQL_FIELD *fields;
-
 			num_fields = mysql_num_fields(res);
 			fields = mysql_fetch_fields(res);
-			for (i = 0; i < num_fields; i++) {
+			for (int i = 0; i < num_fields; i++) {
 				if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
 					replica_io_field = i;
 					continue;
@@ -353,11 +334,11 @@ int main(int argc, char **argv) {
 				double value = atof(row[seconds_behind_field]);
 				int status;
 
-				status = get_status(value, my_threshold);
+				status = get_status(value, config.my_threshold);
 
 				xasprintf(&perf, "%s %s", perf,
-						  fperfdata("seconds behind master", value, "s", true, (double)warning_time, true, (double)critical_time, false, 0,
-									false, 0));
+						  fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true,
+									(double)config.critical_time, false, 0, false, 0));
 
 				if (status == STATE_WARNING) {
 					printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf);
@@ -377,7 +358,7 @@ int main(int argc, char **argv) {
 	mysql_close(&mysql);
 
 	/* print out the result of stats */
-	if (check_replica) {
+	if (config.check_replica) {
 		printf("%s %s|%s\n", result, replica_result, perf);
 	} else {
 		printf("%s|%s\n", result, perf);
@@ -389,12 +370,7 @@ int main(int argc, char **argv) {
 #define CHECK_REPLICA_OPT CHAR_MAX + 1
 
 /* process command-line arguments */
-int process_arguments(int argc, char **argv) {
-	int c;
-	char *warning = NULL;
-	char *critical = NULL;
-
-	int option = 0;
+check_mysql_config_wrapper process_arguments(int argc, char **argv) {
 	static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
 									   {"socket", required_argument, 0, 's'},
 									   {"database", required_argument, 0, 'd'},
@@ -419,56 +395,66 @@ int process_arguments(int argc, char **argv) {
 									   {"ciphers", required_argument, 0, 'L'},
 									   {0, 0, 0, 0}};
 
+	check_mysql_config_wrapper result = {
+		.errorcode = OK,
+		.config = check_mysql_config_init(),
+	};
+
 	if (argc < 1) {
-		return ERROR;
+		result.errorcode = ERROR;
+		return result;
 	}
 
-	while (1) {
-		c = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
+	char *warning = NULL;
+	char *critical = NULL;
+
+	int option = 0;
+	while (true) {
+		int option_index = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
 
-		if (c == -1 || c == EOF) {
+		if (option_index == -1 || option_index == EOF) {
 			break;
 		}
 
-		switch (c) {
+		switch (option_index) {
 		case 'H': /* hostname */
 			if (is_host(optarg)) {
-				db_host = optarg;
+				result.config.db_host = optarg;
 			} else if (*optarg == '/') {
-				db_socket = optarg;
+				result.config.db_socket = optarg;
 			} else {
 				usage2(_("Invalid hostname/address"), optarg);
 			}
 			break;
 		case 's': /* socket */
-			db_socket = optarg;
+			result.config.db_socket = optarg;
 			break;
 		case 'd': /* database */
-			db = optarg;
+			result.config.db = optarg;
 			break;
 		case 'l':
-			ssl = true;
+			result.config.ssl = true;
 			break;
 		case 'C':
-			ca_cert = optarg;
+			result.config.ca_cert = optarg;
 			break;
 		case 'a':
-			cert = optarg;
+			result.config.cert = optarg;
 			break;
 		case 'k':
-			key = optarg;
+			result.config.key = optarg;
 			break;
 		case 'D':
-			ca_dir = optarg;
+			result.config.ca_dir = optarg;
 			break;
 		case 'L':
-			ciphers = optarg;
+			result.config.ciphers = optarg;
 			break;
 		case 'u': /* username */
-			db_user = optarg;
+			result.config.db_user = optarg;
 			break;
 		case 'p': /* authentication information: password */
-			db_pass = strdup(optarg);
+			result.config.db_pass = strdup(optarg);
 
 			/* Delete the password from process list */
 			while (*optarg != '\0') {
@@ -477,28 +463,28 @@ int process_arguments(int argc, char **argv) {
 			}
 			break;
 		case 'f': /* client options file */
-			opt_file = optarg;
+			result.config.opt_file = optarg;
 			break;
 		case 'g': /* client options group */
-			opt_group = optarg;
+			result.config.opt_group = optarg;
 			break;
 		case 'P': /* critical time threshold */
-			db_port = atoi(optarg);
+			result.config.db_port = atoi(optarg);
 			break;
 		case 'S':
 		case CHECK_REPLICA_OPT:
-			check_replica = true; /* check-slave */
+			result.config.check_replica = true; /* check-slave */
 			break;
 		case 'n':
-			ignore_auth = true; /* ignore-auth */
+			result.config.ignore_auth = true; /* ignore-auth */
 			break;
 		case 'w':
 			warning = optarg;
-			warning_time = strtod(warning, NULL);
+			result.config.warning_time = strtod(warning, NULL);
 			break;
 		case 'c':
 			critical = optarg;
-			critical_time = strtod(critical, NULL);
+			result.config.critical_time = strtod(critical, NULL);
 			break;
 		case 'V': /* version */
 			print_revision(progname, NP_VERSION);
@@ -514,48 +500,47 @@ int process_arguments(int argc, char **argv) {
 		}
 	}
 
-	c = optind;
-
-	set_thresholds(&my_threshold, warning, critical);
+	int index = optind;
 
-	while (argc > c) {
+	set_thresholds(&result.config.my_threshold, warning, critical);
 
-		if (db_host == NULL) {
-			if (is_host(argv[c])) {
-				db_host = argv[c++];
+	while (argc > index) {
+		if (result.config.db_host == NULL) {
+			if (is_host(argv[index])) {
+				result.config.db_host = argv[index++];
 			} else {
-				usage2(_("Invalid hostname/address"), argv[c]);
+				usage2(_("Invalid hostname/address"), argv[index]);
 			}
-		} else if (db_user == NULL) {
-			db_user = argv[c++];
-		} else if (db_pass == NULL) {
-			db_pass = argv[c++];
-		} else if (db == NULL) {
-			db = argv[c++];
-		} else if (is_intnonneg(argv[c])) {
-			db_port = atoi(argv[c++]);
+		} else if (result.config.db_user == NULL) {
+			result.config.db_user = argv[index++];
+		} else if (result.config.db_pass == NULL) {
+			result.config.db_pass = argv[index++];
+		} else if (result.config.db == NULL) {
+			result.config.db = argv[index++];
+		} else if (is_intnonneg(argv[index])) {
+			result.config.db_port = atoi(argv[index++]);
 		} else {
 			break;
 		}
 	}
 
-	return validate_arguments();
+	return validate_arguments(result);
 }
 
-int validate_arguments(void) {
-	if (db_user == NULL) {
-		db_user = strdup("");
+check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper config_wrapper) {
+	if (config_wrapper.config.db_user == NULL) {
+		config_wrapper.config.db_user = strdup("");
 	}
 
-	if (db_host == NULL) {
-		db_host = strdup("");
+	if (config_wrapper.config.db_host == NULL) {
+		config_wrapper.config.db_host = strdup("");
 	}
 
-	if (db == NULL) {
-		db = strdup("");
+	if (config_wrapper.config.db == NULL) {
+		config_wrapper.config.db = strdup("");
 	}
 
-	return OK;
+	return config_wrapper;
 }
 
 void print_help(void) {
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h
new file mode 100644
index 00000000..71ddbe8d
--- /dev/null
+++ b/plugins/check_mysql.d/config.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "../../config.h"
+#include "thresholds.h"
+#include <stddef.h>
+#include <mysql.h>
+
+typedef struct {
+	char *db_host;
+	unsigned int db_port;
+	char *db_user;
+	char *db_socket;
+	char *db_pass;
+	char *db;
+	char *ca_cert;
+	char *ca_dir;
+	char *cert;
+	char *key;
+	char *ciphers;
+	bool ssl;
+	char *opt_file;
+	char *opt_group;
+
+	bool check_replica;
+	bool ignore_auth;
+
+	double warning_time;
+	double critical_time;
+	thresholds *my_threshold;
+
+} check_mysql_config;
+
+check_mysql_config check_mysql_config_init() {
+	check_mysql_config tmp = {
+		.db_host = NULL,
+		.db_port = MYSQL_PORT,
+		.db = NULL,
+		.db_pass = NULL,
+		.db_socket = NULL,
+		.db_user = NULL,
+		.ca_cert = NULL,
+		.ca_dir = NULL,
+		.cert = NULL,
+		.key = NULL,
+		.ciphers = NULL,
+		.ssl = false,
+		.opt_file = NULL,
+		.opt_group = NULL,
+
+		.check_replica = false,
+		.ignore_auth = false,
+
+		.warning_time = 0,
+		.critical_time = 0,
+		.my_threshold = NULL,
+	};
+	return tmp;
+}



More information about the Commits mailing list